feat(ledger): implement transaction-build local-state-queries (#2547)
* feat(ledger): implement GetStakePools local-state-query
cardano-cli issues the GetStakePools ledger-state query while balancing a
transaction (e.g. `transaction build`). Dingo did not handle it, so the
query returned an "unsupported query type" error, which tears down the
local-state-query connection — the client sees
`BearerClosed "<socket: 11> closed when reading data"`.
Implement the query: return the key hashes of the currently active
(registered, non-retired) stake pools as a CBOR set (tag 258) of pool IDs.
cardano-cli is strict about the encoding — a plain (untagged) array fails to
decode with "expected tag", and an unsorted set fails with "Canonicity
violation while decoding Set" — so the IDs are emitted in ascending
canonical byte order, wrapped in the single-element result array the
query's result type decodes from.
Adds a Database.GetActivePoolKeyHashes wrapper over the existing metadata
store method. Verified end-to-end against a Conway devnet with cardano-cli
11.0.0.0: `query stake-pools` now returns the pool set and decodes
successfully, matching cardano-node.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Signed-off-by: Chris Guiney <[email protected]>
* feat(ledger): implement GetDRepState local-state-query
The second ledger-state query cardano-cli issues while balancing a
transaction (after GetStakePools). Like the others, leaving it unhandled
tore down the local-state-query connection.
Return the registration state of the requested DReps — or of all DReps when
the credential set is empty (matching the Haskell ledger's "empty means
all") — as a map of stake credential -> {expiry epoch, optional anchor,
deposit}, wrapped in the single-element result array cardano-cli expects.
The wire shape was verified against cardano-node: an empty result is the
CBOR `81 a0` ([ {} ]) — note gouroboros' own DRepStateResult client type
omits that wrapper, so cardano-node's bytes are the reference, not the type.
Verified with cardano-cli 11.0.0.0 against the Conway devnet:
`query drep-state --all-dreps` now returns `[]`, matching cardano-node, and
`transaction build` progresses past GetDRepState.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Signed-off-by: Chris Guiney <[email protected]>
* feat(ledger): implement GetAccountState local-state-query
The final ledger-state query cardano-cli issues while balancing a
transaction. Return the chain's treasury and reserves pots (from the network
state) wrapped in the single-element result array, so the wire shape is
[ [treasury, reserves] ], matching cardano-node. Values are signed because
Coin is an Integer in the ledger.
With this, GetStakePools + GetDRepState + GetAccountState cover the full
query set cardano-cli sends, and `cardano-cli conway transaction build`
completes against Dingo, producing a valid Tx ConwayEra (verified on a Conway
devnet with cardano-cli 11.0.0.0).
Depends on the gouroboros GetAccountState query type; requires a gouroboros
release and a go.mod bump before this builds in CI.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Signed-off-by: Chris Guiney <[email protected]>
* fix(ledger): guard currentPParams read with RLock in drepDeposit
drepDeposit read ls.currentPParams without the read lock, racing concurrent
ledger updates during local-state-query handling. Take ls.RLock() like the
other currentPParams readers; the sole caller (queryShelleyDRepState) does
not hold the lock, so there is no double-acquire.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Signed-off-by: Chris Guiney <[email protected]>
* fix(ledger): guard against nil DReps in GetDRepState
Defensively skip nil entries when building the GetDRepState result so the
dereferences (drep.Credential, drep.ExpiryEpoch) can't panic. The current
contracts already prevent nil — Database.GetDrep returns ErrDrepNotFound
rather than (nil, nil), and GetActiveDreps yields no nil entries — but the
guard covers both the filtered and all-DReps paths at the dereference site
and is robust to future contract changes.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Signed-off-by: Chris Guiney <[email protected]>
---------
Signed-off-by: Chris Guiney <[email protected]>
Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>