mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-05-13 03:26:38 +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.
|
// The traced section of block import.
|
||||||
start := time.Now()
|
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 {
|
if err != nil {
|
||||||
return nil, it.index, err
|
return nil, it.index, err
|
||||||
}
|
}
|
||||||
|
|
@ -1973,9 +1973,13 @@ type blockProcessingResult struct {
|
||||||
witness *stateless.Witness
|
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.
|
// 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 (
|
var (
|
||||||
err error
|
err error
|
||||||
startTime = time.Now()
|
startTime = time.Now()
|
||||||
|
|
|
||||||
|
|
@ -19,20 +19,21 @@ package stateless
|
||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
)
|
)
|
||||||
|
|
||||||
// toExtWitness converts our internal witness representation to the consensus one.
|
// ToExtWitness converts our internal witness representation to the consensus one.
|
||||||
func (w *Witness) toExtWitness() *extWitness {
|
func (w *Witness) ToExtWitness() *ExtWitness {
|
||||||
ext := &extWitness{
|
ext := &ExtWitness{
|
||||||
Headers: w.Headers,
|
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 {
|
for code := range w.Codes {
|
||||||
ext.Codes = append(ext.Codes, []byte(code))
|
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 {
|
for node := range w.State {
|
||||||
ext.State = append(ext.State, []byte(node))
|
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.
|
// 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.Headers = ext.Headers
|
||||||
|
|
||||||
w.Codes = make(map[string]struct{}, len(ext.Codes))
|
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.
|
// EncodeRLP serializes a witness as RLP.
|
||||||
func (w *Witness) EncodeRLP(wr io.Writer) error {
|
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.
|
// DecodeRLP decodes a witness from RLP.
|
||||||
func (w *Witness) DecodeRLP(s *rlp.Stream) error {
|
func (w *Witness) DecodeRLP(s *rlp.Stream) error {
|
||||||
var ext extWitness
|
var ext ExtWitness
|
||||||
if err := s.Decode(&ext); err != nil {
|
if err := s.Decode(&ext); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return w.fromExtWitness(&ext)
|
return w.fromExtWitness(&ext)
|
||||||
}
|
}
|
||||||
|
|
||||||
// extWitness is a witness RLP encoding for transferring across clients.
|
// ExtWitness is a witness RLP encoding for transferring across clients.
|
||||||
type extWitness struct {
|
type ExtWitness struct {
|
||||||
Headers []*types.Header
|
Headers []*types.Header `json:"headers"`
|
||||||
Codes [][]byte
|
Codes []hexutil.Bytes `json:"codes"`
|
||||||
State [][]byte
|
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
|
// Copy deep-copies the witness object. Witness.Block isn't deep-copied as it
|
||||||
// is never mutated by Witness
|
// is never mutated by Witness
|
||||||
func (w *Witness) Copy() *Witness {
|
func (w *Witness) Copy() *Witness {
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"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/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/internal/ethapi"
|
"github.com/ethereum/go-ethereum/internal/ethapi"
|
||||||
|
|
@ -491,3 +492,43 @@ func (api *DebugAPI) StateSize(blockHashOrNumber *rpc.BlockNumberOrHash) (interf
|
||||||
"contractCodeBytes": hexutil.Uint64(stats.ContractCodeBytes),
|
"contractCodeBytes": hexutil.Uint64(stats.ContractCodeBytes),
|
||||||
}, nil
|
}, 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