Files
dex/pkg
zeekay f60386336e feat(dchain): committed-state read RPC (clob_get_trades/orders/markets/book)
The D-Chain VM exposed only write methods (clob_place/submit/cancel/...) over
its HTTP surface; there was no way to read committed chain state, so a fill
proven on the proposer could not be verified as replicated across validators,
and native fills (trade: rows) could not feed markets-display.

Add a READ surface (read.go) orthogonal to the write surface (handler.go):

  - clob_get_trades?since=<h>&limit=<n>  committed trade: log (markets feed +
                                          cross-validator replication probe)
  - clob_get_orders?market=<hex>          resting order: rows for a market
  - clob_get_markets                      every market: id/symbol/assets/summary
  - clob_get_book?market=<hex>&depth=<n>  aggregated bid/ask ladder + totals

Reads are JSON, GET, served via CreateHandlers on the SAME /ext/bc/<D>/dex/
route group as the writes. They read committed state directly under vm.mu —
NO mempool, NO block, NO consensus round — so a read can never change a fill or
balance (proven: TestRead_ZeroConsensusImpact). Every response carries the
accepted-block head (height, lastAccepted, root) so a cross-validator diff is
anchored to an exact block: two nodes at the same height+root MUST return
identical trades.

Trades/markets read durable rows (the committed truth, identical on every node
at a height); orders/book read the in-RAM book (a deterministic fold of the
committed order: rows). The 80-byte trade row carries no poolID (frozen GPU
ABI), so clob_get_trades is the GLOBAL height-ordered log — exactly right for a
single-market devnet (the verification case) and for an indexer that scopes
fills to a market by the order ids it tracks.

State helpers (state.go): readTrades (height-ordered durable scan), listMarkets.
lx: export DEXPrice.Float() + FixedQtyToFloat (one conversion; the internal
fixedPriceToFloat/fixedQtyToFloat now delegate).

TDD (read_test.go, all green, race-clean):
  - TradesAfterCommittedFill: a matched cross is queryable with right px/size/side
  - MarketsAndOrdersAndBook: the three other endpoints reflect committed state
  - ZeroConsensusImpact: 25 reads advance neither height nor mempool
  - CrossValidatorIdenticalTrades: two INDEPENDENT VMs (separate DBs) that
    Accept the SAME block bytes return BYTE-IDENTICAL trades JSON + same root —
    the in-process model of the live 5-validator replication question
  - GenesisEmpty / BadParams: clean empty answers; boundary validation (400/405)

Removed the temporary zzz_fillrepro_test.go (its header said DELETE after;
superseded by read_test.go's committed-fill coverage).
2026-06-22 14:55:38 -07:00
..