Skip to content

Commit

Permalink
add debug_executionWitness API
Browse files Browse the repository at this point in the history
  • Loading branch information
0x00101010 committed Oct 8, 2024
1 parent d5a9661 commit 93214fb
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 0 deletions.
32 changes: 32 additions & 0 deletions core/stateless/encoding.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ package stateless
import (
"io"

"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/rlp"
)

Expand Down Expand Up @@ -74,3 +76,33 @@ type extWitness struct {
Codes [][]byte
State [][]byte
}

// ExecutionWitness is a witness json encoding for transferring across clients
// in the future, we'll probably consider using the extWitness format instead for less overhead.
// currently we're using this format for compatibility with the reth and also for simplicify in terms of parsing.
type ExecutionWitness struct {
Headers []*types.Header `json:"headers"`
Codes map[string]string `json:"codes"`
State map[string]string `json:"state"`
}

func transformMap(in map[string]struct{}) map[string]string {
out := make(map[string]string, len(in))
for item := range in {
bytes := []byte(item)
key := crypto.Keccak256Hash(bytes).Hex()
out[key] = hexutil.Encode(bytes)
}
return out
}

// ToExecutionWitness converts a witness to an execution witness format that is compatible with reth.
// keccak(node) => node
// keccak(bytecodes) => bytecodes
func (w *Witness) ToExecutionWitness() *ExecutionWitness {
return &ExecutionWitness{
Headers: w.Headers,
Codes: transformMap(w.Codes),
State: transformMap(w.State),
}
}
35 changes: 35 additions & 0 deletions eth/api_debug.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/stateless"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/internal/ethapi"
Expand Down Expand Up @@ -446,3 +447,37 @@ func (api *DebugAPI) GetTrieFlushInterval() (string, error) {
}
return api.eth.blockchain.GetTrieFlushInterval().String(), nil
}

func (api *DebugAPI) ExecutionWitness(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*stateless.ExecutionWitness, error) {
block, err := api.eth.APIBackend.BlockByNumberOrHash(ctx, blockNrOrHash)
if err != nil {
return nil, fmt.Errorf("failed to retrieve block: %w", err)
}
if block == nil {
return nil, fmt.Errorf("block not found: %s", blockNrOrHash.String())
}

witness, err := stateless.NewWitness(block.Header(), api.eth.blockchain)
if err != nil {
return nil, fmt.Errorf("failed to create witness: %w", err)
}

parentHeader := witness.Headers[0]
statedb, err := api.eth.blockchain.StateAt(parentHeader.Root)
if err != nil {
return nil, fmt.Errorf("failed to retrieve parent state: %w", err)
}

statedb.StartPrefetcher("debug_execution_witness", witness)

res, err := api.eth.blockchain.Processor().Process(block, statedb, *api.eth.blockchain.GetVMConfig())
if err != nil {
return nil, fmt.Errorf("failed to process block %d: %w", block.Number(), err)
}

if err := api.eth.blockchain.Validator().ValidateState(block, statedb, res, false); err != nil {
return nil, fmt.Errorf("failed to validate block %d: %w", block.Number(), err)
}

return witness.ToExecutionWitness(), nil
}

0 comments on commit 93214fb

Please sign in to comment.