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
fix(auditor): composite-owner upgrades and undecodable owners in input attribution
An upgrade issued back to a composite owner emits one output row per
member under a shared output index. Members resolving to one enrollment
ID attribute the upgrade input to it, now covered by tests; members
spanning enrollment IDs fail the audit naming both IDs — a record keeps
a single sender per action, and leaving the input unattributed would
credit the members without debiting anyone. Refs #2242.
The identity layer signals an owner it cannot decode — an unknown
identity type, a missing deserializer, undecodable audit info — by
returning an error. Treat such an owner as unresolved instead of
failing the audit: a transfer input stays unattributed, an upgrade
input still takes the issued enrollment ID.
Also correct the documented audit-info preference order: the locally
stored audit info wins wherever it exists, since Request.AuditRecord
fills it in before the gap filling runs.
Signed-off-by: Evan <evanyan@sign.global>
Copy file name to clipboardExpand all lines: docs/services/auditor.md
+3-3Lines changed: 3 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -59,11 +59,11 @@ An audit record pairs every input and output with an enrollment ID. Inputs do no
59
59
Each such input is resolved from its own spent token:
60
60
61
61
1. The spent token is read from the vault, yielding its owner, type, and quantity.
62
-
2. The owner is resolved to an enrollment ID and revocation handle through `WalletManager.GetEIDAndRH`, preferring the audit info carried by the record over the locally stored one — a counterparty's audit info is not necessarily present locally.
62
+
2. The owner is resolved to an enrollment ID and revocation handle through `WalletManager.GetEIDAndRH`, using the audit info attached to the input: the locally stored audit info of the spent token's owner where present, the one carried by the request metadata otherwise — a counterparty's audit info is not necessarily present locally. An owner the identity layer cannot decode counts as resolving to nothing.
63
63
64
-
Across the built-in drivers, a **token upgrade** is the action whose metadata describes no sender for its inputs, and whose pre-upgrade owner often resolves to nothing: that identity predates the current driver and the request carries no audit info for it. Since an upgrade re-issues the spent tokens to the same party under a fresh identity, such an input takes the enrollment ID of the outputs issued by **its own action**, when every one of them resolves to the same party. The revocation handle comes from the same output, and is dropped when the outputs carry more than one. Without this the upgraded amount would be credited to the owner without ever being debited, doubling the holding.
64
+
Across the built-in drivers, a **token upgrade** is the action whose metadata describes no sender for its inputs, and whose pre-upgrade owner often resolves to nothing: that identity predates the current driver and the request carries no audit info for it. Since an upgrade re-issues the spent tokens to the same party under a fresh identity, such an input takes the enrollment ID of the outputs issued by **its own action**, when every one of them resolves to the same party. The revocation handle comes from the same output, and is dropped when the outputs carry more than one. Without this the upgraded amount would be credited to the owner without ever being debited, doubling the holding. A composite owner issues one output row per member, all under one output index: members resolving to one enrollment ID attribute the input to it, while members spanning enrollment IDs fail the audit — a record keeps a single sender per action, and an unattributed input would credit the members without debiting anyone.
65
65
66
-
An owner that maps to no single enrollment ID — a composite owner such as a multisig, or one whose audit info is not available to this auditor — leaves its input **unattributed**, with an empty enrollment ID. Amount aggregations skip empty enrollment IDs, so an unattributed input is counted for nobody. Guessing instead, for instance from the first output, would in a payment attribute the payer's spending to the recipient and silently corrupt both balances.
66
+
An owner that maps to no single enrollment ID — a composite owner such as a multisig, or one whose audit info is not available to, or not decodable by, this auditor — leaves its input **unattributed**, with an empty enrollment ID. Amount aggregations skip empty enrollment IDs, so an unattributed input is counted for nobody. Guessing instead, for instance from the first output, would in a payment attribute the payer's spending to the recipient and silently corrupt both balances.
67
67
68
68
An action whose inputs attribute to **more than one** enrollment ID — reachable when the tokens to spend are passed explicitly, since they are not constrained to a single wallet — fails the audit with an error naming the cause: a transaction record keeps a single sender per action, so the store cannot represent it. Representing multi-sender actions is tracked separately.
"output [%d] of action [%d] is issued to a composite owner whose members span enrollment IDs ([%s] and [%s]): no single enrollment ID to attribute its input to",
0 commit comments