trait ReadService extends ReportsHealth
An interface for reading the state of a ledger participant. Please note that this interface is unstable and may significantly change.
The state of a ledger participant is communicated as a stream of state Updates. That stream is accessible via ReadService!.stateUpdates. Commonly that stream is processed by a single consumer that keeps track of the current state and creates indexes to satisfy read requests against that state.
See com.digitalasset.canton.ledger.participant.state.v2 for further architectural information. See Update for a description of the state updates communicated by ReadService!.stateUpdates.
- Alphabetic
- By Inheritance
- ReadService
- ReportsHealth
- AnyRef
- Any
- Hide All
- Show All
- Public
- Protected
Abstract Value Members
- abstract def currentHealth(): HealthStatus
Reports the current health of the object.
Reports the current health of the object. This should always return immediately.
- Definition Classes
- ReportsHealth
- abstract def stateUpdates(beginAfter: Option[Offset])(implicit traceContext: TraceContext): Source[(Offset, Traced[Update]), NotUsed]
Get the stream of state Updates starting from the beginning or right after the given com.digitalasset.canton.ledger.offset.Offset
Get the stream of state Updates starting from the beginning or right after the given com.digitalasset.canton.ledger.offset.Offset
This is where the meat of the implementation effort lies. Please take your time to read carefully through the properties required from correct implementations. These properties fall into two categories:
1. properties about the sequence of (com.digitalasset.canton.ledger.offset.Offset,Update) tuples in a stream read from the beginning, and 2. properties relating the streams obtained from separate calls to stateUpdates.
The first class of properties are invariants of a single stream:
- *strictly increasing com.digitalasset.canton.ledger.offset.Offsets*: for any two consecutive tuples
(o1, u1)
and(o2, u2)
,o1
is strictly smaller thano2
.- *initialize before transaction acceptance*: before any Update.TransactionAccepted, there is a Update.ConfigurationChanged update and Update.PublicPackageUpload updates for all packages referenced by the Update.TransactionAccepted.
- *causal monotonicity*: given a Update.TransactionAccepted with an associated ledger time
lt_tx
, it holds thatlt_tx >= lt_c
for allc
, wherec
is a contract used by the transaction andlt_c
the ledger time of the Update.TransactionAccepted that created the contract. The ledger time of a transaction is specified in the corresponding TransactionMeta meta-data. Note that the ledger time of unrelated updates is not necessarily monotonically increasing. The creating transaction need not have a Update.TransactionAccepted event on this participant if the participant does not host a stakeholder of the contract, e.g., in the case of divulgence.- *time skew*: given a Update.TransactionAccepted with an associated ledger time
lt_tx
and a record timert_tx
, it holds thatrt_TX - minSkew <= lt_TX <= rt_TX + maxSkew
, whereminSkew
andmaxSkew
are parameters specified in the ledger com.digitalasset.canton.ledger.configuration.LedgerTimeModel of the last Update.ConfigurationChanged before the Update.TransactionAccepted.- *command deduplication*: Let there be a Update.TransactionAccepted with CompletionInfo or a Update.CommandRejected with CompletionInfo at offset
off2
. Ifoff2
's CompletionInfo.optDeduplicationPeriod is a api.DeduplicationPeriod.DeduplicationOffset, letoff1
be the first offset after the deduplication offset. If the deduplication period is a api.DeduplicationPeriod.DeduplicationDuration, letoff1
be the first offset whose record time is at most the duration beforeoff2
's record time (inclusive). Then there is no other Update.TransactionAccepted with CompletionInfo for the same CompletionInfo.changeId between the offsetsoff1
andoff2
inclusive.So if a command submission has resulted in a Update.TransactionAccepted, other command submissions with the same SubmitterInfo.changeId must be deduplicated if the earlier's Update.TransactionAccepted falls within the latter's CompletionInfo.optDeduplicationPeriod.
Implementations MAY extend the deduplication period from SubmitterInfo arbitrarily and reject a command submission as a duplicate even if its deduplication period does not include the earlier's Update.TransactionAccepted. A Update.CommandRejected completion does not trigger deduplication and implementations SHOULD process such resubmissions normally.
- *finality*: If the corresponding WriteService acknowledges a submitted transaction or rejection with SubmissionResult.Acknowledged, the ReadService SHOULD make sure that it eventually produces a Update.TransactionAccepted or Update.CommandRejected with the corresponding CompletionInfo, even if there are crashes or lost network messages.
The second class of properties relates multiple calls to stateUpdates to each other. The class contains two properties: (1) a property that enables crash-fault tolerant Ledger API server implementations and (2) a property that enables Ledger API server implementations that are synchronized by a backing ledger.
For crash-fault-tolerance, we require an implementation of stateUpdates to support its consumer to resume consumption starting after the last offset up to which the consumer completed processing. Note that this offset can be before the offset of several of the latest delivered Updates in case the consumer did not complete their processing before crashing.
Formally, we require that the above invariants also hold for any sequence of offset-and-update pairs
us = takeUntilOffset(us_1, o_2) + takeUntilOffset(us_2, o_3) + ... + takeUntilOffset(us_N-1, o_N) + us_N
where
us_i =
stateUpdates(o_i) andlastOffsetOf(us_i) >= o_i+1
. Here,us_i
is the sequence of offset-and-update pairs sourced from a call to stateUpdates and the side-condition formalizes that later calls must start from an offset before or equal to the last offset delivered in the previous call.For synchronization, we require that two parties hosted on separate participant nodes are in sync on transaction nodes and contracts that they can both see. The more formal definition is based on the notion of projections of transactions (see https://docs.daml.com/concepts/ledger-model/ledger-privacy.html), as follows.
Assume that there is - a party
A
hosted at participantp1
, - a partyB
hosted at participantp2
, and - an accepted transaction with identifiertid
evidenced to both participantsp1
andp2
in their state update streams after the Update.PartyAddedToParticipant updates forA
, respectivelyB
. The projections oftx1
andtx2
to the nodes visible to bothA
andB
is the same.Note that the transaction
tx1
associated totid
onp1
is not required to be the same as the transactiontx2
associated totid
onp2
, as these two participants do not necessarily host the same parties; and some implementations ensure data segregation on the ledger. Requiring only the projections to sets of parties to be equal leaves just enough leeway for this data segregation.Note further that the offsets of the transactions might not agree, as these offsets are participant-local.
- abstract def validateDar(dar: ByteString)(implicit traceContext: TraceContext): Future[SubmissionResult]
Concrete Value Members
- final def !=(arg0: Any): Boolean
- Definition Classes
- AnyRef → Any
- final def ##: Int
- Definition Classes
- AnyRef → Any
- final def ==(arg0: Any): Boolean
- Definition Classes
- AnyRef → Any
- final def asInstanceOf[T0]: T0
- Definition Classes
- Any
- def clone(): AnyRef
- Attributes
- protected[lang]
- Definition Classes
- AnyRef
- Annotations
- @throws(classOf[java.lang.CloneNotSupportedException]) @native() @IntrinsicCandidate()
- final def eq(arg0: AnyRef): Boolean
- Definition Classes
- AnyRef
- def equals(arg0: AnyRef): Boolean
- Definition Classes
- AnyRef → Any
- final def getClass(): Class[_ <: AnyRef]
- Definition Classes
- AnyRef → Any
- Annotations
- @native() @IntrinsicCandidate()
- def getConnectedDomains(request: ConnectedDomainRequest)(implicit traceContext: TraceContext): Future[ConnectedDomainResponse]
- def hashCode(): Int
- Definition Classes
- AnyRef → Any
- Annotations
- @native() @IntrinsicCandidate()
- def incompleteReassignmentOffsets(validAt: Offset, stakeholders: Set[LfPartyId])(implicit traceContext: TraceContext): Future[Vector[Offset]]
Get the offsets of the incomplete assigned/unassigned events for a set of stakeholders.
Get the offsets of the incomplete assigned/unassigned events for a set of stakeholders.
- validAt
The offset of validity in participant offset terms.
- stakeholders
Only offsets are returned which have at least one stakeholder from this set.
- returns
All the offset of assigned/unassigned events which do not have their conterparts visible at the validAt offset, and only for the reassignments for which this participant is reassigning.
- final def isInstanceOf[T0]: Boolean
- Definition Classes
- Any
- final def ne(arg0: AnyRef): Boolean
- Definition Classes
- AnyRef
- final def notify(): Unit
- Definition Classes
- AnyRef
- Annotations
- @native() @IntrinsicCandidate()
- final def notifyAll(): Unit
- Definition Classes
- AnyRef
- Annotations
- @native() @IntrinsicCandidate()
- final def synchronized[T0](arg0: => T0): T0
- Definition Classes
- AnyRef
- def toString(): String
- Definition Classes
- AnyRef → Any
- final def wait(arg0: Long, arg1: Int): Unit
- Definition Classes
- AnyRef
- Annotations
- @throws(classOf[java.lang.InterruptedException])
- final def wait(arg0: Long): Unit
- Definition Classes
- AnyRef
- Annotations
- @throws(classOf[java.lang.InterruptedException]) @native()
- final def wait(): Unit
- Definition Classes
- AnyRef
- Annotations
- @throws(classOf[java.lang.InterruptedException])