Skip to content

rpc: add Reth-compatible format for debug_executionWitness#21509

Draft
lupin012 wants to merge 2 commits into
mainfrom
lupin012/debug_executionWitness_reth_format
Draft

rpc: add Reth-compatible format for debug_executionWitness#21509
lupin012 wants to merge 2 commits into
mainfrom
lupin012/debug_executionWitness_reth_format

Conversation

@lupin012
Copy link
Copy Markdown
Contributor

@lupin012 lupin012 commented May 29, 2026

Before this PR the debug_executionWitness () returns data according Geth.

This PR permit to return debug_executionWitness () in two formats: Reth (canonical) [default] and Geth using a config param

In debug_execution_witness.go:

  • ExecutionWitnessResult.Headers changed from []map[string]any to any (holds either JSON objects or RLP-encoded bytes depending on the flag)

  • Added internal allCodes field for stateless verification (unfiltered: accessed + newly deployed code)

  • New witnessHeadersToJSON and witnessHeadersToRLP serialisation helpers

  • New filterEIP7702Codes — removes EIP-7702 delegation designator codes and their targets from codes in Reth-compat mode

  • collectAccessedState accepts gethCompat bool and integrates the EIP-7702 filter internally, avoiding a second GetAccessedCode() call

  • collectAccessedHeaders now returns []*types.Header; serialisation to wire format happens at the call site

  • Storage keys: emit key.Bytes() only (previously addr || key composite)

  • Local sortedCodesSlice helper eliminates the duplicated sort-and-collect pattern used for both SortedCodes and AllCodes

  • Stateless verifier uses allCodes instead of Codes so contracts deployed within the block are available during re-execution

  • Reth-compatible (defualt):

    • headers RLP-encoded,
    • keys populated (EIP-7702 delegation codes filtered out)
    • code see Reth canonical
    • state
  • --rpc.witness.gethcompat: Geth-compatible:

    • headers json object
    • keys null
    • code
    • state

I've run some tests on Hive (50 blocks), and Erigon returns the exact same responses as Geth and Reth (canonical) for all fields except for state.
For the state field in a few tests on hive:

  • Erigon provides fewer MPT nodes than Geth, and
  • other few even fewer than Reth canonical.
    It's possible that these extra/missing nodes aren't actually essential for the witness.

I haven't run any tests on mainnet comparing with Reth (canonical), but
I have run a few mainnet tests comparing with Geth using the --rpc.witness.gethcompat flag

@lupin012 lupin012 requested a review from awskii May 29, 2026 12:00
@lupin012 lupin012 force-pushed the lupin012/debug_executionWitness_reth_format branch from 1a352c3 to 5927fa4 Compare May 29, 2026 13:49
Add --rpc.witness.gethcompat flag to select the output format:
- default (off): Reth-compatible — headers RLP-encoded, keys populated,
  EIP-7702 delegation codes filtered out
- --rpc.witness.gethcompat: Geth-compatible — headers as JSON objects,
  keys null (previous behaviour)

Also remove the unused mode *string parameter from the ExecutionWitness
interface, extract a sortedCodesSlice helper to eliminate duplicated
sort-and-collect logic, and avoid a second GetAccessedCode() call by
integrating the EIP-7702 filter into collectAccessedState.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@lupin012 lupin012 force-pushed the lupin012/debug_executionWitness_reth_format branch from 5927fa4 to 837fde9 Compare May 30, 2026 14:27
@lupin012 lupin012 marked this pull request as ready for review May 30, 2026 21:26
@lupin012 lupin012 added the RPC label May 31, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a configurable output format for debug_executionWitness, defaulting to a Reth-compatible (canonical) wire format while allowing a Geth-compatible mode via --rpc.witness.gethcompat. This fits into Erigon’s RPC daemon/debug API surface, aiming to improve cross-client compatibility for witness consumers and stateless verification.

Changes:

  • Add a witnessGethCompat switch to DebugAPIImpl and plumb a new CLI/config flag (rpc.witness.gethcompat) through rpcdaemon/node config.
  • Change witness header serialization to be either JSON objects (Geth mode) or RLP-encoded bytes (Reth mode), and adjust the witness result shape accordingly.
  • Refactor witness code collection to support stateless verification with an internal allCodes set and add EIP-7702 delegation-code filtering in Reth mode.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
rpc/jsonrpc/debug_execution_witness.go Core witness result format switch (JSON vs RLP headers), code/key collection changes, and stateless verifier adjustments.
rpc/jsonrpc/debug_api.go Adds witnessGethCompat to DebugAPIImpl and extends constructor signature.
rpc/jsonrpc/daemon.go Wires cfg.WitnessGethCompat into NewPrivateDebugAPI.
rpc/jsonrpc/debug_api_test.go Updates debug API tests for new NewPrivateDebugAPI signature and adjusts witness assertions.
rpc/jsonrpc/gen_traces_test.go Updates test to match new NewPrivateDebugAPI signature.
cmd/utils/flags.go Introduces rpc.witness.gethcompat CLI flag definition.
node/cli/default_flags.go Registers the new witness compat flag in default flags.
node/cli/flags.go Plumbs WitnessGethCompat into embedded rpcdaemon HTTP config.
cmd/rpcdaemon/cli/httpcfg/http_cfg.go Adds WitnessGethCompat to rpcdaemon HTTP config struct.
cmd/rpcdaemon/cli/config.go Exposes rpc.witness.gethcompat as a cobra persistent flag.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 523 to 524
// Keys is always null (reserved for future use, included for Geth compatibility)
Keys []hexutil.Bytes `json:"keys"`
Comment on lines 794 to 806
t.Run("by block number", func(t *testing.T) {
// Test with block number 1
blockNum := rpc.BlockNumber(1)
result, err := api.ExecutionWitness(ctx, rpc.BlockNumberOrHash{BlockNumber: &blockNum})

require.NoError(t, err)
require.NotNil(t, result)
require.NotNil(t, result.State, "State should not be nil")
require.Nil(t, result.Keys, "Keys must remain nil (Geth compatibility)")
if len(result.Headers) > 0 {
require.NotNil(t, result.Keys, "Keys must be set in Reth-compatible mode")
if len(result.headerByNumber) > 0 {
require.Contains(t, result.headerByNumber, uint64(0), "parent header (block 0) must be present in lookup map when Headers is non-empty")
}
})
@lupin012 lupin012 marked this pull request as draft June 2, 2026 07:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants