You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Browse filesBrowse the repository at this point in the historyBrowse files
Hayim.Shaul@ibm.com
committed
fix(tokens): publish token events only after commit
Token add and delete events were published while the database transaction
that produced them was still open, so a subscriber could observe a token
that was later rolled back and never persisted.
Buffer the events on DBTransaction and publish them from Commit, once the
underlying commit succeeded, or from FlushEvents when the transaction is
owned by the caller. Rollback discards them.
Service.AppendValid applies a request to a transaction it does not own, so
it now returns a PostCommit function that the owner of the transaction
invokes once its commit succeeded. The finality listener calls it after
committing and before waking the finality waiters, so a confirmed
transaction is never observed with its token events still pending.
Signed-off-by: Hayim.Shaul@ibm.com <hayimsha@fhe03.vpc.cloud9.ibm.com>
Copy file name to clipboardExpand all lines: docs/services/tokens.md
+49-1Lines changed: 49 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -9,7 +9,7 @@ The internal [Service](../../token/services/tokens/tokens.go) is responsible for
9
9
### Core Responsibilities
10
10
***State Management**: Updating the local `TokenDB` to reflect the ledger's state (marking tokens as spendable, pending, or deleted). See [storage.go](../../token/services/tokens/storage.go).
11
11
***Typed Token Support**: Providing a unified way to handle multiple cryptographic token formats (e.g., cleartext vs. commitments) simultaneously via the [TypedToken](../../token/services/tokens/typed.go) structure.
12
-
***Lifecycle Monitoring**: Notifying local listeners (via `events.Publisher`) when tokens are added or removed.
12
+
***Lifecycle Monitoring**: Notifying local listeners (via `events.Publisher`) when tokens are added or removed, once the change has been committed. See [Event Publication and Transaction Boundaries](#event-publication-and-transaction-boundaries).
13
13
***Consistency**: Identifying and removing stale unspent tokens by cross-referencing local storage with the ledger via the [Network Service](../../token/services/network/network.go) (see `PruneInvalidUnspentTokens`).
14
14
15
15
### Marking Spent Tokens
@@ -21,6 +21,54 @@ event is published for it. A failure reported by the underlying store is always
21
21
regardless of whether the token was found locally, so that a transaction is never recorded
22
22
as processed while its spends were not applied.
23
23
24
+
### Event Publication and Transaction Boundaries
25
+
26
+
The `store-token` (`tokens.AddToken`) and `delete-token` (`tokens.DeleteToken`) events are
27
+
published **only after the database transaction that produced them has been committed**. A
28
+
subscriber therefore never observes a token that is later rolled back and never persisted.
29
+
30
+
`DBTransaction.AppendToken` and `DBTransaction.DeleteToken` record their events on the
31
+
transaction — `DBTransaction.Notify` buffers, it does not publish — and:
32
+
33
+
*`DBTransaction.Commit(ctx)` publishes them, and only if the commit succeeded. This covers
34
+
the transactions the service owns, obtained from `DBStorage.NewTransaction`.
35
+
*`DBTransaction.Rollback` discards them.
36
+
*`DBTransaction.FlushEvents(ctx)` publishes them explicitly. It is used when the transaction
37
+
is owned by the caller (`DBStorage.ContinueTransaction`), since the service is then not the
38
+
one that decides whether the transaction is committed.
39
+
40
+
`Service.AppendValid` is the continued-transaction case: it applies a token request to a
41
+
transaction owned by the caller, and returns a `PostCommit` function alongside the error. The
42
+
caller must invoke it after its own commit succeeded, and must not invoke it when it rolls
43
+
back:
44
+
45
+
```go
46
+
tx, err:= ttxDB.NewTransaction()
47
+
if err != nil {
48
+
return errors.Wrapf(err, "failed creating new transaction [%s]", txID)
0 commit comments