mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-02-26 15:47:21 +00:00
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 <3272758+gballet@users.noreply.github.com>
This commit is contained in:
parent
110b4e13c5
commit
03b77d1a49
4 changed files with 67 additions and 16 deletions
|
|
@ -1907,7 +1907,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool, makeWitness
|
|||
}
|
||||
// The traced section of block import.
|
||||
start := time.Now()
|
||||
res, err := bc.processBlock(parent.Root, block, setHead, makeWitness && len(chain) == 1)
|
||||
res, err := bc.ProcessBlock(parent.Root, block, setHead, makeWitness && len(chain) == 1)
|
||||
if err != nil {
|
||||
return nil, it.index, err
|
||||
}
|
||||
|
|
@ -1973,9 +1973,13 @@ type blockProcessingResult struct {
|
|||
witness *stateless.Witness
|
||||
}
|
||||
|
||||
// processBlock executes and validates the given block. If there was no error
|
||||
func (bpr *blockProcessingResult) Witness() *stateless.Witness {
|
||||
return bpr.witness
|
||||
}
|
||||
|
||||
// ProcessBlock executes and validates the given block. If there was no error
|
||||
// it writes the block and associated state to database.
|
||||
func (bc *BlockChain) processBlock(parentRoot common.Hash, block *types.Block, setHead bool, makeWitness bool) (_ *blockProcessingResult, blockEndErr error) {
|
||||
func (bc *BlockChain) ProcessBlock(parentRoot common.Hash, block *types.Block, setHead bool, makeWitness bool) (_ *blockProcessingResult, blockEndErr error) {
|
||||
var (
|
||||
err error
|
||||
startTime = time.Now()
|
||||
|
|
|
|||
|
|
@ -19,20 +19,21 @@ package stateless
|
|||
import (
|
||||
"io"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
)
|
||||
|
||||
// toExtWitness converts our internal witness representation to the consensus one.
|
||||
func (w *Witness) toExtWitness() *extWitness {
|
||||
ext := &extWitness{
|
||||
// ToExtWitness converts our internal witness representation to the consensus one.
|
||||
func (w *Witness) ToExtWitness() *ExtWitness {
|
||||
ext := &ExtWitness{
|
||||
Headers: w.Headers,
|
||||
}
|
||||
ext.Codes = make([][]byte, 0, len(w.Codes))
|
||||
ext.Codes = make([]hexutil.Bytes, 0, len(w.Codes))
|
||||
for code := range w.Codes {
|
||||
ext.Codes = append(ext.Codes, []byte(code))
|
||||
}
|
||||
ext.State = make([][]byte, 0, len(w.State))
|
||||
ext.State = make([]hexutil.Bytes, 0, len(w.State))
|
||||
for node := range w.State {
|
||||
ext.State = append(ext.State, []byte(node))
|
||||
}
|
||||
|
|
@ -40,7 +41,7 @@ func (w *Witness) toExtWitness() *extWitness {
|
|||
}
|
||||
|
||||
// fromExtWitness converts the consensus witness format into our internal one.
|
||||
func (w *Witness) fromExtWitness(ext *extWitness) error {
|
||||
func (w *Witness) fromExtWitness(ext *ExtWitness) error {
|
||||
w.Headers = ext.Headers
|
||||
|
||||
w.Codes = make(map[string]struct{}, len(ext.Codes))
|
||||
|
|
@ -56,21 +57,22 @@ func (w *Witness) fromExtWitness(ext *extWitness) error {
|
|||
|
||||
// EncodeRLP serializes a witness as RLP.
|
||||
func (w *Witness) EncodeRLP(wr io.Writer) error {
|
||||
return rlp.Encode(wr, w.toExtWitness())
|
||||
return rlp.Encode(wr, w.ToExtWitness())
|
||||
}
|
||||
|
||||
// DecodeRLP decodes a witness from RLP.
|
||||
func (w *Witness) DecodeRLP(s *rlp.Stream) error {
|
||||
var ext extWitness
|
||||
var ext ExtWitness
|
||||
if err := s.Decode(&ext); err != nil {
|
||||
return err
|
||||
}
|
||||
return w.fromExtWitness(&ext)
|
||||
}
|
||||
|
||||
// extWitness is a witness RLP encoding for transferring across clients.
|
||||
type extWitness struct {
|
||||
Headers []*types.Header
|
||||
Codes [][]byte
|
||||
State [][]byte
|
||||
// ExtWitness is a witness RLP encoding for transferring across clients.
|
||||
type ExtWitness struct {
|
||||
Headers []*types.Header `json:"headers"`
|
||||
Codes []hexutil.Bytes `json:"codes"`
|
||||
State []hexutil.Bytes `json:"state"`
|
||||
Keys []hexutil.Bytes `json:"keys"`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -100,6 +100,10 @@ func (w *Witness) AddState(nodes map[string][]byte) {
|
|||
}
|
||||
}
|
||||
|
||||
func (w *Witness) AddKey() {
|
||||
panic("not yet implemented")
|
||||
}
|
||||
|
||||
// Copy deep-copies the witness object. Witness.Block isn't deep-copied as it
|
||||
// is never mutated by Witness
|
||||
func (w *Witness) Copy() *Witness {
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
@ -491,3 +492,43 @@ func (api *DebugAPI) StateSize(blockHashOrNumber *rpc.BlockNumberOrHash) (interf
|
|||
"contractCodeBytes": hexutil.Uint64(stats.ContractCodeBytes),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (api *DebugAPI) ExecutionWitness(bn rpc.BlockNumber) (*stateless.ExtWitness, error) {
|
||||
bc := api.eth.blockchain
|
||||
block, err := api.eth.APIBackend.BlockByNumber(context.Background(), bn)
|
||||
if err != nil {
|
||||
return &stateless.ExtWitness{}, fmt.Errorf("block number %v not found", bn)
|
||||
}
|
||||
|
||||
parent := bc.GetHeader(block.ParentHash(), block.NumberU64()-1)
|
||||
if parent == nil {
|
||||
return &stateless.ExtWitness{}, fmt.Errorf("block number %v found, but parent missing", bn)
|
||||
}
|
||||
|
||||
result, err := bc.ProcessBlock(parent.Root, block, false, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return result.Witness().ToExtWitness(), nil
|
||||
}
|
||||
|
||||
func (api *DebugAPI) ExecutionWitnessByHash(hash common.Hash) (*stateless.ExtWitness, error) {
|
||||
bc := api.eth.blockchain
|
||||
block := bc.GetBlockByHash(hash)
|
||||
if block == nil {
|
||||
return &stateless.ExtWitness{}, fmt.Errorf("block hash %x not found", hash)
|
||||
}
|
||||
|
||||
parent := bc.GetHeader(block.ParentHash(), block.NumberU64()-1)
|
||||
if parent == nil {
|
||||
return &stateless.ExtWitness{}, fmt.Errorf("block number %x found, but parent missing", hash)
|
||||
}
|
||||
|
||||
result, err := bc.ProcessBlock(parent.Root, block, false, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return result.Witness().ToExtWitness(), nil
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue