Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 1 addition & 10 deletions cmd/keeper/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,17 +53,8 @@ func main() {
}
vmConfig := vm.Config{}

crossStateRoot, crossReceiptRoot, err := core.ExecuteStateless(context.Background(), chainConfig, vmConfig, payload.Block, payload.Witness)
if err != nil {
if err := core.ExecuteStateless(context.Background(), chainConfig, vmConfig, payload.Block, payload.Witness); err != nil {
fmt.Fprintf(os.Stderr, "stateless self-validation failed: %v\n", err)
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)
}
Comment on lines -61 to -68
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Post state check (ValidateState) is now done inside of ExecuteStateless

}
33 changes: 3 additions & 30 deletions core/block_validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import (
"errors"
"fmt"

"github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/params"
Expand All @@ -33,16 +32,11 @@ import (
// BlockValidator implements Validator.
type BlockValidator struct {
config *params.ChainConfig // Chain configuration options
bc *BlockChain // Canonical block chain
}

// NewBlockValidator returns a new block validator which is safe for re-use
func NewBlockValidator(config *params.ChainConfig, blockchain *BlockChain) *BlockValidator {
validator := &BlockValidator{
config: config,
bc: blockchain,
}
return validator
func NewBlockValidator(config *params.ChainConfig) *BlockValidator {
return &BlockValidator{config: config}
}

// ValidateBody validates the given block's uncles and verifies the block
Expand All @@ -53,17 +47,9 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error {
if v.config.IsOsaka(block.Number(), block.Time()) && block.Size() > params.MaxBlockSize {
return ErrBlockOversized
}
// Check whether the block is already imported.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The checks that we have moved from here are only needed if you have state and are safe guards to check if we should indeed insert this block into the chain. It has been moved into blockchain_insert so that ExecuteStateless can use this method as is for pre execution checks.

The checks that remain in this method are essentially checking the consistency between the block body and the header (pre-execution)

if v.bc.HasBlockAndState(block.Hash(), block.NumberU64()) {
return ErrKnownBlock
}

// Header validity is known at this point. Here we verify that uncles, transactions
// and withdrawals given in the block body match the header.
header := block.Header()
if err := v.bc.engine.VerifyUncles(v.bc, block); err != nil {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This check is still required even after the Merge, ensuring the uncle list is empty. I believe it's also required in stateless mode.

// VerifyUncles verifies that the given block's uncles conform to the consensus
// rules of the Ethereum consensus engine.
func (beacon *Beacon) VerifyUncles(chain consensus.ChainReader, block *types.Block) error {
	if !beacon.IsPoSHeader(block.Header()) {
		return beacon.ethone.VerifyUncles(chain, block)
	}
	// Verify that there is no uncle block. It's explicitly disabled in the beacon
	if len(block.Uncles()) > 0 {
		return errTooManyUncles
	}
	return nil
}

return err
}
if hash := types.CalcUncleHash(block.Uncles()); hash != header.UncleHash {
return fmt.Errorf("uncle root hash mismatch (header value %x, calculated %x)", header.UncleHash, hash)
}
Expand Down Expand Up @@ -110,20 +96,12 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error {
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
}

// 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.
func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateDB, res *ProcessResult, stateless bool) error {
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We no longer need to return early when in stateless mode because stateless mode does the same checks as stateful mode

func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateDB, res *ProcessResult) error {
if res == nil {
return errors.New("nil ProcessResult value")
}
Expand All @@ -141,11 +119,6 @@ func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateD
if rbloom != header.Bloom {
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
}
Comment on lines -144 to -148
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is designed for another use case and is still needed. I agree that, in your case, it should be called, but then it has to be via another flag.

Copy link
Copy Markdown
Member

@rjl493456442 rjl493456442 Mar 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the original intention is that: the stateless mode produces all the hashes without the hints (such as the state root in block header) and these hashes are explicitly checked outside the stateless execution.

But I feel Kev is right here. The input for stateless execution is: (a) the block (b) the state (c) the state proofs.
The executor is responsible for verifying the states and making sure the produced hashes are not malformed.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

func ExecuteStateless(ctx context.Context, config *params.ChainConfig, vmconfig vm.Config, block *types.Block, witness *stateless.Witness) error {
	// Create and populate the state database to serve as the stateless backend
	memdb := witness.MakeHashDB()
	db, err := state.New(witness.Root(), state.NewDatabase(triedb.NewDatabase(memdb, triedb.HashDefaults), nil))
	if err != nil {
		return err
	}

The pre-execution root is derived from the witness. I am not 100% sure it's correct. Ideally it should be the state root of the parent referred by the block.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally it should be the state root of the parent referred by the block.

Yep this is my understanding, so we would:

  • Retrieve the purported parent header from the execution witness
  • Check that it is the parent header
  • Take the post state root from that header and use it as the pre-state root for this block

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't look at the pipeline for this part of this part of the code, ie whether memdb , db etc are correctly formed. I was planning to look at that as a followup, but can also do it in this PR

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rjl493456442 my point is that the other use case needs to be fixed before you delete this. Doing this would recompute the state root twice. You can't just delete that check.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you say what this other usecase is?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cross-validation

// The receipt Trie's root (R = (Tr [[H1, R1], ... [Hn, Rn]]))
receiptSha := types.DeriveSha(res.Receipts, trie.NewStackTrie(nil))
if receiptSha != header.ReceiptHash {
Expand Down
22 changes: 4 additions & 18 deletions core/blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -423,7 +423,7 @@ func NewBlockChain(db ethdb.Database, genesis *Genesis, engine consensus.Engine,
return nil, err
}
bc.flushInterval.Store(int64(cfg.TrieTimeLimit))
bc.validator = NewBlockValidator(chainConfig, bc)
bc.validator = NewBlockValidator(chainConfig)
bc.prefetcher = newStatePrefetcher(chainConfig, bc.hc)
bc.processor = NewStateProcessor(bc.hc)

Expand Down Expand Up @@ -1908,7 +1908,7 @@ func (bc *BlockChain) insertChain(ctx context.Context, chain types.Blocks, setHe
defer close(abort)

// 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()

// Left-trim all the known blocks that don't need to build snapshot
Expand Down Expand Up @@ -2259,7 +2259,7 @@ func (bc *BlockChain) ProcessBlock(ctx context.Context, parentRoot common.Hash,

vstart := time.Now()
_, _, spanEnd = telemetry.StartSpan(ctx, "bc.validator.ValidateState")
err = bc.validator.ValidateState(block, statedb, res, false)
err = bc.validator.ValidateState(block, statedb, res)
spanEnd(&err)
if err != nil {
bc.reportBadBlock(block, res, err)
Expand All @@ -2276,24 +2276,10 @@ func (bc *BlockChain) ProcessBlock(ctx context.Context, parentRoot common.Hash,
if witness := statedb.Witness(); witness != nil && config.StatelessSelfValidation {
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())

Comment on lines -2279 to -2285
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no longer need these because stateless mode takes in the unmodified block. I think it was a bit awkward before because the code was executing a block that has fields in its header that were intentionally zeroed out. As noted above, this led to some parts of the code returning early when in stateless mode or just skipping important checks like ValidateBody

// Run the stateless self-cross-validation
crossStateRoot, crossReceiptRoot, err := ExecuteStateless(ctx, bc.chainConfig, bc.cfg.VmConfig, task, witness)
if err != nil {
if err := ExecuteStateless(ctx, bc.chainConfig, bc.cfg.VmConfig, block, witness); err != nil {
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 (
Expand Down
31 changes: 26 additions & 5 deletions core/blockchain_insert.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (

"github.com/ethereum/go-ethereum/common"
"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/log"
)
Expand Down Expand Up @@ -95,19 +96,21 @@ type insertIterator struct {
results <-chan error // Verification result sink from the consensus engine
errors []error // Header verification errors for the blocks

index int // Current offset of the iterator
validator Validator // Validator to run if verification succeeds
index int // Current offset of the iterator
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
// 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{
chain: chain,
results: results,
errors: make([]error, 0, len(chain)),
index: -1,
validator: validator,
bc: bc,
}
}

Expand All @@ -127,8 +130,26 @@ func (it *insertIterator) next() (*types.Block, error) {
if it.errors[it.index] != nil {
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-merge only)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please restore it back to Body validation, it's still required after the merge.

Copy link
Copy Markdown
Contributor Author

@kevaundray kevaundray Mar 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah I think I am missing something, I thought that it would be covered by verifyHeader and validateBody.

My thinking was that:

  • In verifyHeader, we check if uncleHash == EmptyUncleHash here

  • Then in validateBody, we check that the calculated UncleHash matches the one in the header here

Opened a PR here to check

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we have some duplicated checks here, honestly.

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
}
Comment on lines +136 to +150
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Checks that were in ValidateBody have been moved here.

These are very much tied to the blockchain instance and not related to verifying a block against its header fields

// Validate the block body against header
return block, it.validator.ValidateBody(block)
}

// previous returns the previous header that was being processed, or nil.
Expand Down
2 changes: 1 addition & 1 deletion core/blockchain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ func testBlockChainImport(chain types.Blocks, blockchain *BlockChain) error {
blockchain.reportBadBlock(block, res, err)
return err
}
err = blockchain.validator.ValidateState(block, statedb, res, false)
err = blockchain.validator.ValidateState(block, statedb, res)
if err != nil {
blockchain.reportBadBlock(block, res, err)
return err
Expand Down
50 changes: 24 additions & 26 deletions core/stateless.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,56 +27,54 @@ import (
"github.com/ethereum/go-ethereum/core/stateless"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/trie"
"github.com/ethereum/go-ethereum/triedb"
)

// ExecuteStateless runs a stateless execution based on a witness, verifies
// everything it can locally and returns the state root and receipt root, that
// need the other side to explicitly check.
// ExecuteStateless runs a stateless execution based on a witness, fully
// validating the block including header, body, state root and receipt root.
//
// 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 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.
func ExecuteStateless(ctx context.Context, config *params.ChainConfig, vmconfig vm.Config, block *types.Block, witness *stateless.Witness) (common.Hash, common.Hash, 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())
}
func ExecuteStateless(ctx context.Context, config *params.ChainConfig, vmconfig vm.Config, block *types.Block, witness *stateless.Witness) error {
// Create and populate the state database to serve as the stateless backend
memdb := witness.MakeHashDB()
db, err := state.New(witness.Root(), state.NewDatabase(triedb.NewDatabase(memdb, triedb.HashDefaults), 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
engine := beacon.New(ethash.NewFaker())
chain := &HeaderChain{
config: config,
chainDb: memdb,
headerCache: lru.NewCache[common.Hash, *types.Header](256),
engine: beacon.New(ethash.NewFaker()),
engine: engine,
}
processor := NewStateProcessor(chain)
validator := NewBlockValidator(config, nil) // No chain, we only validate the state, not the block
validator := NewBlockValidator(config)

// Pre-execution: Verify the block header against the parent header
if err := engine.VerifyHeader(chain, block.Header()); err != nil {
return err
}

// Run the stateless blocks processing and self-validate certain fields
// Pre-execution: Verify the block body against the header
if err := validator.ValidateBody(block); err != nil {
return err
}
Comment on lines +67 to +69
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

new check added, so we now completely validate the block


// Process the block by executing all transactions
res, err := processor.Process(ctx, block, db, vmconfig)
if err != nil {
return common.Hash{}, common.Hash{}, err
return err
}
if err = validator.ValidateState(block, db, res, true); err != nil {
return common.Hash{}, common.Hash{}, err
}
// Almost everything validated, but receipt and state root needs to be returned
receiptRoot := types.DeriveSha(res.Receipts, trie.NewStackTrie(nil))
stateRoot := db.IntermediateRoot(config.IsEIP158(block.Number()))
return stateRoot, receiptRoot, nil
Comment on lines -78 to -81
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We no longer return receiptRoot and stateRoot, however if the block was valid, we can just call methods on Block to get them


// Post-execution: Validate gas, bloom, receipts, state root and
// other post execution artifacts
return validator.ValidateState(block, db, res)
}
2 changes: 1 addition & 1 deletion core/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ type Validator interface {
ValidateBody(block *types.Block) error

// 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.
Expand Down
31 changes: 8 additions & 23 deletions eth/catalyst/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1690,26 +1690,17 @@ func TestWitnessCreationAndConsumption(t *testing.T) {
t.Fatalf("witness missing from payload")
}
// Test stateless execution of the created witness
wantStateRoot := envelope.ExecutionPayload.StateRoot
wantReceiptRoot := envelope.ExecutionPayload.ReceiptsRoot

envelope.ExecutionPayload.StateRoot = common.Hash{}
envelope.ExecutionPayload.ReceiptsRoot = common.Hash{}

Comment on lines -1696 to -1698
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

main change, we no longer zero out the state root and receipt root

res, err := api.ExecuteStatelessPayloadV3(*envelope.ExecutionPayload, []common.Hash{}, &common.Hash{42}, *envelope.Witness)
if err != nil {
t.Fatalf("error executing stateless payload witness: %v", err)
}
if res.StateRoot != wantStateRoot {
t.Fatalf("stateless state root mismatch: have %v, want %v", res.StateRoot, wantStateRoot)
if res.StateRoot != envelope.ExecutionPayload.StateRoot {
t.Fatalf("stateless state root mismatch: have %v, want %v", res.StateRoot, envelope.ExecutionPayload.StateRoot)
}
if res.ReceiptsRoot != wantReceiptRoot {
t.Fatalf("stateless receipt root mismatch: have %v, want %v", res.ReceiptsRoot, wantReceiptRoot)
if res.ReceiptsRoot != envelope.ExecutionPayload.ReceiptsRoot {
t.Fatalf("stateless receipt root mismatch: have %v, want %v", res.ReceiptsRoot, envelope.ExecutionPayload.ReceiptsRoot)
}
// Test block insertion with witness creation
envelope.ExecutionPayload.StateRoot = wantStateRoot
envelope.ExecutionPayload.ReceiptsRoot = wantReceiptRoot

res2, err := api.NewPayloadWithWitnessV3(context.Background(), *envelope.ExecutionPayload, []common.Hash{}, &common.Hash{42})
if err != nil {
t.Fatalf("error executing stateless payload witness: %v", err)
Expand All @@ -1718,21 +1709,15 @@ func TestWitnessCreationAndConsumption(t *testing.T) {
t.Fatalf("witness missing from payload")
}
// Test stateless execution of the created witness
wantStateRoot = envelope.ExecutionPayload.StateRoot
wantReceiptRoot = envelope.ExecutionPayload.ReceiptsRoot

envelope.ExecutionPayload.StateRoot = common.Hash{}
envelope.ExecutionPayload.ReceiptsRoot = common.Hash{}

res, err = api.ExecuteStatelessPayloadV3(*envelope.ExecutionPayload, []common.Hash{}, &common.Hash{42}, *res2.Witness)
if err != nil {
t.Fatalf("error executing stateless payload witness: %v", err)
}
if res.StateRoot != wantStateRoot {
t.Fatalf("stateless state root mismatch: have %v, want %v", res.StateRoot, wantStateRoot)
if res.StateRoot != envelope.ExecutionPayload.StateRoot {
t.Fatalf("stateless state root mismatch: have %v, want %v", res.StateRoot, envelope.ExecutionPayload.StateRoot)
}
if res.ReceiptsRoot != wantReceiptRoot {
t.Fatalf("stateless receipt root mismatch: have %v, want %v", res.ReceiptsRoot, wantReceiptRoot)
if res.ReceiptsRoot != envelope.ExecutionPayload.ReceiptsRoot {
t.Fatalf("stateless receipt root mismatch: have %v, want %v", res.ReceiptsRoot, envelope.ExecutionPayload.ReceiptsRoot)
}
}

Expand Down
5 changes: 2 additions & 3 deletions eth/catalyst/witness.go
Original file line number Diff line number Diff line change
Expand Up @@ -284,11 +284,10 @@ func (api *ConsensusAPI) executeStatelessPayload(params engine.ExecutableData, v
api.lastNewPayloadUpdate.Store(time.Now().Unix())

log.Trace("Executing block statelessly", "number", block.Number(), "hash", params.BlockHash)
stateRoot, receiptRoot, err := core.ExecuteStateless(context.Background(), api.config(), vm.Config{}, block, witness)
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • I don't think anyone is using these cross validation methods?

  • Note: the change is non-breaking because the input is a valid block and its only internally that the blocks have their state root and receipt root zeroed out.

if err != nil {
if err := core.ExecuteStateless(context.Background(), api.config(), vm.Config{}, block, witness); err != nil {
log.Warn("ExecuteStatelessPayload: execution failed", "err", err)
errorMsg := err.Error()
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