Skip to content

Commit 03b77d1

Browse files
authored
core/stateless: API methods to get execution witness of block
This PR adds a new RPC call, which re-executes a block with stateless mode activated, so that the witness data are collected and returned. They are `debug_executionWitnessByHash` which takes in a block hash and `debug_executionWitness` which takes in a block number. --------- Signed-off-by: Guillaume Ballet <[email protected]>
1 parent 110b4e1 commit 03b77d1

File tree

4 files changed

+67
-16
lines changed

4 files changed

+67
-16
lines changed

core/blockchain.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1907,7 +1907,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool, makeWitness
19071907
}
19081908
// The traced section of block import.
19091909
start := time.Now()
1910-
res, err := bc.processBlock(parent.Root, block, setHead, makeWitness && len(chain) == 1)
1910+
res, err := bc.ProcessBlock(parent.Root, block, setHead, makeWitness && len(chain) == 1)
19111911
if err != nil {
19121912
return nil, it.index, err
19131913
}
@@ -1973,9 +1973,13 @@ type blockProcessingResult struct {
19731973
witness *stateless.Witness
19741974
}
19751975

1976-
// processBlock executes and validates the given block. If there was no error
1976+
func (bpr *blockProcessingResult) Witness() *stateless.Witness {
1977+
return bpr.witness
1978+
}
1979+
1980+
// ProcessBlock executes and validates the given block. If there was no error
19771981
// it writes the block and associated state to database.
1978-
func (bc *BlockChain) processBlock(parentRoot common.Hash, block *types.Block, setHead bool, makeWitness bool) (_ *blockProcessingResult, blockEndErr error) {
1982+
func (bc *BlockChain) ProcessBlock(parentRoot common.Hash, block *types.Block, setHead bool, makeWitness bool) (_ *blockProcessingResult, blockEndErr error) {
19791983
var (
19801984
err error
19811985
startTime = time.Now()

core/stateless/encoding.go

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -19,28 +19,29 @@ package stateless
1919
import (
2020
"io"
2121

22+
"github.com/ethereum/go-ethereum/common/hexutil"
2223
"github.com/ethereum/go-ethereum/core/types"
2324
"github.com/ethereum/go-ethereum/rlp"
2425
)
2526

26-
// toExtWitness converts our internal witness representation to the consensus one.
27-
func (w *Witness) toExtWitness() *extWitness {
28-
ext := &extWitness{
27+
// ToExtWitness converts our internal witness representation to the consensus one.
28+
func (w *Witness) ToExtWitness() *ExtWitness {
29+
ext := &ExtWitness{
2930
Headers: w.Headers,
3031
}
31-
ext.Codes = make([][]byte, 0, len(w.Codes))
32+
ext.Codes = make([]hexutil.Bytes, 0, len(w.Codes))
3233
for code := range w.Codes {
3334
ext.Codes = append(ext.Codes, []byte(code))
3435
}
35-
ext.State = make([][]byte, 0, len(w.State))
36+
ext.State = make([]hexutil.Bytes, 0, len(w.State))
3637
for node := range w.State {
3738
ext.State = append(ext.State, []byte(node))
3839
}
3940
return ext
4041
}
4142

4243
// fromExtWitness converts the consensus witness format into our internal one.
43-
func (w *Witness) fromExtWitness(ext *extWitness) error {
44+
func (w *Witness) fromExtWitness(ext *ExtWitness) error {
4445
w.Headers = ext.Headers
4546

4647
w.Codes = make(map[string]struct{}, len(ext.Codes))
@@ -56,21 +57,22 @@ func (w *Witness) fromExtWitness(ext *extWitness) error {
5657

5758
// EncodeRLP serializes a witness as RLP.
5859
func (w *Witness) EncodeRLP(wr io.Writer) error {
59-
return rlp.Encode(wr, w.toExtWitness())
60+
return rlp.Encode(wr, w.ToExtWitness())
6061
}
6162

6263
// DecodeRLP decodes a witness from RLP.
6364
func (w *Witness) DecodeRLP(s *rlp.Stream) error {
64-
var ext extWitness
65+
var ext ExtWitness
6566
if err := s.Decode(&ext); err != nil {
6667
return err
6768
}
6869
return w.fromExtWitness(&ext)
6970
}
7071

71-
// extWitness is a witness RLP encoding for transferring across clients.
72-
type extWitness struct {
73-
Headers []*types.Header
74-
Codes [][]byte
75-
State [][]byte
72+
// ExtWitness is a witness RLP encoding for transferring across clients.
73+
type ExtWitness struct {
74+
Headers []*types.Header `json:"headers"`
75+
Codes []hexutil.Bytes `json:"codes"`
76+
State []hexutil.Bytes `json:"state"`
77+
Keys []hexutil.Bytes `json:"keys"`
7678
}

core/stateless/witness.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,10 @@ func (w *Witness) AddState(nodes map[string][]byte) {
100100
}
101101
}
102102

103+
func (w *Witness) AddKey() {
104+
panic("not yet implemented")
105+
}
106+
103107
// Copy deep-copies the witness object. Witness.Block isn't deep-copied as it
104108
// is never mutated by Witness
105109
func (w *Witness) Copy() *Witness {

eth/api_debug.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626
"github.com/ethereum/go-ethereum/common/hexutil"
2727
"github.com/ethereum/go-ethereum/core/rawdb"
2828
"github.com/ethereum/go-ethereum/core/state"
29+
"github.com/ethereum/go-ethereum/core/stateless"
2930
"github.com/ethereum/go-ethereum/core/types"
3031
"github.com/ethereum/go-ethereum/crypto"
3132
"github.com/ethereum/go-ethereum/internal/ethapi"
@@ -491,3 +492,43 @@ func (api *DebugAPI) StateSize(blockHashOrNumber *rpc.BlockNumberOrHash) (interf
491492
"contractCodeBytes": hexutil.Uint64(stats.ContractCodeBytes),
492493
}, nil
493494
}
495+
496+
func (api *DebugAPI) ExecutionWitness(bn rpc.BlockNumber) (*stateless.ExtWitness, error) {
497+
bc := api.eth.blockchain
498+
block, err := api.eth.APIBackend.BlockByNumber(context.Background(), bn)
499+
if err != nil {
500+
return &stateless.ExtWitness{}, fmt.Errorf("block number %v not found", bn)
501+
}
502+
503+
parent := bc.GetHeader(block.ParentHash(), block.NumberU64()-1)
504+
if parent == nil {
505+
return &stateless.ExtWitness{}, fmt.Errorf("block number %v found, but parent missing", bn)
506+
}
507+
508+
result, err := bc.ProcessBlock(parent.Root, block, false, true)
509+
if err != nil {
510+
return nil, err
511+
}
512+
513+
return result.Witness().ToExtWitness(), nil
514+
}
515+
516+
func (api *DebugAPI) ExecutionWitnessByHash(hash common.Hash) (*stateless.ExtWitness, error) {
517+
bc := api.eth.blockchain
518+
block := bc.GetBlockByHash(hash)
519+
if block == nil {
520+
return &stateless.ExtWitness{}, fmt.Errorf("block hash %x not found", hash)
521+
}
522+
523+
parent := bc.GetHeader(block.ParentHash(), block.NumberU64()-1)
524+
if parent == nil {
525+
return &stateless.ExtWitness{}, fmt.Errorf("block number %x found, but parent missing", hash)
526+
}
527+
528+
result, err := bc.ProcessBlock(parent.Root, block, false, true)
529+
if err != nil {
530+
return nil, err
531+
}
532+
533+
return result.Witness().ToExtWitness(), nil
534+
}

0 commit comments

Comments
 (0)