debug: add debug_executionWitness spec - #847
MysticRyuujin wants to merge 7 commits into
Conversation
|
@jsign thanks — all four applied in 6b650d0. Two questions left that only the specs side can answer:
|
|
Open points that still need input from the client side, separate from the specs-side questions above.
One consequence worth stating plainly, since it's the cost of optionality: witness responses can't be byte-exact across clients if Two input cases the draft doesn't define. I've specced the genesis case (no parent header to prove the pre-state against, so clients MUST error — mirroring
Three positions nobody has pushed back on yet, which I'd rather have confirmed than assumed: dropping That last one is the blocker for fixtures: geth currently returns headers as JSON objects, so nothing here can be conformance-tested until that changes. Is anyone on the geth side willing to own it? The unknown-block-number crash I hit while prototyping ( |
|
Both read-only and read/write accesses.
One flat array.
Empty array, omitted and
Ordering does not matter for us on the prover side and also dedup happens automatically. I guess we may lean towards asking for dedup just to keep
As a small improvement over this, conformance fixtures might contain the
Erigon doesn't and we have an open PR to explicitly return an error in case
No objections.
|
|
Thanks @canepat, all applied in 58eab5e.
|
8e36f4b to
02be2e5
Compare
The two witness cases are speconly: content is exact-matchable only once clients implement the canonical witness builder, so hive checks the schema. The generator still verifies structure at fill time: RLP-decodable headers in ascending order ending with the parent, non-empty state, and sorted state and codes. Fixtures are generated from go-ethereum with the pending encoding change (canonical witness result: RLP headers, no keys field).
|
Since the approvals: added the testgen generator and five fixtures as the last commit (8a670c3), so spec and tests review in one place. The two witness-returning cases are speconly; rationale and verification (fill, speccheck plus a keys:null negative test, hive 5/5 against a patched geth) are in the updated description. The geth encoding change is up as ethereum/go-ethereum#35606. CI's make fill stays red here until that merges and the tools/go.mod pin advances, the same situation as #854. If sign-off lands first, I drop the fixtures commit and this merges spec-only. |
|
Geth closed my PR so 🤷🏻♂️ |
Concrete spec proposal for #845, opened as a draft to anchor the discussion on the shape.
Specs
debug_executionWitness(BlockNumberOrTagOrHash)returning the canonical execution witness,{state, codes, headers}with RLP-encoded headers. This matches the execution-specs stateless validation interface (stateless.pyExecutionWitness) and the SSZ container proposed in #773. The witness semantics are owned by execution-specs; this is the JSON-RPC binding.Positions encoded here (rationale in #845):
keysis optional. It is not part of the canonical format, but clients may include the accessed state keys for prover-side use (discussion). Semantics pinned per canepat's answers: reads and writes, one flat array of 20-byte addresses and 32-byte slot keys, deduplicated, and an empty set means omit the field.BlockNumberOrTagOrHash; no*ByHashvariant, nomodeparam. A client that accepts a format-selection parameter MUST return the canonical witness when the caller omits it, so shippedmodeparams survive as extensions while the default flips to canonical.state/codessorted lexicographically and deduplicated, headers ascending, per the host builder rules (build_execution_witness). Confirmed normative, which gives each block a single canonical witness and makes exact-match fixtures possible. The normative MUST is scoped tostate/codes/headers; the optionalkeysfield sits outside it.headersis never empty, because the guest takes the pre-state root fromheaders[-1].state_root. It holds at most 256 entries, sinceBLOCKHASHreaches back no further.pendingMUST error. Genesis has no parent header to prove the pre-state against, mirroringdebug_traceBlock*;pendingdoes not identify an executed block, and Erigon already rejects it. A hash naming a non-canonical block MAY be served when the client retains the required data.4444 Pruned history unavailablereused; a distinct witness-unavailable code can ride the error-groups work (error-groups, tools, tests: add spec-mandated error-code fixtures for methods #784)Update 2026-08-28: fixtures and the testgen generator are now included (the last commit). The two gaps the earlier draft named are now split cleanly:
keysfield;pendingrejected; theengine_newPayloadWithWitnessV5blob is a separate encoding and untouched). Until that merges and thetools/go.modpin advances, CI'smake fillfails on the witness cases here, the same situation as eth_createAccessList: clarify gas-fee affordability when fee fields omitted #854.get-witness-by-numberandget-witness-by-hashare speconly, so hive validates each client's response against this schema while the generator enforces structure at fill time (headers RLP-decode, ascend by block number, and end with the parent; state non-empty; state and codes sorted). Byte-exact fixtures would enshrine geth's legacy-semantics witness (bytecode on every read, sibling set from its trie iteration order); speconly avoids that while still rejecting wrong shapes.get-witness-genesis,get-witness-pending, andget-witness-invalid-blockcover the MUST-error inputs.Verification:
make fillreports zero failures against go-ethereum with ethereum/go-ethereum#35606 applied; speccheck passes, and injecting"keys": nullinto a fixture fails speccheck, which proves the schema is enforced. hive rpc-compat replays all five fixtures against geth built from that branch (Dockerfile.local, local fixtures, schema from this branch): 5/5 passed,failed=0, 2026-08-28.The example values in the spec are real (generated from that geth against the test chain), but they illustrate the shape rather than a conformance baseline, per the content gap above.