diff --git a/core/blockchain.go b/core/blockchain.go index c97897cd70..939b46634f 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -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() diff --git a/core/stateless/encoding.go b/core/stateless/encoding.go index 5f4cb0ea3c..5c43159e66 100644 --- a/core/stateless/encoding.go +++ b/core/stateless/encoding.go @@ -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"` } diff --git a/core/stateless/witness.go b/core/stateless/witness.go index 371a128f48..588c895a2f 100644 --- a/core/stateless/witness.go +++ b/core/stateless/witness.go @@ -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 { diff --git a/eth/api_debug.go b/eth/api_debug.go index 9cedbcbb2a..892e103213 100644 --- a/eth/api_debug.go +++ b/eth/api_debug.go @@ -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 +}