mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-07 07:28:40 +00:00
initial commit
This commit is contained in:
parent
ede376af8e
commit
3880f712f1
8 changed files with 58 additions and 93 deletions
|
|
@ -53,17 +53,8 @@ func main() {
|
||||||
}
|
}
|
||||||
vmConfig := vm.Config{}
|
vmConfig := vm.Config{}
|
||||||
|
|
||||||
crossStateRoot, crossReceiptRoot, err := core.ExecuteStateless(context.Background(), chainConfig, vmConfig, payload.Block, payload.Witness)
|
if err := core.ExecuteStateless(context.Background(), chainConfig, vmConfig, payload.Block, payload.Witness); err != nil {
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "stateless self-validation failed: %v\n", err)
|
fmt.Fprintf(os.Stderr, "stateless self-validation failed: %v\n", err)
|
||||||
os.Exit(10)
|
os.Exit(10)
|
||||||
}
|
}
|
||||||
if crossStateRoot != payload.Block.Root() {
|
|
||||||
fmt.Fprintf(os.Stderr, "stateless self-validation root mismatch (cross: %x local: %x)\n", crossStateRoot, payload.Block.Root())
|
|
||||||
os.Exit(11)
|
|
||||||
}
|
|
||||||
if crossReceiptRoot != payload.Block.ReceiptHash() {
|
|
||||||
fmt.Fprintf(os.Stderr, "stateless self-validation receipt root mismatch (cross: %x local: %x)\n", crossReceiptRoot, payload.Block.ReceiptHash())
|
|
||||||
os.Exit(12)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,6 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/consensus"
|
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
|
@ -33,16 +32,11 @@ import (
|
||||||
// BlockValidator implements Validator.
|
// BlockValidator implements Validator.
|
||||||
type BlockValidator struct {
|
type BlockValidator struct {
|
||||||
config *params.ChainConfig // Chain configuration options
|
config *params.ChainConfig // Chain configuration options
|
||||||
bc *BlockChain // Canonical block chain
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewBlockValidator returns a new block validator which is safe for re-use
|
// NewBlockValidator returns a new block validator which is safe for re-use
|
||||||
func NewBlockValidator(config *params.ChainConfig, blockchain *BlockChain) *BlockValidator {
|
func NewBlockValidator(config *params.ChainConfig) *BlockValidator {
|
||||||
validator := &BlockValidator{
|
return &BlockValidator{config: config}
|
||||||
config: config,
|
|
||||||
bc: blockchain,
|
|
||||||
}
|
|
||||||
return validator
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ValidateBody validates the given block's uncles and verifies the block
|
// ValidateBody validates the given block's uncles and verifies the block
|
||||||
|
|
@ -53,17 +47,9 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error {
|
||||||
if v.config.IsOsaka(block.Number(), block.Time()) && block.Size() > params.MaxBlockSize {
|
if v.config.IsOsaka(block.Number(), block.Time()) && block.Size() > params.MaxBlockSize {
|
||||||
return ErrBlockOversized
|
return ErrBlockOversized
|
||||||
}
|
}
|
||||||
// Check whether the block is already imported.
|
|
||||||
if v.bc.HasBlockAndState(block.Hash(), block.NumberU64()) {
|
|
||||||
return ErrKnownBlock
|
|
||||||
}
|
|
||||||
|
|
||||||
// Header validity is known at this point. Here we verify that uncles, transactions
|
// Header validity is known at this point. Here we verify that uncles, transactions
|
||||||
// and withdrawals given in the block body match the header.
|
// and withdrawals given in the block body match the header.
|
||||||
header := block.Header()
|
header := block.Header()
|
||||||
if err := v.bc.engine.VerifyUncles(v.bc, block); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if hash := types.CalcUncleHash(block.Uncles()); hash != header.UncleHash {
|
if hash := types.CalcUncleHash(block.Uncles()); hash != header.UncleHash {
|
||||||
return fmt.Errorf("uncle root hash mismatch (header value %x, calculated %x)", header.UncleHash, hash)
|
return fmt.Errorf("uncle root hash mismatch (header value %x, calculated %x)", header.UncleHash, hash)
|
||||||
}
|
}
|
||||||
|
|
@ -110,20 +96,12 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error {
|
||||||
return errors.New("data blobs present in block body")
|
return errors.New("data blobs present in block body")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ancestor block must be known.
|
|
||||||
if !v.bc.HasBlockAndState(block.ParentHash(), block.NumberU64()-1) {
|
|
||||||
if !v.bc.HasBlock(block.ParentHash(), block.NumberU64()-1) {
|
|
||||||
return consensus.ErrUnknownAncestor
|
|
||||||
}
|
|
||||||
return consensus.ErrPrunedAncestor
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ValidateState validates the various changes that happen after a state transition,
|
// ValidateState validates the various changes that happen after a state transition,
|
||||||
// such as amount of used gas, the receipt roots and the state root itself.
|
// such as amount of used gas, the receipt roots and the state root itself.
|
||||||
func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateDB, res *ProcessResult, stateless bool) error {
|
func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateDB, res *ProcessResult) error {
|
||||||
if res == nil {
|
if res == nil {
|
||||||
return errors.New("nil ProcessResult value")
|
return errors.New("nil ProcessResult value")
|
||||||
}
|
}
|
||||||
|
|
@ -141,11 +119,6 @@ func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateD
|
||||||
if rbloom != header.Bloom {
|
if rbloom != header.Bloom {
|
||||||
return fmt.Errorf("invalid bloom (remote: %x local: %x)", header.Bloom, rbloom)
|
return fmt.Errorf("invalid bloom (remote: %x local: %x)", header.Bloom, rbloom)
|
||||||
}
|
}
|
||||||
// In stateless mode, return early because the receipt and state root are not
|
|
||||||
// provided through the witness, rather the cross validator needs to return it.
|
|
||||||
if stateless {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
// The receipt Trie's root (R = (Tr [[H1, R1], ... [Hn, Rn]]))
|
// The receipt Trie's root (R = (Tr [[H1, R1], ... [Hn, Rn]]))
|
||||||
receiptSha := types.DeriveSha(res.Receipts, trie.NewStackTrie(nil))
|
receiptSha := types.DeriveSha(res.Receipts, trie.NewStackTrie(nil))
|
||||||
if receiptSha != header.ReceiptHash {
|
if receiptSha != header.ReceiptHash {
|
||||||
|
|
|
||||||
|
|
@ -423,7 +423,7 @@ func NewBlockChain(db ethdb.Database, genesis *Genesis, engine consensus.Engine,
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
bc.flushInterval.Store(int64(cfg.TrieTimeLimit))
|
bc.flushInterval.Store(int64(cfg.TrieTimeLimit))
|
||||||
bc.validator = NewBlockValidator(chainConfig, bc)
|
bc.validator = NewBlockValidator(chainConfig)
|
||||||
bc.prefetcher = newStatePrefetcher(chainConfig, bc.hc)
|
bc.prefetcher = newStatePrefetcher(chainConfig, bc.hc)
|
||||||
bc.processor = NewStateProcessor(bc.hc)
|
bc.processor = NewStateProcessor(bc.hc)
|
||||||
|
|
||||||
|
|
@ -1908,7 +1908,7 @@ func (bc *BlockChain) insertChain(ctx context.Context, chain types.Blocks, setHe
|
||||||
defer close(abort)
|
defer close(abort)
|
||||||
|
|
||||||
// Peek the error for the first block to decide the directing import logic
|
// Peek the error for the first block to decide the directing import logic
|
||||||
it := newInsertIterator(chain, results, bc.validator)
|
it := newInsertIterator(chain, results, bc.validator, bc)
|
||||||
block, err := it.next()
|
block, err := it.next()
|
||||||
|
|
||||||
// Left-trim all the known blocks that don't need to build snapshot
|
// Left-trim all the known blocks that don't need to build snapshot
|
||||||
|
|
@ -2259,7 +2259,7 @@ func (bc *BlockChain) ProcessBlock(ctx context.Context, parentRoot common.Hash,
|
||||||
|
|
||||||
vstart := time.Now()
|
vstart := time.Now()
|
||||||
_, _, spanEnd = telemetry.StartSpan(ctx, "bc.validator.ValidateState")
|
_, _, spanEnd = telemetry.StartSpan(ctx, "bc.validator.ValidateState")
|
||||||
err = bc.validator.ValidateState(block, statedb, res, false)
|
err = bc.validator.ValidateState(block, statedb, res)
|
||||||
spanEnd(&err)
|
spanEnd(&err)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
bc.reportBadBlock(block, res, err)
|
bc.reportBadBlock(block, res, err)
|
||||||
|
|
@ -2276,24 +2276,10 @@ func (bc *BlockChain) ProcessBlock(ctx context.Context, parentRoot common.Hash,
|
||||||
if witness := statedb.Witness(); witness != nil && config.StatelessSelfValidation {
|
if witness := statedb.Witness(); witness != nil && config.StatelessSelfValidation {
|
||||||
log.Warn("Running stateless self-validation", "block", block.Number(), "hash", block.Hash())
|
log.Warn("Running stateless self-validation", "block", block.Number(), "hash", block.Hash())
|
||||||
|
|
||||||
// Remove critical computed fields from the block to force true recalculation
|
|
||||||
context := block.Header()
|
|
||||||
context.Root = common.Hash{}
|
|
||||||
context.ReceiptHash = common.Hash{}
|
|
||||||
|
|
||||||
task := types.NewBlockWithHeader(context).WithBody(*block.Body())
|
|
||||||
|
|
||||||
// Run the stateless self-cross-validation
|
// Run the stateless self-cross-validation
|
||||||
crossStateRoot, crossReceiptRoot, err := ExecuteStateless(ctx, bc.chainConfig, bc.cfg.VmConfig, task, witness)
|
if err := ExecuteStateless(ctx, bc.chainConfig, bc.cfg.VmConfig, block, witness); err != nil {
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("stateless self-validation failed: %v", err)
|
return nil, fmt.Errorf("stateless self-validation failed: %v", err)
|
||||||
}
|
}
|
||||||
if crossStateRoot != block.Root() {
|
|
||||||
return nil, fmt.Errorf("stateless self-validation root mismatch (cross: %x local: %x)", crossStateRoot, block.Root())
|
|
||||||
}
|
|
||||||
if crossReceiptRoot != block.ReceiptHash() {
|
|
||||||
return nil, fmt.Errorf("stateless self-validation receipt root mismatch (cross: %x local: %x)", crossReceiptRoot, block.ReceiptHash())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import (
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/mclock"
|
"github.com/ethereum/go-ethereum/common/mclock"
|
||||||
|
"github.com/ethereum/go-ethereum/consensus"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
)
|
)
|
||||||
|
|
@ -95,19 +96,21 @@ type insertIterator struct {
|
||||||
results <-chan error // Verification result sink from the consensus engine
|
results <-chan error // Verification result sink from the consensus engine
|
||||||
errors []error // Header verification errors for the blocks
|
errors []error // Header verification errors for the blocks
|
||||||
|
|
||||||
index int // Current offset of the iterator
|
index int // Current offset of the iterator
|
||||||
validator Validator // Validator to run if verification succeeds
|
validator Validator // Validator to run if verification succeeds
|
||||||
|
bc *BlockChain // Blockchain for admission checks
|
||||||
}
|
}
|
||||||
|
|
||||||
// newInsertIterator creates a new iterator based on the given blocks, which are
|
// newInsertIterator creates a new iterator based on the given blocks, which are
|
||||||
// assumed to be a contiguous chain.
|
// assumed to be a contiguous chain.
|
||||||
func newInsertIterator(chain types.Blocks, results <-chan error, validator Validator) *insertIterator {
|
func newInsertIterator(chain types.Blocks, results <-chan error, validator Validator, bc *BlockChain) *insertIterator {
|
||||||
return &insertIterator{
|
return &insertIterator{
|
||||||
chain: chain,
|
chain: chain,
|
||||||
results: results,
|
results: results,
|
||||||
errors: make([]error, 0, len(chain)),
|
errors: make([]error, 0, len(chain)),
|
||||||
index: -1,
|
index: -1,
|
||||||
validator: validator,
|
validator: validator,
|
||||||
|
bc: bc,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -127,8 +130,26 @@ func (it *insertIterator) next() (*types.Block, error) {
|
||||||
if it.errors[it.index] != nil {
|
if it.errors[it.index] != nil {
|
||||||
return it.chain[it.index], it.errors[it.index]
|
return it.chain[it.index], it.errors[it.index]
|
||||||
}
|
}
|
||||||
// Block header valid, run body validation and return
|
|
||||||
return it.chain[it.index], it.validator.ValidateBody(it.chain[it.index])
|
block := it.chain[it.index]
|
||||||
|
|
||||||
|
// Skip blocks we've already imported and fully processed.
|
||||||
|
if it.bc.HasBlockAndState(block.Hash(), block.NumberU64()) {
|
||||||
|
return block, ErrKnownBlock
|
||||||
|
}
|
||||||
|
// Verify uncle blocks against chain history (pre-mereg only)
|
||||||
|
if err := it.bc.engine.VerifyUncles(it.bc, block); err != nil {
|
||||||
|
return block, err
|
||||||
|
}
|
||||||
|
// Ensure the parent block is known and its state is available.
|
||||||
|
if !it.bc.HasBlockAndState(block.ParentHash(), block.NumberU64()-1) {
|
||||||
|
if !it.bc.HasBlock(block.ParentHash(), block.NumberU64()-1) {
|
||||||
|
return block, consensus.ErrUnknownAncestor
|
||||||
|
}
|
||||||
|
return block, consensus.ErrPrunedAncestor
|
||||||
|
}
|
||||||
|
// Validate the block body against header
|
||||||
|
return block, it.validator.ValidateBody(block)
|
||||||
}
|
}
|
||||||
|
|
||||||
// previous returns the previous header that was being processed, or nil.
|
// previous returns the previous header that was being processed, or nil.
|
||||||
|
|
|
||||||
|
|
@ -166,7 +166,7 @@ func testBlockChainImport(chain types.Blocks, blockchain *BlockChain) error {
|
||||||
blockchain.reportBadBlock(block, res, err)
|
blockchain.reportBadBlock(block, res, err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = blockchain.validator.ValidateState(block, statedb, res, false)
|
err = blockchain.validator.ValidateState(block, statedb, res)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
blockchain.reportBadBlock(block, res, err)
|
blockchain.reportBadBlock(block, res, err)
|
||||||
return err
|
return err
|
||||||
|
|
|
||||||
|
|
@ -27,56 +27,51 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/stateless"
|
"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/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/trie"
|
|
||||||
"github.com/ethereum/go-ethereum/triedb"
|
"github.com/ethereum/go-ethereum/triedb"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ExecuteStateless runs a stateless execution based on a witness, verifies
|
// ExecuteStateless runs a stateless execution based on a witness, fully
|
||||||
// everything it can locally and returns the state root and receipt root, that
|
// validating the block including header, body, state root and receipt root.
|
||||||
// need the other side to explicitly check.
|
|
||||||
//
|
//
|
||||||
// This method is a bit of a sore thumb here, but:
|
// This method is a bit of a sore thumb here, but:
|
||||||
// - It cannot be placed in core/stateless, because state.New prodces a circular dep
|
// - It cannot be placed in core/stateless, because state.New prodces a circular dep
|
||||||
// - It cannot be placed outside of core, because it needs to construct a dud headerchain
|
// - It cannot be placed outside of core, because it needs to construct a dud headerchain
|
||||||
//
|
//
|
||||||
// TODO(karalabe): Would be nice to resolve both issues above somehow and move it.
|
// TODO(karalabe): Would be nice to resolve both issues above somehow and move it.
|
||||||
func ExecuteStateless(ctx context.Context, config *params.ChainConfig, vmconfig vm.Config, block *types.Block, witness *stateless.Witness) (common.Hash, common.Hash, error) {
|
func ExecuteStateless(ctx context.Context, config *params.ChainConfig, vmconfig vm.Config, block *types.Block, witness *stateless.Witness) error {
|
||||||
// Sanity check if the supplied block accidentally contains a set root or
|
|
||||||
// receipt hash. If so, be very loud, but still continue.
|
|
||||||
if block.Root() != (common.Hash{}) {
|
|
||||||
log.Error("stateless runner received state root it's expected to calculate (faulty consensus client)", "block", block.Number())
|
|
||||||
}
|
|
||||||
if block.ReceiptHash() != (common.Hash{}) {
|
|
||||||
log.Error("stateless runner received receipt root it's expected to calculate (faulty consensus client)", "block", block.Number())
|
|
||||||
}
|
|
||||||
// Create and populate the state database to serve as the stateless backend
|
// Create and populate the state database to serve as the stateless backend
|
||||||
memdb := witness.MakeHashDB()
|
memdb := witness.MakeHashDB()
|
||||||
db, err := state.New(witness.Root(), state.NewDatabase(triedb.NewDatabase(memdb, triedb.HashDefaults), nil))
|
db, err := state.New(witness.Root(), state.NewDatabase(triedb.NewDatabase(memdb, triedb.HashDefaults), nil))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return common.Hash{}, common.Hash{}, err
|
return err
|
||||||
}
|
}
|
||||||
// Create a blockchain that is idle, but can be used to access headers through
|
// Create a blockchain that is idle, but can be used to access headers through
|
||||||
|
engine := beacon.New(ethash.NewFaker())
|
||||||
chain := &HeaderChain{
|
chain := &HeaderChain{
|
||||||
config: config,
|
config: config,
|
||||||
chainDb: memdb,
|
chainDb: memdb,
|
||||||
headerCache: lru.NewCache[common.Hash, *types.Header](256),
|
headerCache: lru.NewCache[common.Hash, *types.Header](256),
|
||||||
engine: beacon.New(ethash.NewFaker()),
|
engine: engine,
|
||||||
|
}
|
||||||
|
// Verify the block header against the parent header from the witness
|
||||||
|
if err := engine.VerifyHeader(chain, block.Header()); err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
processor := NewStateProcessor(chain)
|
processor := NewStateProcessor(chain)
|
||||||
validator := NewBlockValidator(config, nil) // No chain, we only validate the state, not the block
|
validator := NewBlockValidator(config)
|
||||||
|
|
||||||
// Run the stateless blocks processing and self-validate certain fields
|
// Verify the block body (transactions, withdrawals, blob gas) against the header
|
||||||
|
if err := validator.ValidateBody(block); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// Run the stateless block processing and self-validate all fields
|
||||||
res, err := processor.Process(ctx, block, db, vmconfig)
|
res, err := processor.Process(ctx, block, db, vmconfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return common.Hash{}, common.Hash{}, err
|
return err
|
||||||
}
|
}
|
||||||
if err = validator.ValidateState(block, db, res, true); err != nil {
|
if err = validator.ValidateState(block, db, res); err != nil {
|
||||||
return common.Hash{}, common.Hash{}, err
|
return err
|
||||||
}
|
}
|
||||||
// Almost everything validated, but receipt and state root needs to be returned
|
return nil
|
||||||
receiptRoot := types.DeriveSha(res.Receipts, trie.NewStackTrie(nil))
|
|
||||||
stateRoot := db.IntermediateRoot(config.IsEIP158(block.Number()))
|
|
||||||
return stateRoot, receiptRoot, nil
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ type Validator interface {
|
||||||
ValidateBody(block *types.Block) error
|
ValidateBody(block *types.Block) error
|
||||||
|
|
||||||
// ValidateState validates the given statedb and optionally the process result.
|
// ValidateState validates the given statedb and optionally the process result.
|
||||||
ValidateState(block *types.Block, state *state.StateDB, res *ProcessResult, stateless bool) error
|
ValidateState(block *types.Block, state *state.StateDB, res *ProcessResult) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prefetcher is an interface for pre-caching transaction signatures and state.
|
// Prefetcher is an interface for pre-caching transaction signatures and state.
|
||||||
|
|
|
||||||
|
|
@ -284,11 +284,10 @@ func (api *ConsensusAPI) executeStatelessPayload(params engine.ExecutableData, v
|
||||||
api.lastNewPayloadUpdate.Store(time.Now().Unix())
|
api.lastNewPayloadUpdate.Store(time.Now().Unix())
|
||||||
|
|
||||||
log.Trace("Executing block statelessly", "number", block.Number(), "hash", params.BlockHash)
|
log.Trace("Executing block statelessly", "number", block.Number(), "hash", params.BlockHash)
|
||||||
stateRoot, receiptRoot, err := core.ExecuteStateless(context.Background(), api.config(), vm.Config{}, block, witness)
|
if err := core.ExecuteStateless(context.Background(), api.config(), vm.Config{}, block, witness); err != nil {
|
||||||
if err != nil {
|
|
||||||
log.Warn("ExecuteStatelessPayload: execution failed", "err", err)
|
log.Warn("ExecuteStatelessPayload: execution failed", "err", err)
|
||||||
errorMsg := err.Error()
|
errorMsg := err.Error()
|
||||||
return engine.StatelessPayloadStatusV1{Status: engine.INVALID, ValidationError: &errorMsg}, nil
|
return engine.StatelessPayloadStatusV1{Status: engine.INVALID, ValidationError: &errorMsg}, nil
|
||||||
}
|
}
|
||||||
return engine.StatelessPayloadStatusV1{Status: engine.VALID, StateRoot: stateRoot, ReceiptsRoot: receiptRoot}, nil
|
return engine.StatelessPayloadStatusV1{Status: engine.VALID, StateRoot: block.Root(), ReceiptsRoot: block.ReceiptHash()}, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue