Event ordering within a transaction

  1. Is the event ID lexicographically sequential within a transaction? If not, is there a way to know the event index within a transaction?
  2. Are the events inside a transaction guaranteed to be emitted by the ledger API in the same order in which they happened in time within the boundaries of the same transaction?
  3. Is it possible 2 events inside the same transaction may have the exact same timestamp?
  4. Typically in client applications, to uniquely identity an event, is the recommended approach to use the tx offset + event ID, or is the event ID sufficient and guaranteed to be globally unique (within a Canton domain)?
  1. and 2. I recommend to not rely on lexicographic ordering here. Instead for the flat transaction stream, the list of events is in execution order. Similarly, for the transaction tree, a preorder traversal gives you execution order. So first process the event, then process the first child recursively, then the second child, …. That is guaranteed to give you the right order without relying on lexicographic sorting.

  2. As for timestamps, there is no per-event timestamp. The only timestamps you get over the ledger API is the ledger effective time for each transaction. There is no guarantee that those are monotonically increasing but you do get causal monotonicity.

  3. The event id itself should be enough. There is even an endpoint to lookup the transaction based on the event id. Ofc sometimes it can still be convenient to store it together with the transaction id locally.

1 Like

Thanks @cocreature.

  1. Re your #1, I’m assuming this execution order of events in a tax always matches the order of statements in a Daml choice’s do block - is this correct?

  2. Re your #2, is the order of transaction emission via the API based on LET or Record time?

  3. For two transactions A & B, if A is emitted via the transaction stream before B, are the following correct:

  • 3.1. offset_A < offset_B (lexicographically)

  • 3.2. Record_time_A < Record_time_B so A will always be recorded as committed on the ledger before B, but may not be executed/interpreted before B

  • 3.3. LET_A < LET_B if and only if A & B were submitted on the same participant node

  • 3.4. LET_A >= LET_B if and only if A & B were submitted on different participant nodes

  1. Are there any cases other than (iv) wherein it’s possible (and how?) for a tx with a higher offset to have a lower LET (transaction timestamp) than another that has a lower offset?
  1. Yes
  2. It’s based on the offset. In practice, record time also increases monotonically per domain afaik but since you cannot observe that that’s not really useful.
    3.1. yes
    3.2. as per above, I believe in practice this does increase per domain but offsets are a more useful thing to look at here
    3.3. Not quite, this only holds if you wait for A to be committed before submitting B, e.g., using submitAndWait. If you submit them in parallel you don’t get any guarantees.
    3.4. No, you can get that if you submit them in parallel on the same participant. (ofc assuming the causal monotonicity constraints aren’t violated, those always apply).
  3. see above
1 Like

Thank you @cocreature for the explanations!

@cocreature One last thing on this please, as I was thinking through the implications of this.

Assuming I’m storing the event payloads in an external database for analytics, this basically means that there is no single field or combination of fields that are available (out of the box) on Events & Transactions that I can use to tell me the chronological order of events. I would have to append the event payloads with some form of sequence number I’d have to generate based on emission order of events or tx tree traversal.

Is my understanding correct?

Yes, you would need to include your own index that you generate during traversal.

1 Like

Cheers - thank you again!