diff --git a/.github/workflows/kurtosis-stateless-e2e.yml b/.github/workflows/kurtosis-stateless-e2e.yml index c98b01aec0..8c0e50d9c6 100644 --- a/.github/workflows/kurtosis-stateless-e2e.yml +++ b/.github/workflows/kurtosis-stateless-e2e.yml @@ -58,7 +58,7 @@ jobs: uses: actions/checkout@v5 with: repository: 0xPolygon/kurtosis-pos - ref: stateless + ref: raneet10/stateless-parallel-import path: kurtosis-pos - name: Pre kurtosis run diff --git a/core/block_validator.go b/core/block_validator.go index 9a8389c813..57d52d0d03 100644 --- a/core/block_validator.go +++ b/core/block_validator.go @@ -131,7 +131,7 @@ func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateD } header := block.Header() if block.GasUsed() != res.GasUsed { - return fmt.Errorf("invalid gas used (remote: %d local: %d)", block.GasUsed(), res.GasUsed) + return fmt.Errorf("%w (remote: %d local: %d)", ErrGasUsedMismatch, block.GasUsed(), res.GasUsed) } // Validate the received block's bloom with the one derived from the generated receipts. // For valid blocks this should always validate to true. @@ -141,7 +141,7 @@ func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateD // everything. rbloom := types.MergeBloom(res.Receipts) if rbloom != header.Bloom { - return fmt.Errorf("invalid bloom (remote: %x local: %x)", header.Bloom, rbloom) + return fmt.Errorf("%w (remote: %x local: %x)", ErrBloomMismatch, 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. @@ -151,13 +151,13 @@ func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateD // The receipt Trie's root (R = (Tr [[H1, R1], ... [Hn, Rn]])) receiptSha := types.DeriveSha(res.Receipts, trie.NewStackTrie(nil)) if receiptSha != header.ReceiptHash { - return fmt.Errorf("invalid receipt root hash (remote: %x local: %x)", header.ReceiptHash, receiptSha) + return fmt.Errorf("%w (remote: %x local: %x)", ErrReceiptRootMismatch, header.ReceiptHash, receiptSha) } // Validate the parsed requests match the expected header value. if header.RequestsHash != nil { reqhash := types.CalcRequestsHash(res.Requests) if reqhash != *header.RequestsHash { - return fmt.Errorf("invalid requests hash (remote: %x local: %x)", *header.RequestsHash, reqhash) + return fmt.Errorf("%w (remote: %x local: %x)", ErrRequestsHashMismatch, *header.RequestsHash, reqhash) } } else if res.Requests != nil { return errors.New("block has requests before prague fork") diff --git a/core/blockchain.go b/core/blockchain.go index c161f0e577..df7cd69f0e 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -113,6 +113,11 @@ var ( blockExecutionParallelTimer = metrics.NewRegisteredTimer("chain/execution/parallel/timer", nil) blockExecutionSerialTimer = metrics.NewRegisteredTimer("chain/execution/serial/timer", nil) + statelessParallelImportTimer = metrics.NewRegisteredTimer("chain/imports/stateless/parallel", nil) + statelessSequentialImportTimer = metrics.NewRegisteredTimer("chain/imports/stateless/sequential", nil) + statelessParallelImportBlocksCounter = metrics.NewRegisteredCounter("chain/imports/stateless/parallel/blocks", nil) + statelessSequentialImportBlocksCounter = metrics.NewRegisteredCounter("chain/imports/stateless/sequential/blocks", nil) + blockReorgMeter = metrics.NewRegisteredMeter("chain/reorg/executes", nil) blockReorgAddMeter = metrics.NewRegisteredMeter("chain/reorg/add", nil) blockReorgDropMeter = metrics.NewRegisteredMeter("chain/reorg/drop", nil) @@ -360,15 +365,17 @@ type BlockChain struct { stopping atomic.Bool // false if chain is running, true when stopped procInterrupt atomic.Bool // interrupt signaler for block processing - engine consensus.Engine - validator Validator // Block and state validator interface - prefetcher Prefetcher - processor Processor // Block transaction processor interface - parallelProcessor Processor // Parallel block transaction processor interface - parallelSpeculativeProcesses int // Number of parallel speculative processes - enforceParallelProcessor bool - forker *ForkChoice - logger *tracing.Hooks + engine consensus.Engine + validator Validator // Block and state validator interface + prefetcher Prefetcher + processor Processor // Block transaction processor interface + parallelProcessor Processor // Parallel block transaction processor interface + parallelSpeculativeProcesses int // Number of parallel speculative processes + enforceParallelProcessor bool + parallelStatelessImportEnabled atomic.Bool // Whether parallel stateless import is enabled via config + parallelStatelessImportWorkers int // Number of workers to use for parallel stateless import + forker *ForkChoice + logger *tracing.Hooks // Bor related changes borReceiptsCache *lru.Cache[common.Hash, *types.Receipt] // Cache for the most recent bor receipt receipts per block @@ -619,6 +626,23 @@ func NewBlockChain(db ethdb.Database, genesis *Genesis, engine consensus.Engine, return bc, nil } +// ParallelStatelessImportEnable enables parallel stateless import. +func (bc *BlockChain) ParallelStatelessImportEnable() { + bc.parallelStatelessImportEnabled.Store(true) +} + +// SetParallelStatelessImportWorkers sets the number of workers used by parallel stateless import. +func (bc *BlockChain) SetParallelStatelessImportWorkers(n int) { + if n > 0 { + bc.parallelStatelessImportWorkers = n + } +} + +// IsParallelStatelessImportEnabled returns true if parallel stateless import is currently enabled. +func (bc *BlockChain) IsParallelStatelessImportEnabled() bool { + return bc.parallelStatelessImportEnabled.Load() +} + // NewParallelBlockChain , similar to NewBlockChain, creates a new blockchain object, but with a parallel state processor func NewParallelBlockChain(db ethdb.Database, genesis *Genesis, engine consensus.Engine, cfg *BlockChainConfig, numprocs int, enforce bool) (*BlockChain, error) { bc, err := NewBlockChain(db, genesis, engine, cfg) @@ -2427,18 +2451,8 @@ func (bc *BlockChain) InsertChainWithWitnesses(chain types.Blocks, makeWitness b return n, err } -func (bc *BlockChain) InsertChainStateless(chain types.Blocks, witnesses []*stateless.Witness) (int, error) { - // Sanity check that we have something meaningful to import - if len(chain) == 0 { - return 0, nil - } - - bc.blockProcFeed.Send(true) - defer bc.blockProcFeed.Send(false) - - stats := insertStats{startTime: mclock.Now()} - - // Do a sanity check that the provided chain is actually ordered and linked. +// verifyContiguousBlocks checks that the provided blocks are ordered and linked. +func verifyContiguousBlocks(chain types.Blocks) error { for i := 1; i < len(chain); i++ { block, prev := chain[i], chain[i-1] if block.NumberU64() != prev.NumberU64()+1 || block.ParentHash() != prev.Hash() { @@ -2449,11 +2463,268 @@ func (bc *BlockChain) InsertChainStateless(chain types.Blocks, witnesses []*stat "prevnumber", prev.Number(), "prevhash", prev.Hash(), ) - - return 0, fmt.Errorf("non contiguous insert: item %d is #%d [%x..], item %d is #%d [%x..] (parent [%x..])", i-1, prev.NumberU64(), + return fmt.Errorf("non contiguous insert: item %d is #%d [%x..], item %d is #%d [%x..] (parent [%x..])", i-1, prev.NumberU64(), prev.Hash().Bytes()[:4], i, block.NumberU64(), block.Hash().Bytes()[:4], block.ParentHash().Bytes()[:4]) } } + return nil +} + +// prepareHeaderVerification starts the parallel header verifier and returns a stopper and per-header error channels. +func (bc *BlockChain) prepareHeaderVerification(headers []*types.Header) (stop func(), errChans []chan error) { + abort, results := bc.engine.VerifyHeaders(bc, headers) + var abortOnce sync.Once + stop = func() { abortOnce.Do(func() { close(abort) }) } + + errChans = make([]chan error, len(headers)) + for i := range errChans { + errChans[i] = make(chan error, 1) + } + go func() { + for i := 0; i < len(headers); i++ { + err := <-results + errChans[i] <- err + } + for i := range errChans { + close(errChans[i]) + } + }() + return stop, errChans +} + +func (bc *BlockChain) handleHeaderVerificationError(block *types.Block, index int, hErr error) error { + if hErr == consensus.ErrUnknownAncestor { + parentNum := block.NumberU64() - 1 + existingBlock := bc.GetBlockByNumber(parentNum) + if existingBlock != nil && existingBlock.Hash() != block.ParentHash() { + log.Info("Conflicting block detected in stateless sync", + "blockNum", block.NumberU64(), + "parentNum", parentNum, + "existingParent", existingBlock.Hash(), + "expectedParent", block.ParentHash()) + existingHeader := existingBlock.Header() + verifyErr := bc.engine.VerifyHeader(bc, existingHeader) + if verifyErr == nil { + log.Info("Existing parent block is valid, rejecting new fork", + "existingParent", existingBlock.Hash(), + "rejectedParent", block.ParentHash()) + return fmt.Errorf("rejecting block %d: existing parent %s is valid", block.NumberU64(), existingBlock.Hash()) + } + log.Info("Existing parent block is invalid, accepting reorg", + "existingParent", existingBlock.Hash(), + "newParent", block.ParentHash(), + "verifyErr", verifyErr) + if err := bc.SetHead(parentNum - 1); err != nil { + return fmt.Errorf("failed to rewind for reorg: %w", err) + } + return fmt.Errorf("reorg detected, rewound to block %d", parentNum-1) + } + if index != 0 { + return hErr + } + return nil + } + return hErr +} + +// parallelStatelessImport processes a batch of blocks in parallel in stateless mode. +func (bc *BlockChain) insertChainStatelessParallel(chain types.Blocks, witnesses []*stateless.Witness, errChans []chan error, stats *insertStats, stopHeaders func()) (int, error) { + log.Debug("Performing parallel stateless import", "chain length", len(chain)) + start := time.Now() + defer func() { statelessParallelImportTimer.UpdateSince(start) }() + statelessParallelImportBlocksCounter.Inc(int64(len(chain))) + + // Parallel stateless execution with a worker pool + type execResult struct { + sdb *state.StateDB + err error + needsRetry bool + gasUsed uint64 + } + results := make([]execResult, len(chain)) + defer func() { + for i := range results { + if results[i].sdb != nil { + results[i].sdb = nil + } + } + }() + + workCh := make(chan int, len(chain)) + var snapDiffItems, snapBufItems common.StorageSize + var wg sync.WaitGroup + numWorkers := runtime.GOMAXPROCS(0) + if bc.parallelStatelessImportEnabled.Load() && bc.parallelStatelessImportWorkers > 0 { + numWorkers = bc.parallelStatelessImportWorkers + } + + for w := 0; w < numWorkers; w++ { + wg.Add(1) + go func() { + defer wg.Done() + for idx := range workCh { + blk := chain[idx] + // Known block: skip execution + if bc.HasBlock(blk.Hash(), blk.NumberU64()) { + continue + } + if bc.insertStopped() { + results[idx].err = errInsertionInterrupted + continue + } + var witness *stateless.Witness + if idx < len(witnesses) { + witness = witnesses[idx] + } + sdb, res, perr := bc.ProcessBlockWithWitnesses(blk, witness) + if perr != nil { + sdb = nil + // Defer execution errors to the sequential writer for retry + log.Info("Deferring execution retry to writer stage", "block", blk.NumberU64(), "hash", blk.Hash(), "err", perr) + results[idx].needsRetry = true + continue + } + + // If StateDB captured a database error during execution, defer to writer + if sdb != nil && sdb.Error() != nil { + err := sdb.Error() + log.Info("Deferring due to StateDB error", "block", blk.NumberU64(), "hash", blk.Hash(), "err", err) + sdb = nil + results[idx].needsRetry = true + continue + } + if witness != nil { + sdb.SetWitness(witness) + } + results[idx].sdb = sdb + results[idx].gasUsed = res.GasUsed + } + }() + } + + for i := range chain { + workCh <- i + } + close(workCh) + wg.Wait() + + // Sequentially verify headers and write blocks + var processed atomic.Int32 + for i, block := range chain { + if bc.HasBlock(block.Hash(), block.NumberU64()) { + processed.Add(1) + log.Trace("Skipping known block in InsertChainStateless", "number", block.NumberU64(), "hash", block.Hash()) + if i < len(errChans) { + if err := <-errChans[i]; err != nil { + stopHeaders() + return int(processed.Load() - 1), fmt.Errorf("header verification failed for known block %d (%s): %w", block.NumberU64(), block.Hash(), err) + } + } + stats.processed = int(processed.Load()) + stats.usedGas += block.GasUsed() + + if bc.snaps != nil { + snapDiffItems, snapBufItems = bc.snaps.Size() + } + trieDiffNodes, trieBufNodes, _ := bc.triedb.Size() + stats.report(chain, i, snapDiffItems, snapBufItems, trieDiffNodes, trieBufNodes, true, true) + continue + } + + if resErr := results[i].err; resErr != nil { + stopHeaders() + return int(processed.Load()), resErr + } + + var hErr error + if i < len(errChans) { + hErr = <-errChans[i] + } + if hErr != nil { + if err := bc.handleHeaderVerificationError(block, i, hErr); err != nil { + stopHeaders() + return int(processed.Load()), err + } + } + + // Validate witness pre-state for this block (if present) before writing + if i < len(witnesses) && witnesses[i] != nil { + var headerReader stateless.HeaderReader = bc + if witnesses[i].HeaderReader() != nil { + headerReader = witnesses[i].HeaderReader() + } + if err := stateless.ValidateWitnessPreState(witnesses[i], headerReader); err != nil { + stopHeaders() + return int(processed.Load()), fmt.Errorf("post-import witness validation failed for block %d: %w", block.NumberU64(), err) + } + } + + // Only commit blocks that don't need retry + if !results[i].needsRetry { + if _, werr := bc.writeBlockAndSetHead(block, nil, nil, results[i].sdb, false, true); werr != nil { + stopHeaders() + return int(processed.Load()), werr + } + results[i].sdb = nil + } else { + // Handle deferred retry for validation errors + log.Info("Retrying deferred validation", "block", block.NumberU64(), "hash", block.Hash()) + var witness *stateless.Witness + if i < len(witnesses) { + witness = witnesses[i] + } + sdb, res, perr := bc.ProcessBlockWithWitnesses(block, witness) + if perr != nil { + log.Error("Deferred validation failed", "block", block.NumberU64(), "hash", block.Hash(), "err", perr) + stopHeaders() + return int(processed.Load()), perr + } + if sdb != nil && sdb.Error() != nil { + retryErr := sdb.Error() + log.Error("Deferred validation captured StateDB error", "block", block.NumberU64(), "hash", block.Hash(), "err", retryErr) + stopHeaders() + return int(processed.Load()), retryErr + } + if witness != nil { + sdb.SetWitness(witness) + } + results[i].gasUsed = res.GasUsed + + // Commit the block after successful retry + if _, werr := bc.writeBlockAndSetHead(block, nil, nil, sdb, false, true); werr != nil { + stopHeaders() + return int(processed.Load()), werr + } + } + + processed.Add(1) + stats.processed = int(processed.Load()) + stats.usedGas += results[i].gasUsed + if bc.snaps != nil { + snapDiffItems, snapBufItems = bc.snaps.Size() + } + trieDiffNodes, trieBufNodes, _ := bc.triedb.Size() + stats.report(chain, i, snapDiffItems, snapBufItems, trieDiffNodes, trieBufNodes, true, true) + } + + return int(processed.Load()), nil +} + +func (bc *BlockChain) InsertChainStateless(chain types.Blocks, witnesses []*stateless.Witness) (int, error) { + // Sanity check that we have something meaningful to import + if len(chain) == 0 { + return 0, nil + } + + bc.blockProcFeed.Send(true) + defer bc.blockProcFeed.Send(false) + + stats := insertStats{startTime: mclock.Now()} + + // Ensure blocks are ordered and linked + if err := verifyContiguousBlocks(chain); err != nil { + return 0, err + } // Pre-checks passed, start the full block imports if !bc.chainmu.TryLock() { @@ -2461,131 +2732,97 @@ func (bc *BlockChain) InsertChainStateless(chain types.Blocks, witnesses []*stat } defer bc.chainmu.Unlock() - // Start the parallel header verifier + // Prepare headers slice headers := make([]*types.Header, len(chain)) for i, block := range chain { headers[i] = block.Header() } - abort, results := bc.engine.VerifyHeaders(bc, headers) - defer close(abort) + + // Start header verification + stopHeaders, errChans := bc.prepareHeaderVerification(headers) + defer stopHeaders() // Check the validity of incoming chain isValid, err := bc.forker.ValidateReorg(bc.CurrentBlock(), headers) if err != nil { return 0, err } - if !isValid { - // The chain to be imported is invalid as the blocks doesn't match with - // the whitelisted block number. return 0, whitelist.ErrMismatch } - // In stateless mode, we process blocks one by one without committing the state - var processed int - for i, block := range chain { - // Check if block is already known before attempting to process + if !bc.parallelStatelessImportEnabled.Load() { + return bc.insertChainStatelessSequential(chain, witnesses, errChans, &stats) + } + + return bc.insertChainStatelessParallel(chain, witnesses, errChans, &stats, stopHeaders) +} +// insertChainStatelessSequential imports a small batch of blocks sequentially in stateless mode. +func (bc *BlockChain) insertChainStatelessSequential(chain types.Blocks, witnesses []*stateless.Witness, errChans []chan error, stats *insertStats) (int, error) { + log.Debug("Performing sequential stateless import", "chain length", len(chain)) + start := time.Now() + defer func() { statelessSequentialImportTimer.UpdateSince(start) }() + statelessSequentialImportBlocksCounter.Inc(int64(len(chain))) + var processed atomic.Int32 + for i, block := range chain { + // Known block short-circuit if bc.HasBlock(block.Hash(), block.NumberU64()) { + processed.Add(1) log.Trace("Skipping known block in InsertChainStateless", "number", block.NumberU64(), "hash", block.Hash()) - processed++ // Count as processed since we're skipping it - // We need to ensure the header verification result for this block is consumed - // even though we are skipping the processing. - if err := <-results; err != nil { + if err := <-errChans[i]; err != nil { // If header verification failed for this known block (shouldn't happen often), // it might indicate a deeper issue, but we can't proceed with the chain. log.Warn("Header verification failed for known block", "number", block.NumberU64(), "hash", block.Hash(), "err", err) - return processed - 1, fmt.Errorf("header verification failed for known block %d (%s): %w", block.NumberU64(), block.Hash(), err) + return int(processed.Load() - 1), fmt.Errorf("header verification failed for known block %d (%s): %w", block.NumberU64(), block.Hash(), err) } - continue // Skip to the next block + continue } - // If the chain is terminating, don't even bother starting up. if bc.insertStopped() { - return processed, errInsertionInterrupted - } - - // Wait for the block's verification to complete - if err := <-results; err != nil { - if err == consensus.ErrUnknownAncestor { - // For stateless nodes, check if this is a reorg situation - parentNum := block.NumberU64() - 1 - existingBlock := bc.GetBlockByNumber(parentNum) - - if existingBlock != nil && existingBlock.Hash() != block.ParentHash() { - // We have a different block at the parent's height - this could be a reorg - log.Info("Conflicting block detected in stateless sync", - "blockNum", block.NumberU64(), - "parentNum", parentNum, - "existingParent", existingBlock.Hash(), - "expectedParent", block.ParentHash()) - - // Verify the existing parent block to see if it's valid - // This helps avoid unnecessary rewinds if the existing block is correct - existingHeader := existingBlock.Header() - verifyErr := bc.engine.VerifyHeader(bc, existingHeader) - - // Check if the existing parent is valid - if verifyErr == nil { - // Existing parent is valid, so the new block is on a wrong fork - log.Info("Existing parent block is valid, rejecting new fork", - "existingParent", existingBlock.Hash(), - "rejectedParent", block.ParentHash()) - return processed, fmt.Errorf("rejecting block %d: existing parent %s is valid", - block.NumberU64(), existingBlock.Hash()) - } - - // Existing parent is invalid, we need to rewind and accept the new chain - log.Info("Existing parent block is invalid, accepting reorg", - "existingParent", existingBlock.Hash(), - "newParent", block.ParentHash(), - "verifyErr", verifyErr) - - // For stateless nodes, we need to rewind and let the sync continue - // This will cause the correct parent block to be fetched and imported - if err := bc.SetHead(parentNum - 1); err != nil { - return processed, fmt.Errorf("failed to rewind for reorg: %w", err) - } - - // Return to let the downloader retry with the correct chain - return processed, fmt.Errorf("reorg detected, rewound to block %d", parentNum-1) - } else if i != 0 { - // Not the first block and no reorg detected - return processed, err - } - // First block in batch or successful reorg handling - continue - } else { - return processed, err - } + return int(processed.Load()), errInsertionInterrupted } - - // Get the witness for this block if available var witness *stateless.Witness if i < len(witnesses) { witness = witnesses[i] } - - // Process the block using stateless execution - statedb, res, err := bc.ProcessBlockWithWitnesses(block, witness) - if err != nil { - return processed, err + statedb, res, perr := bc.ProcessBlockWithWitnesses(block, witness) + if perr != nil { + return int(processed.Load()), perr } - statedb.SetWitness(witness) - - // Write the block to the chain without committing state - if _, err := bc.writeBlockAndSetHead(block, res.Receipts, res.Logs, statedb, false, true); err != nil { - return processed, err + hErr := <-errChans[i] + if hErr != nil { + if err := bc.handleHeaderVerificationError(block, i, hErr); err != nil { + return int(processed.Load()), err + } } - processed++ - - stats.processed = processed + if _, werr := bc.writeBlockAndSetHead(block, nil, nil, statedb, false, true); werr != nil { + return int(processed.Load()), werr + } + processed.Add(1) + stats.processed = int(processed.Load()) stats.usedGas += res.GasUsed - - stats.report(chain, i, 0, 0, 0, 0, true, true) + var snapDiffItems, snapBufItems common.StorageSize + if bc.snaps != nil { + snapDiffItems, snapBufItems = bc.snaps.Size() + } + trieDiffNodes, trieBufNodes, _ := bc.triedb.Size() + stats.report(chain, i, snapDiffItems, snapBufItems, trieDiffNodes, trieBufNodes, true, true) } - - return processed, nil + // End-of-batch witness validation + for i, block := range chain { + if i < len(witnesses) && witnesses[i] != nil { + var headerReader stateless.HeaderReader = bc + if witnesses[i].HeaderReader() != nil { + headerReader = witnesses[i].HeaderReader() + } + if err := stateless.ValidateWitnessPreState(witnesses[i], headerReader); err != nil { + return int(processed.Load()), fmt.Errorf("post-import witness validation failed for block %d: %w", block.NumberU64(), err) + } + } + } + return int(processed.Load()), nil } // insertChain is the internal implementation of InsertChain, which assumes that @@ -2896,7 +3133,11 @@ func (bc *BlockChain) insertChainWithWitnesses(chain types.Blocks, setHead bool, if witnesses != nil && len(witnesses) > it.processed()-1 && witnesses[it.processed()-1] != nil { // 1. Validate the witness. - if err := stateless.ValidateWitnessPreState(witnesses[it.processed()-1], bc); err != nil { + var headerReader stateless.HeaderReader = bc + if witnesses[it.processed()-1].HeaderReader() != nil { + headerReader = witnesses[it.processed()-1].HeaderReader() + } + if err := stateless.ValidateWitnessPreState(witnesses[it.processed()-1], headerReader); err != nil { log.Error("Witness validation failed during chain insertion", "blockNumber", block.Number(), "blockHash", block.Hash(), "err", err) bc.reportBlock(block, &ProcessResult{}, err) followupInterrupt.Store(true) @@ -3905,9 +4146,18 @@ func (bc *BlockChain) ProcessBlockWithWitnesses(block *types.Block, witness *sta } // Validate witness. - if err := stateless.ValidateWitnessPreState(witness, bc); err != nil { - log.Error("Witness validation failed during stateless processing", "blockNumber", block.Number(), "blockHash", block.Hash(), "err", err) - return nil, nil, fmt.Errorf("witness validation failed: %w", err) + // During parallel import, defer pre-state validation to the end of the batch. + if !bc.parallelStatelessImportEnabled.Load() { + var headerReader stateless.HeaderReader + if witness.HeaderReader() != nil { + headerReader = witness.HeaderReader() + } else { + headerReader = bc + } + if err := stateless.ValidateWitnessPreState(witness, headerReader); err != nil { + log.Error("Witness validation failed during stateless processing", "blockNumber", block.Number(), "blockHash", block.Hash(), "err", err) + return nil, nil, fmt.Errorf("witness validation failed: %w", err) + } } // Remove critical computed fields from the block to force true recalculation @@ -3929,7 +4179,7 @@ func (bc *BlockChain) ProcessBlockWithWitnesses(block *types.Block, witness *sta } if crossStateRoot != block.Root() { log.Error("Stateless self-validation root mismatch", "block", block.Number(), "hash", block.Hash(), "cross", crossStateRoot, "local", block.Root()) - err = fmt.Errorf("stateless self-validation state root mismatch: remote %x != local %x", block.Root(), crossStateRoot) + err = fmt.Errorf("%w: remote %x != local %x", ErrStatelessStateRootMismatch, block.Root(), crossStateRoot) return nil, nil, err } if crossReceiptRoot != block.ReceiptHash() { diff --git a/core/blockchain_test.go b/core/blockchain_test.go index c89cb0b192..d04a419a15 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -33,11 +33,13 @@ import ( "github.com/davecgh/go-spew/spew" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/mclock" "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus/beacon" "github.com/ethereum/go-ethereum/consensus/ethash" "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/core/vm" "github.com/ethereum/go-ethereum/core/vm/program" @@ -4333,7 +4335,6 @@ func TestDeleteThenCreate(t *testing.T) { } */ factoryBIN := common.Hex2Bytes("608060405234801561001057600080fd5b50610241806100206000396000f3fe608060405234801561001057600080fd5b506004361061002a5760003560e01c80627743601461002f575b600080fd5b610049600480360381019061004491906100d8565b61004b565b005b6000808251602084016000f59050803b61006457600080fd5b5050565b600061007b61007684610146565b610121565b905082815260208101848484011115610097576100966101eb565b5b6100a2848285610177565b509392505050565b600082601f8301126100bf576100be6101e6565b5b81356100cf848260208601610068565b91505092915050565b6000602082840312156100ee576100ed6101f5565b5b600082013567ffffffffffffffff81111561010c5761010b6101f0565b5b610118848285016100aa565b91505092915050565b600061012b61013c565b90506101378282610186565b919050565b6000604051905090565b600067ffffffffffffffff821115610161576101606101b7565b5b61016a826101fa565b9050602081019050919050565b82818337600083830152505050565b61018f826101fa565b810181811067ffffffffffffffff821117156101ae576101ad6101b7565b5b80604052505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f830116905091905056fea2646970667358221220ea8b35ed310d03b6b3deef166941140b4d9e90ea2c92f6b41eb441daf49a59c364736f6c63430008070033") - /* contract C { uint256 value; @@ -5404,25 +5405,334 @@ func TestStatelessInsertChain(t *testing.T) { } defer chain.Stop() - // Test 1: Empty chain should return 0 without error - _, err = chain.InsertChainStateless(types.Blocks{}, nil) - if err != nil { - t.Fatalf("expected no error for empty chain, got: %v", err) + // Parallel path + _, blocksParallel, _ := GenerateChainWithGenesis(gspec, engine, 10, func(i int, b *BlockGen) { + b.SetCoinbase(common.Address{1}) + }) + + // Pre-insert canonically to avoid witness requirements and mark as known + if _, err := chain.InsertChain(blocksParallel, true); err != nil { + t.Fatalf("failed to pre-insert canonical blocks: %v", err) } - // Test 2: Verify the method exists and handles stateless mode correctly - // The actual stateless execution would require proper witnesses with state proofs, - // which is complex to set up in a unit test. This test verifies: - // - The InsertChainStateless method exists - // - It properly handles empty input - // - It's only available when Stateless = true (stateless mode) + witnessesParallel := make([]*stateless.Witness, len(blocksParallel)) + for i, b := range blocksParallel { + w, err := stateless.NewWitness(b.Header(), chain) + if err != nil { + t.Fatalf("failed to build witness for block %d: %v", b.NumberU64(), err) + } + witnessesParallel[i] = w + } + processed, err := chain.InsertChainStateless(blocksParallel, witnessesParallel) + if err != nil { + t.Fatalf("unexpected error on parallel stateless import: %v", err) + } + if processed != len(blocksParallel) { + t.Fatalf("expected processed=%d, got %d", len(blocksParallel), processed) + } // Verify we're in stateless mode (Stateless = true) if chain.cfg.Stateless != true { t.Error("Expected blockchain to be configured for stateless mode (Stateless = true)") } - t.Log("InsertChainStateless method exists and handles stateless mode configuration correctly") + // Sequential path + _, blocksSequential, _ := GenerateChainWithGenesis(gspec, engine, 5, func(i int, b *BlockGen) { + b.SetCoinbase(common.Address{1}) + }) + + // Pre-insert canonically to avoid witness requirements and mark as known + if _, err := chain.InsertChain(blocksSequential, true); err != nil { + t.Fatalf("failed to pre-insert canonical blocks: %v", err) + } + + // Now import via InsertChainStateless and expect clean happy path in sequential + witnessesSequential := make([]*stateless.Witness, len(blocksSequential)) + for i, b := range blocksSequential { + w, err := stateless.NewWitness(b.Header(), chain) + if err != nil { + t.Fatalf("failed to build witness for block %d: %v", b.NumberU64(), err) + } + witnessesSequential[i] = w + } + processed, err = chain.InsertChainStateless(blocksSequential, witnessesSequential) + if err != nil { + t.Fatalf("unexpected error on sequential stateless import: %v", err) + } + if processed != len(blocksSequential) { + t.Fatalf("expected processed=%d, got %d", len(blocksSequential), processed) + } +} + +// corruptWitnessState corrupts witness by completely replacing all state with invalid data +func corruptWitnessState(witness *stateless.Witness) *stateless.Witness { + corrupted := witness.Copy() + + // Completely replace all state with obviously invalid data + // This will cause failures when any state access is attempted + corrupted.State = map[string]struct{}{ + "invalid_state_node_1": {}, + "invalid_state_node_2": {}, + "corrupted_data_here": {}, + } + + return corrupted +} + +// corruptWitnessHeaders corrupts witness headers with wrong state root +func corruptWitnessHeaders(witness *stateless.Witness) *stateless.Witness { + corrupted := witness.Copy() + if len(corrupted.Headers) > 0 { + wrongHeader := types.CopyHeader(corrupted.Headers[0]) + wrongHeader.Root = common.HexToHash("0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef") // Incorrect state root + corrupted.Headers[0] = wrongHeader + } + return corrupted +} + +// clearWitnessState removes all state data from witness +func clearWitnessState(witness *stateless.Witness) *stateless.Witness { + cleared := witness.Copy() + cleared.State = make(map[string]struct{}) + return cleared +} + +// createEmptyHeaderWitness creates a witness with empty headers +func createEmptyHeaderWitness(header *types.Header) *stateless.Witness { + witness := &stateless.Witness{ + Headers: []*types.Header{}, // Empty headers + Codes: make(map[string]struct{}), + State: make(map[string]struct{}), + } + witness.SetHeader(header) + return witness +} + +// createTestBlockAndWitness creates a fresh block and witness for testing +func createTestBlockAndWitness(t *testing.T) (*BlockChain, *types.Block, *stateless.Witness) { + t.Helper() + + key, _ := crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + addr := crypto.PubkeyToAddress(key.PublicKey) + gspec := &Genesis{ + Config: params.TestChainConfig, + Alloc: types.GenesisAlloc{addr: {Balance: big.NewInt(10000000000000000)}}, + } + + cfg := DefaultConfig() + cfg.Stateless = true + + // Create stateful chain for witness generation + engine := ethash.NewFaker() + stateFullChain, err := NewBlockChain(rawdb.NewMemoryDatabase(), gspec, engine, cfg) + if err != nil { + t.Fatalf("failed to create full-state chain: %v", err) + } + defer stateFullChain.Stop() + + // Generate block with transaction + _, blocks, _ := GenerateChainWithGenesis(gspec, engine, 1, func(i int, b *BlockGen) { + b.SetCoinbase(common.Address{1}) + // Use transaction nonce 0 since each test uses a fresh account state + tx, _ := types.SignTx(types.NewTransaction(0, common.HexToAddress("0x1234"), big.NewInt(1000), 21000, big.NewInt(2000000000), nil), types.HomesteadSigner{}, key) + b.AddTx(tx) + }) + block := blocks[0] + + // Generate witness + witness, _, err := stateFullChain.insertChain(types.Blocks{block}, true, true) + if err != nil { + t.Fatalf("failed to build witness: %v", err) + } + + // Create fresh stateless chain + statelessChain, err := NewBlockChain(rawdb.NewMemoryDatabase(), gspec, ethash.NewFaker(), cfg) + if err != nil { + t.Fatalf("failed to create stateless chain: %v", err) + } + + return statelessChain, block, witness +} + +// TestParallelStateless_ContractDeployedThenCalled ensures that a contract +// deployed and later accessed imports correctly +// in parallel stateless mode. +func TestParallelStateless_ContractDeployedThenCalled(t *testing.T) { + key, _ := crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + addr := crypto.PubkeyToAddress(key.PublicKey) + gspec := &Genesis{ + Config: params.TestChainConfig, + Alloc: types.GenesisAlloc{addr: {Balance: big.NewInt(10000000000000000)}}, + } + + cfg := DefaultConfig() + cfg.Stateless = true + + eng := ethash.NewFaker() + + // Build a 3-block chain: B1 deploy contract, B2 noop, B3 call contract + var contractAddr common.Address + _, blocks, _ := GenerateChainWithGenesis(gspec, eng, 3, func(i int, b *BlockGen) { + b.SetCoinbase(common.Address{1}) + if i == 0 { + code := []byte{0x60, 0x00, 0x56} + tx, _ := types.SignTx( + types.NewContractCreation(0, big.NewInt(0), 150000, b.header.BaseFee, code), + types.HomesteadSigner{}, key, + ) + b.AddTx(tx) + contractAddr = crypto.CreateAddress(addr, 0) + } + if i == 2 { + // Call the deployed contract in block 3 + callData := []byte{} + tx, _ := types.SignTx( + types.NewTransaction(1, contractAddr, big.NewInt(0), 100000, big.NewInt(2_000_000_000), callData), + types.HomesteadSigner{}, key, + ) + b.AddTx(tx) + } + }) + + // Create stateful chain for witness generation + stateFullChain, err := NewBlockChain(rawdb.NewMemoryDatabase(), gspec, eng, cfg) + require.NoError(t, err) + defer stateFullChain.Stop() + + // Build witnesses by inserting each block on the full chain (stateful) + w1, _, err := stateFullChain.insertChain(types.Blocks{blocks[0]}, true, true) + require.NoError(t, err) + require.NotNil(t, w1) + + w2, _, err := stateFullChain.insertChain(types.Blocks{blocks[1]}, true, true) + require.NoError(t, err) + require.NotNil(t, w2) + + w3, _, err := stateFullChain.insertChain(types.Blocks{blocks[2]}, true, true) + require.NoError(t, err) + require.NotNil(t, w3) + + // Corrupt the third witness by dropping code to simulate missing bytecode in worker + badW3 := w3.Copy() + badW3.Codes = make(map[string]struct{}) + + // Create stateless chain for parallel insertion + statelessChain, err := NewBlockChain(rawdb.NewMemoryDatabase(), gspec, ethash.NewFaker(), cfg) + require.NoError(t, err) + defer statelessChain.Stop() + + headers := []*types.Header{blocks[0].Header(), blocks[1].Header(), blocks[2].Header()} + stopHeaders, errChans := statelessChain.prepareHeaderVerification(headers) + defer stopHeaders() + + stats := &insertStats{startTime: mclock.Now()} + processed, err := statelessChain.insertChainStatelessParallel(types.Blocks{blocks[0], blocks[1], blocks[2]}, []*stateless.Witness{w1, w2, badW3}, errChans, stats, stopHeaders) + + require.NoError(t, err) + require.Equal(t, 3, processed) +} + +// TestStatelessInsertChainInvalidInputs tests invalid or edge inputs for sequential and parallel stateless insertions +func TestStatelessInsertChainInvalidInputs(t *testing.T) { + adversarialTests := []struct { + name string + setupFn func(t *testing.T) (*BlockChain, []*types.Block, []*stateless.Witness) + wantErr bool + }{ + { + name: "empty chain insertion", + setupFn: func(t *testing.T) (*BlockChain, []*types.Block, []*stateless.Witness) { + chain, _, _ := createTestBlockAndWitness(t) + return chain, []*types.Block{}, []*stateless.Witness{} + }, + wantErr: false, + }, + { + name: "explicit nil witness", + setupFn: func(t *testing.T) (*BlockChain, []*types.Block, []*stateless.Witness) { + chain, block, _ := createTestBlockAndWitness(t) + return chain, []*types.Block{block}, []*stateless.Witness{nil} + }, + wantErr: true, + }, + { + name: "corrupted witness state data", + setupFn: func(t *testing.T) (*BlockChain, []*types.Block, []*stateless.Witness) { + chain, block, witness := createTestBlockAndWitness(t) + corruptedWitness := corruptWitnessState(witness) + return chain, []*types.Block{block}, []*stateless.Witness{corruptedWitness} + }, + wantErr: true, + }, + { + name: "witness missing required trie nodes", + setupFn: func(t *testing.T) (*BlockChain, []*types.Block, []*stateless.Witness) { + chain, block, witness := createTestBlockAndWitness(t) + clearedWitness := clearWitnessState(witness) + return chain, []*types.Block{block}, []*stateless.Witness{clearedWitness} + }, + wantErr: true, + }, + { + name: "witness with incorrect state root in headers", + setupFn: func(t *testing.T) (*BlockChain, []*types.Block, []*stateless.Witness) { + chain, block, witness := createTestBlockAndWitness(t) + corruptedWitness := corruptWitnessHeaders(witness) + return chain, []*types.Block{block}, []*stateless.Witness{corruptedWitness} + }, + wantErr: true, + }, + { + name: "witness with empty headers", + setupFn: func(t *testing.T) (*BlockChain, []*types.Block, []*stateless.Witness) { + chain, block, _ := createTestBlockAndWitness(t) + emptyHeaderWitness := createEmptyHeaderWitness(block.Header()) + return chain, []*types.Block{block}, []*stateless.Witness{emptyHeaderWitness} + }, + wantErr: true, + }, + } + + for _, tt := range adversarialTests { + t.Run(tt.name, func(t *testing.T) { + testInsertMethod := func(t *testing.T, methodName string, isParallel bool) { + chain, blocks, witnesses := tt.setupFn(t) + defer chain.Stop() + + headers := make([]*types.Header, len(blocks)) + for i, block := range blocks { + headers[i] = block.Header() + } + + stats := &insertStats{startTime: mclock.Now()} + + var err error + if isParallel { + stopHeaders, errChans := chain.prepareHeaderVerification(headers) + defer stopHeaders() + _, err = chain.insertChainStatelessParallel(blocks, witnesses, errChans, stats, stopHeaders) + } else { + _, errChans := chain.prepareHeaderVerification(headers) + _, err = chain.insertChainStatelessSequential(blocks, witnesses, errChans, stats) + } + + if tt.wantErr { + require.Error(t, err, methodName+" expected error but got none") + t.Logf("%s got expected error: %v", methodName, err) + } else { + require.NoError(t, err, methodName+" unexpected error") + } + } + + t.Run("sequential", func(t *testing.T) { + testInsertMethod(t, "insertChainStatelessSequential", false) + }) + + t.Run("parallel", func(t *testing.T) { + testInsertMethod(t, "insertChainStatelessParallel", true) + }) + }) + } } // TestStatelessSetHeadBeyondRoot tests setHeadBeyondRoot in stateless mode diff --git a/core/error.go b/core/error.go index 4aee98d27b..d58f534208 100644 --- a/core/error.go +++ b/core/error.go @@ -33,6 +33,27 @@ var ( ErrNoGenesis = errors.New("genesis not found in chain") errSideChainReceipts = errors.New("side blocks can't be accepted as ancient chain data") + + // ErrStatelessStateRootMismatch indicates a mismatch between locally computed + // state root and the cross-validated (remote) state root during stateless + // self-validation. + ErrStatelessStateRootMismatch = errors.New("stateless self-validation state root mismatch") + + // ErrGasUsedMismatch indicates a mismatch between locally computed + // gas used and the block's gas used during validation. + ErrGasUsedMismatch = errors.New("invalid gas used") + + // ErrBloomMismatch indicates a mismatch between locally computed + // bloom filter and the block's bloom during validation. + ErrBloomMismatch = errors.New("invalid bloom") + + // ErrReceiptRootMismatch indicates a mismatch between locally computed + // receipt root and the block's receipt root during validation. + ErrReceiptRootMismatch = errors.New("invalid receipt root hash") + + // ErrRequestsHashMismatch indicates a mismatch between locally computed + // requests hash and the block's requests hash during validation. + ErrRequestsHashMismatch = errors.New("invalid requests hash") ) // List of evm-call-message pre-checking errors. All state transition messages will diff --git a/core/stateless/test_utils.go b/core/stateless/test_utils.go new file mode 100644 index 0000000000..e90d6eb63b --- /dev/null +++ b/core/stateless/test_utils.go @@ -0,0 +1,25 @@ +package stateless + +import ( + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" +) + +// MockHeaderReader is a mock implementation of HeaderReader for testing. +type MockHeaderReader struct { + headers map[common.Hash]*types.Header +} + +func (m *MockHeaderReader) GetHeader(hash common.Hash, number uint64) *types.Header { + return m.headers[hash] +} + +func NewMockHeaderReader() *MockHeaderReader { + return &MockHeaderReader{ + headers: make(map[common.Hash]*types.Header), + } +} + +func (m *MockHeaderReader) AddHeader(header *types.Header) { + m.headers[header.Hash()] = header +} diff --git a/core/stateless/witness.go b/core/stateless/witness.go index 2f0cab8fae..e4b31fa2df 100644 --- a/core/stateless/witness.go +++ b/core/stateless/witness.go @@ -171,6 +171,13 @@ func (w *Witness) SetHeader(header *types.Header) { } } +func (w *Witness) HeaderReader() HeaderReader { + if w == nil { + return nil + } + return w.chain +} + // GetWitnessFromRlp decodes a witness from its RLP encoded form. func GetWitnessFromRlp(rlpEncodedWitness []byte) (*Witness, error) { var witness Witness diff --git a/core/stateless/witness_test.go b/core/stateless/witness_test.go index 8afafe2dec..e52f09f26f 100644 --- a/core/stateless/witness_test.go +++ b/core/stateless/witness_test.go @@ -8,25 +8,6 @@ import ( "github.com/ethereum/go-ethereum/core/types" ) -// MockHeaderReader is a mock implementation of HeaderReader for testing. -type mockHeaderReader struct { - headers map[common.Hash]*types.Header -} - -func (m *mockHeaderReader) GetHeader(hash common.Hash, number uint64) *types.Header { - return m.headers[hash] -} - -func newMockHeaderReader() *mockHeaderReader { - return &mockHeaderReader{ - headers: make(map[common.Hash]*types.Header), - } -} - -func (m *mockHeaderReader) addHeader(header *types.Header) { - m.headers[header.Hash()] = header -} - func TestValidateWitnessPreState_Success(t *testing.T) { // Create test headers. parentStateRoot := common.HexToHash("0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef") @@ -47,8 +28,8 @@ func TestValidateWitnessPreState_Success(t *testing.T) { } // Set up mock header reader. - mockReader := newMockHeaderReader() - mockReader.addHeader(parentHeader) + mockReader := NewMockHeaderReader() + mockReader.AddHeader(parentHeader) // Create witness with matching pre-state root. witness := &Witness{ @@ -93,8 +74,8 @@ func TestValidateWitnessPreState_StateMismatch(t *testing.T) { } // Set up mock header reader. - mockReader := newMockHeaderReader() - mockReader.addHeader(parentHeader) + mockReader := NewMockHeaderReader() + mockReader.AddHeader(parentHeader) // Create witness with mismatched pre-state root. witness := &Witness{ @@ -119,7 +100,7 @@ func TestValidateWitnessPreState_StateMismatch(t *testing.T) { } func TestValidateWitnessPreState_EdgeCases(t *testing.T) { - mockReader := newMockHeaderReader() + mockReader := NewMockHeaderReader() // Test case 1: Nil witness. t.Run("NilWitness", func(t *testing.T) { @@ -238,9 +219,9 @@ func TestValidateWitnessPreState_MultipleHeaders(t *testing.T) { } // Set up mock header reader. - mockReader := newMockHeaderReader() - mockReader.addHeader(parentHeader) - mockReader.addHeader(grandParentHeader) + mockReader := NewMockHeaderReader() + mockReader.AddHeader(parentHeader) + mockReader.AddHeader(grandParentHeader) // Create witness with multiple headers (parent should be first). witness := &Witness{ diff --git a/core/stateless_bench_test.go b/core/stateless_bench_test.go new file mode 100644 index 0000000000..b444c6cc31 --- /dev/null +++ b/core/stateless_bench_test.go @@ -0,0 +1,86 @@ +package core + +import ( + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/mclock" + "github.com/ethereum/go-ethereum/consensus/ethash" + "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/core/stateless" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/params" +) + +// prepareStatelessBenchmark sets up the stateless and full-state chains, generates blocks, +// constructs witnesses using full-state execution, and starts header verification. +func prepareStatelessBenchmark(b *testing.B) (stateLessChain *BlockChain, stateFullChain *BlockChain, blocks types.Blocks, witnesses []*stateless.Witness, stopHeaders func(), errChans []chan error) { + b.Helper() + + engine := ethash.NewFaker() + gspec := &Genesis{Config: params.TestChainConfig} + cfg := DefaultConfig() + cfg.Stateless = true + + stateLessChain, err := NewBlockChain(rawdb.NewMemoryDatabase(), gspec, engine, cfg) + if err != nil { + b.Fatalf("failed to create stateless chain: %v", err) + } + + stateFullChain, err = NewBlockChain(rawdb.NewMemoryDatabase(), gspec, engine, cfg) + if err != nil { + b.Fatalf("failed to create full-state chain: %v", err) + } + + _, blocks, _ = GenerateChainWithGenesis(gspec, engine, b.N, func(i int, b *BlockGen) { + b.SetCoinbase(common.Address{1}) + }) + + headers := make([]*types.Header, len(blocks)) + for i, blk := range blocks { + headers[i] = blk.Header() + } + + witnesses = make([]*stateless.Witness, len(blocks)) + for i, blk := range blocks { + var w *stateless.Witness + w, _, err = stateFullChain.insertChain(types.Blocks{blk}, true, true) + if err != nil { + b.Fatalf("failed to build witness via full-state insert: %v", err) + } + witnesses[i] = w + } + + stopHeaders, errChans = stateLessChain.prepareHeaderVerification(headers) + return +} + +func BenchmarkInsertChainStatelessSequential(b *testing.B) { + stateLessChain, stateFullChain, blocks, witnesses, stopHeaders, errChans := prepareStatelessBenchmark(b) + defer stateLessChain.Stop() + defer stateFullChain.Stop() + defer stopHeaders() + + b.ReportAllocs() + b.ResetTimer() + + _, err := stateLessChain.insertChainStatelessSequential(blocks, witnesses, errChans, &insertStats{startTime: mclock.Now()}) + if err != nil { + b.Fatalf("sequential stateless insert failed: %v", err) + } +} + +func BenchmarkInsertChainStatelessParallel(b *testing.B) { + stateLessChain, stateFullChain, blocks, witnesses, stopHeaders, errChans := prepareStatelessBenchmark(b) + defer stateLessChain.Stop() + defer stateFullChain.Stop() + defer stopHeaders() + + b.ReportAllocs() + b.ResetTimer() + + _, err := stateLessChain.insertChainStatelessParallel(blocks, witnesses, errChans, &insertStats{startTime: mclock.Now()}, stopHeaders) + if err != nil { + b.Fatalf("parallel stateless insert failed: %v", err) + } +} diff --git a/eth/api_backend.go b/eth/api_backend.go index f1db352274..8dfcc383ca 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -708,3 +708,7 @@ func (b *EthAPIBackend) WitnessByNumberOrHash(ctx context.Context, blockNrOrHash return nil, errors.New("invalid block number or hash") } + +func (b *EthAPIBackend) IsParallelImportActive() bool { + return b.eth.blockchain.IsParallelStatelessImportEnabled() +} diff --git a/eth/backend.go b/eth/backend.go index 24cdd8076c..27a5b644b9 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -307,6 +307,14 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { eth.blockchain, err = core.NewBlockChain(chainDb, config.Genesis, eth.engine, options) } + // Set parallel stateless import toggle on blockchain + if err == nil && eth.blockchain != nil && config.EnableParallelStatelessImport { + eth.blockchain.ParallelStatelessImportEnable() + if config.EnableParallelStatelessImportWorkers > 0 { + eth.blockchain.SetParallelStatelessImportWorkers(config.EnableParallelStatelessImportWorkers) + } + } + if err != nil { return nil, err } diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go index 17ddf77187..f5d8f8a2d7 100644 --- a/eth/ethconfig/config.go +++ b/eth/ethconfig/config.go @@ -235,6 +235,19 @@ type Config struct { // Minimum necessary distance between local header and peer to fast forward FastForwardThreshold uint64 + // Minimum necessary distance between local header and latest non pruned witness + WitnessPruneThreshold uint64 + + // The time interval between each witness prune routine + WitnessPruneInterval time.Duration + + // EnableParallelStatelessImport toggles parallel stateless block import (download path) + EnableParallelStatelessImport bool + + // EnableParallelStatelessImportWorkers sets the number of workers (CPUs) used for parallel stateless import. + // If 0, defaults to GOMAXPROCS. + EnableParallelStatelessImportWorkers int + // WitnessAPIEnabled enables witness API endpoints WitnessAPIEnabled bool diff --git a/eth/ethconfig/gen_config.go b/eth/ethconfig/gen_config.go index d2024dec47..5d14a338fe 100644 --- a/eth/ethconfig/gen_config.go +++ b/eth/ethconfig/gen_config.go @@ -19,63 +19,71 @@ import ( // MarshalTOML marshals as TOML. func (c Config) MarshalTOML() (interface{}, error) { type Config struct { - Genesis *core.Genesis `toml:",omitempty"` - NetworkId uint64 - SyncMode downloader.SyncMode - HistoryMode history.HistoryMode - EthDiscoveryURLs []string - SnapDiscoveryURLs []string - NoPruning bool - NoPrefetch bool - TxLookupLimit uint64 `toml:",omitempty"` - TransactionHistory uint64 `toml:",omitempty"` - LogHistory uint64 `toml:",omitempty"` - LogNoHistory bool `toml:",omitempty"` - LogExportCheckpoints string - StateHistory uint64 `toml:",omitempty"` - StateScheme string `toml:",omitempty"` - RequiredBlocks map[uint64]common.Hash `toml:"-"` - SkipBcVersionCheck bool `toml:"-"` - DatabaseHandles int `toml:"-"` - DatabaseCache int - DatabaseFreezer string - DatabaseEra string - TrieCleanCache int - TrieDirtyCache int - TrieTimeout time.Duration - SnapshotCache int - Preimages bool - TriesInMemory uint64 - FilterLogCacheSize int - Miner miner.Config - TxPool legacypool.Config - BlobPool blobpool.Config - GPO gasprice.Config - EnablePreimageRecording bool - VMTrace string - VMTraceJsonConfig string - RPCGasCap uint64 - RPCReturnDataLimit uint64 - RPCEVMTimeout time.Duration - RPCTxFeeCap float64 - OverrideOsaka *big.Int `toml:",omitempty"` - HeimdallURL string - HeimdallTimeout time.Duration - WithoutHeimdall bool - HeimdallgRPCAddress string - HeimdallWSAddress string - RunHeimdall bool - RunHeimdallArgs string - UseHeimdallApp bool - BorLogs bool - ParallelEVM core.ParallelEVMConfig `toml:",omitempty"` - WitnessProtocol bool - SyncWithWitnesses bool - SyncAndProduceWitnesses bool - DevFakeAuthor bool `hcl:"devfakeauthor,optional" toml:"devfakeauthor,optional"` - OverrideVerkle *big.Int `toml:",omitempty"` - EnableBlockTracking bool - FastForwardThreshold uint64 + Genesis *core.Genesis `toml:",omitempty"` + NetworkId uint64 + SyncMode downloader.SyncMode + HistoryMode history.HistoryMode + EthDiscoveryURLs []string + SnapDiscoveryURLs []string + NoPruning bool + NoPrefetch bool + TxLookupLimit uint64 `toml:",omitempty"` + TransactionHistory uint64 `toml:",omitempty"` + LogHistory uint64 `toml:",omitempty"` + LogNoHistory bool `toml:",omitempty"` + LogExportCheckpoints string + StateHistory uint64 `toml:",omitempty"` + StateScheme string `toml:",omitempty"` + RequiredBlocks map[uint64]common.Hash `toml:"-"` + SkipBcVersionCheck bool `toml:"-"` + DatabaseHandles int `toml:"-"` + DatabaseCache int + DatabaseFreezer string + DatabaseEra string + LevelDbCompactionTableSize uint64 + LevelDbCompactionTableSizeMultiplier float64 + LevelDbCompactionTotalSize uint64 + LevelDbCompactionTotalSizeMultiplier float64 + TrieCleanCache int + TrieDirtyCache int + TrieTimeout time.Duration + SnapshotCache int + Preimages bool + TriesInMemory uint64 + FilterLogCacheSize int + Miner miner.Config + TxPool legacypool.Config + BlobPool blobpool.Config + GPO gasprice.Config + EnablePreimageRecording bool + VMTrace string + VMTraceJsonConfig string + RPCGasCap uint64 + RPCReturnDataLimit uint64 + RPCEVMTimeout time.Duration + RPCTxFeeCap float64 + OverrideOsaka *big.Int `toml:",omitempty"` + HeimdallURL string + HeimdallTimeout time.Duration + WithoutHeimdall bool + HeimdallgRPCAddress string + HeimdallWSAddress string + RunHeimdall bool + RunHeimdallArgs string + UseHeimdallApp bool + BorLogs bool + ParallelEVM core.ParallelEVMConfig `toml:",omitempty"` + WitnessProtocol bool + SyncWithWitnesses bool + SyncAndProduceWitnesses bool + DevFakeAuthor bool `hcl:"devfakeauthor,optional" toml:"devfakeauthor,optional"` + OverrideVerkle *big.Int `toml:",omitempty"` + EnableBlockTracking bool + FastForwardThreshold uint64 + WitnessPruneThreshold uint64 + WitnessPruneInterval time.Duration + EnableParallelStatelessImport bool + EnableParallelStatelessImportWorkers int } var enc Config enc.Genesis = c.Genesis @@ -135,69 +143,81 @@ func (c Config) MarshalTOML() (interface{}, error) { enc.OverrideVerkle = c.OverrideVerkle enc.EnableBlockTracking = c.EnableBlockTracking enc.FastForwardThreshold = c.FastForwardThreshold + enc.WitnessPruneThreshold = c.WitnessPruneThreshold + enc.WitnessPruneInterval = c.WitnessPruneInterval + enc.EnableParallelStatelessImport = c.EnableParallelStatelessImport + enc.EnableParallelStatelessImportWorkers = c.EnableParallelStatelessImportWorkers return &enc, nil } // UnmarshalTOML unmarshals from TOML. func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { type Config struct { - Genesis *core.Genesis `toml:",omitempty"` - NetworkId *uint64 - SyncMode *downloader.SyncMode - HistoryMode *history.HistoryMode - EthDiscoveryURLs []string - SnapDiscoveryURLs []string - NoPruning *bool - NoPrefetch *bool - TxLookupLimit *uint64 `toml:",omitempty"` - TransactionHistory *uint64 `toml:",omitempty"` - LogHistory *uint64 `toml:",omitempty"` - LogNoHistory *bool `toml:",omitempty"` - LogExportCheckpoints *string - StateHistory *uint64 `toml:",omitempty"` - StateScheme *string `toml:",omitempty"` - RequiredBlocks map[uint64]common.Hash `toml:"-"` - SkipBcVersionCheck *bool `toml:"-"` - DatabaseHandles *int `toml:"-"` - DatabaseCache *int - DatabaseFreezer *string - DatabaseEra *string - TrieCleanCache *int - TrieDirtyCache *int - TrieTimeout *time.Duration - SnapshotCache *int - Preimages *bool - TriesInMemory *uint64 - FilterLogCacheSize *int - Miner *miner.Config - TxPool *legacypool.Config - BlobPool *blobpool.Config - GPO *gasprice.Config - EnablePreimageRecording *bool - VMTrace *string - VMTraceJsonConfig *string - RPCGasCap *uint64 - RPCReturnDataLimit *uint64 - RPCEVMTimeout *time.Duration - RPCTxFeeCap *float64 - OverrideOsaka *big.Int `toml:",omitempty"` - HeimdallURL *string - HeimdallTimeout *time.Duration - WithoutHeimdall *bool - HeimdallgRPCAddress *string - HeimdallWSAddress *string - RunHeimdall *bool - RunHeimdallArgs *string - UseHeimdallApp *bool - BorLogs *bool - ParallelEVM *core.ParallelEVMConfig `toml:",omitempty"` - WitnessProtocol *bool - SyncWithWitnesses *bool - SyncAndProduceWitnesses *bool - DevFakeAuthor *bool `hcl:"devfakeauthor,optional" toml:"devfakeauthor,optional"` - OverrideVerkle *big.Int `toml:",omitempty"` - EnableBlockTracking *bool - FastForwardThreshold *uint64 + Genesis *core.Genesis `toml:",omitempty"` + NetworkId *uint64 + SyncMode *downloader.SyncMode + HistoryMode *history.HistoryMode + EthDiscoveryURLs []string + SnapDiscoveryURLs []string + NoPruning *bool + NoPrefetch *bool + TxLookupLimit *uint64 `toml:",omitempty"` + TransactionHistory *uint64 `toml:",omitempty"` + LogHistory *uint64 `toml:",omitempty"` + LogNoHistory *bool `toml:",omitempty"` + LogExportCheckpoints *string + StateHistory *uint64 `toml:",omitempty"` + StateScheme *string `toml:",omitempty"` + RequiredBlocks map[uint64]common.Hash `toml:"-"` + SkipBcVersionCheck *bool `toml:"-"` + DatabaseHandles *int `toml:"-"` + DatabaseCache *int + DatabaseFreezer *string + DatabaseEra *string + LevelDbCompactionTableSize *uint64 + LevelDbCompactionTableSizeMultiplier *float64 + LevelDbCompactionTotalSize *uint64 + LevelDbCompactionTotalSizeMultiplier *float64 + TrieCleanCache *int + TrieDirtyCache *int + TrieTimeout *time.Duration + SnapshotCache *int + Preimages *bool + TriesInMemory *uint64 + FilterLogCacheSize *int + Miner *miner.Config + TxPool *legacypool.Config + BlobPool *blobpool.Config + GPO *gasprice.Config + EnablePreimageRecording *bool + VMTrace *string + VMTraceJsonConfig *string + RPCGasCap *uint64 + RPCReturnDataLimit *uint64 + RPCEVMTimeout *time.Duration + RPCTxFeeCap *float64 + OverrideOsaka *big.Int `toml:",omitempty"` + HeimdallURL *string + HeimdallTimeout *time.Duration + WithoutHeimdall *bool + HeimdallgRPCAddress *string + HeimdallWSAddress *string + RunHeimdall *bool + RunHeimdallArgs *string + UseHeimdallApp *bool + BorLogs *bool + ParallelEVM *core.ParallelEVMConfig `toml:",omitempty"` + WitnessProtocol *bool + SyncWithWitnesses *bool + SyncAndProduceWitnesses *bool + DevFakeAuthor *bool `hcl:"devfakeauthor,optional" toml:"devfakeauthor,optional"` + OverrideVerkle *big.Int `toml:",omitempty"` + EnableBlockTracking *bool + FastForwardThreshold *uint64 + WitnessPruneThreshold *uint64 + WitnessPruneInterval *time.Duration + EnableParallelStatelessImport *bool + EnableParallelStatelessImportWorkers *int } var dec Config if err := unmarshal(&dec); err != nil { @@ -374,5 +394,17 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { if dec.FastForwardThreshold != nil { c.FastForwardThreshold = *dec.FastForwardThreshold } + if dec.WitnessPruneThreshold != nil { + c.WitnessPruneThreshold = *dec.WitnessPruneThreshold + } + if dec.WitnessPruneInterval != nil { + c.WitnessPruneInterval = *dec.WitnessPruneInterval + } + if dec.EnableParallelStatelessImport != nil { + c.EnableParallelStatelessImport = *dec.EnableParallelStatelessImport + } + if dec.EnableParallelStatelessImportWorkers != nil { + c.EnableParallelStatelessImportWorkers = *dec.EnableParallelStatelessImportWorkers + } return nil } diff --git a/eth/filters/IBackend.go b/eth/filters/IBackend.go index 4634321f57..90b9ab5fbf 100644 --- a/eth/filters/IBackend.go +++ b/eth/filters/IBackend.go @@ -1,10 +1,5 @@ // Code generated by MockGen. DO NOT EDIT. // Source: github.com/ethereum/go-ethereum/internal/ethapi (interfaces: Backend) -// -// Generated by this command: -// -// mockgen -destination=../../eth/filters/IBackend.go -package=filters . Backend -// // Package filters is a generated GoMock package. package filters @@ -29,14 +24,13 @@ import ( event "github.com/ethereum/go-ethereum/event" params "github.com/ethereum/go-ethereum/params" rpc "github.com/ethereum/go-ethereum/rpc" - gomock "go.uber.org/mock/gomock" + "go.uber.org/mock/gomock" ) // MockBackend is a mock of Backend interface. type MockBackend struct { ctrl *gomock.Controller recorder *MockBackendMockRecorder - isgomock struct{} } // MockBackendMockRecorder is the mock recorder for MockBackend. @@ -71,62 +65,62 @@ func (mr *MockBackendMockRecorder) AccountManager() *gomock.Call { } // BlobBaseFee mocks base method. -func (m *MockBackend) BlobBaseFee(ctx context.Context) *big.Int { +func (m *MockBackend) BlobBaseFee(arg0 context.Context) *big.Int { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "BlobBaseFee", ctx) + ret := m.ctrl.Call(m, "BlobBaseFee", arg0) ret0, _ := ret[0].(*big.Int) return ret0 } // BlobBaseFee indicates an expected call of BlobBaseFee. -func (mr *MockBackendMockRecorder) BlobBaseFee(ctx any) *gomock.Call { +func (mr *MockBackendMockRecorder) BlobBaseFee(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlobBaseFee", reflect.TypeOf((*MockBackend)(nil).BlobBaseFee), ctx) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlobBaseFee", reflect.TypeOf((*MockBackend)(nil).BlobBaseFee), arg0) } // BlockByHash mocks base method. -func (m *MockBackend) BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) { +func (m *MockBackend) BlockByHash(arg0 context.Context, arg1 common.Hash) (*types.Block, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "BlockByHash", ctx, hash) + ret := m.ctrl.Call(m, "BlockByHash", arg0, arg1) ret0, _ := ret[0].(*types.Block) ret1, _ := ret[1].(error) return ret0, ret1 } // BlockByHash indicates an expected call of BlockByHash. -func (mr *MockBackendMockRecorder) BlockByHash(ctx, hash any) *gomock.Call { +func (mr *MockBackendMockRecorder) BlockByHash(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlockByHash", reflect.TypeOf((*MockBackend)(nil).BlockByHash), ctx, hash) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlockByHash", reflect.TypeOf((*MockBackend)(nil).BlockByHash), arg0, arg1) } // BlockByNumber mocks base method. -func (m *MockBackend) BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error) { +func (m *MockBackend) BlockByNumber(arg0 context.Context, arg1 rpc.BlockNumber) (*types.Block, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "BlockByNumber", ctx, number) + ret := m.ctrl.Call(m, "BlockByNumber", arg0, arg1) ret0, _ := ret[0].(*types.Block) ret1, _ := ret[1].(error) return ret0, ret1 } // BlockByNumber indicates an expected call of BlockByNumber. -func (mr *MockBackendMockRecorder) BlockByNumber(ctx, number any) *gomock.Call { +func (mr *MockBackendMockRecorder) BlockByNumber(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlockByNumber", reflect.TypeOf((*MockBackend)(nil).BlockByNumber), ctx, number) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlockByNumber", reflect.TypeOf((*MockBackend)(nil).BlockByNumber), arg0, arg1) } // BlockByNumberOrHash mocks base method. -func (m *MockBackend) BlockByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Block, error) { +func (m *MockBackend) BlockByNumberOrHash(arg0 context.Context, arg1 rpc.BlockNumberOrHash) (*types.Block, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "BlockByNumberOrHash", ctx, blockNrOrHash) + ret := m.ctrl.Call(m, "BlockByNumberOrHash", arg0, arg1) ret0, _ := ret[0].(*types.Block) ret1, _ := ret[1].(error) return ret0, ret1 } // BlockByNumberOrHash indicates an expected call of BlockByNumberOrHash. -func (mr *MockBackendMockRecorder) BlockByNumberOrHash(ctx, blockNrOrHash any) *gomock.Call { +func (mr *MockBackendMockRecorder) BlockByNumberOrHash(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlockByNumberOrHash", reflect.TypeOf((*MockBackend)(nil).BlockByNumberOrHash), ctx, blockNrOrHash) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlockByNumberOrHash", reflect.TypeOf((*MockBackend)(nil).BlockByNumberOrHash), arg0, arg1) } // ChainConfig mocks base method. @@ -228,9 +222,9 @@ func (mr *MockBackendMockRecorder) ExtRPCEnabled() *gomock.Call { } // FeeHistory mocks base method. -func (m *MockBackend) FeeHistory(ctx context.Context, blockCount uint64, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (*big.Int, [][]*big.Int, []*big.Int, []float64, []*big.Int, []float64, error) { +func (m *MockBackend) FeeHistory(arg0 context.Context, arg1 uint64, arg2 rpc.BlockNumber, arg3 []float64) (*big.Int, [][]*big.Int, []*big.Int, []float64, []*big.Int, []float64, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "FeeHistory", ctx, blockCount, lastBlock, rewardPercentiles) + ret := m.ctrl.Call(m, "FeeHistory", arg0, arg1, arg2, arg3) ret0, _ := ret[0].(*big.Int) ret1, _ := ret[1].([][]*big.Int) ret2, _ := ret[2].([]*big.Int) @@ -242,60 +236,60 @@ func (m *MockBackend) FeeHistory(ctx context.Context, blockCount uint64, lastBlo } // FeeHistory indicates an expected call of FeeHistory. -func (mr *MockBackendMockRecorder) FeeHistory(ctx, blockCount, lastBlock, rewardPercentiles any) *gomock.Call { +func (mr *MockBackendMockRecorder) FeeHistory(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FeeHistory", reflect.TypeOf((*MockBackend)(nil).FeeHistory), ctx, blockCount, lastBlock, rewardPercentiles) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FeeHistory", reflect.TypeOf((*MockBackend)(nil).FeeHistory), arg0, arg1, arg2, arg3) } // GetBody mocks base method. -func (m *MockBackend) GetBody(ctx context.Context, hash common.Hash, number rpc.BlockNumber) (*types.Body, error) { +func (m *MockBackend) GetBody(arg0 context.Context, arg1 common.Hash, arg2 rpc.BlockNumber) (*types.Body, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetBody", ctx, hash, number) + ret := m.ctrl.Call(m, "GetBody", arg0, arg1, arg2) ret0, _ := ret[0].(*types.Body) ret1, _ := ret[1].(error) return ret0, ret1 } // GetBody indicates an expected call of GetBody. -func (mr *MockBackendMockRecorder) GetBody(ctx, hash, number any) *gomock.Call { +func (mr *MockBackendMockRecorder) GetBody(arg0, arg1, arg2 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBody", reflect.TypeOf((*MockBackend)(nil).GetBody), ctx, hash, number) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBody", reflect.TypeOf((*MockBackend)(nil).GetBody), arg0, arg1, arg2) } // GetBorBlockLogs mocks base method. -func (m *MockBackend) GetBorBlockLogs(ctx context.Context, hash common.Hash) ([]*types.Log, error) { +func (m *MockBackend) GetBorBlockLogs(arg0 context.Context, arg1 common.Hash) ([]*types.Log, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetBorBlockLogs", ctx, hash) + ret := m.ctrl.Call(m, "GetBorBlockLogs", arg0, arg1) ret0, _ := ret[0].([]*types.Log) ret1, _ := ret[1].(error) return ret0, ret1 } // GetBorBlockLogs indicates an expected call of GetBorBlockLogs. -func (mr *MockBackendMockRecorder) GetBorBlockLogs(ctx, hash any) *gomock.Call { +func (mr *MockBackendMockRecorder) GetBorBlockLogs(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBorBlockLogs", reflect.TypeOf((*MockBackend)(nil).GetBorBlockLogs), ctx, hash) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBorBlockLogs", reflect.TypeOf((*MockBackend)(nil).GetBorBlockLogs), arg0, arg1) } // GetBorBlockReceipt mocks base method. -func (m *MockBackend) GetBorBlockReceipt(ctx context.Context, hash common.Hash) (*types.Receipt, error) { +func (m *MockBackend) GetBorBlockReceipt(arg0 context.Context, arg1 common.Hash) (*types.Receipt, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetBorBlockReceipt", ctx, hash) + ret := m.ctrl.Call(m, "GetBorBlockReceipt", arg0, arg1) ret0, _ := ret[0].(*types.Receipt) ret1, _ := ret[1].(error) return ret0, ret1 } // GetBorBlockReceipt indicates an expected call of GetBorBlockReceipt. -func (mr *MockBackendMockRecorder) GetBorBlockReceipt(ctx, hash any) *gomock.Call { +func (mr *MockBackendMockRecorder) GetBorBlockReceipt(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBorBlockReceipt", reflect.TypeOf((*MockBackend)(nil).GetBorBlockReceipt), ctx, hash) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBorBlockReceipt", reflect.TypeOf((*MockBackend)(nil).GetBorBlockReceipt), arg0, arg1) } // GetBorBlockTransaction mocks base method. -func (m *MockBackend) GetBorBlockTransaction(ctx context.Context, txHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error) { +func (m *MockBackend) GetBorBlockTransaction(arg0 context.Context, arg1 common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetBorBlockTransaction", ctx, txHash) + ret := m.ctrl.Call(m, "GetBorBlockTransaction", arg0, arg1) ret0, _ := ret[0].(*types.Transaction) ret1, _ := ret[1].(common.Hash) ret2, _ := ret[2].(uint64) @@ -305,15 +299,15 @@ func (m *MockBackend) GetBorBlockTransaction(ctx context.Context, txHash common. } // GetBorBlockTransaction indicates an expected call of GetBorBlockTransaction. -func (mr *MockBackendMockRecorder) GetBorBlockTransaction(ctx, txHash any) *gomock.Call { +func (mr *MockBackendMockRecorder) GetBorBlockTransaction(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBorBlockTransaction", reflect.TypeOf((*MockBackend)(nil).GetBorBlockTransaction), ctx, txHash) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBorBlockTransaction", reflect.TypeOf((*MockBackend)(nil).GetBorBlockTransaction), arg0, arg1) } // GetBorBlockTransactionWithBlockHash mocks base method. -func (m *MockBackend) GetBorBlockTransactionWithBlockHash(ctx context.Context, txHash, blockHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error) { +func (m *MockBackend) GetBorBlockTransactionWithBlockHash(arg0 context.Context, arg1, arg2 common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetBorBlockTransactionWithBlockHash", ctx, txHash, blockHash) + ret := m.ctrl.Call(m, "GetBorBlockTransactionWithBlockHash", arg0, arg1, arg2) ret0, _ := ret[0].(*types.Transaction) ret1, _ := ret[1].(common.Hash) ret2, _ := ret[2].(uint64) @@ -323,67 +317,67 @@ func (m *MockBackend) GetBorBlockTransactionWithBlockHash(ctx context.Context, t } // GetBorBlockTransactionWithBlockHash indicates an expected call of GetBorBlockTransactionWithBlockHash. -func (mr *MockBackendMockRecorder) GetBorBlockTransactionWithBlockHash(ctx, txHash, blockHash any) *gomock.Call { +func (mr *MockBackendMockRecorder) GetBorBlockTransactionWithBlockHash(arg0, arg1, arg2 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBorBlockTransactionWithBlockHash", reflect.TypeOf((*MockBackend)(nil).GetBorBlockTransactionWithBlockHash), ctx, txHash, blockHash) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBorBlockTransactionWithBlockHash", reflect.TypeOf((*MockBackend)(nil).GetBorBlockTransactionWithBlockHash), arg0, arg1, arg2) } // GetEVM mocks base method. -func (m *MockBackend) GetEVM(ctx context.Context, arg1 *state.StateDB, header *types.Header, vmConfig *vm.Config, blockCtx *vm.BlockContext) *vm.EVM { +func (m *MockBackend) GetEVM(arg0 context.Context, arg1 *state.StateDB, arg2 *types.Header, arg3 *vm.Config, arg4 *vm.BlockContext) *vm.EVM { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetEVM", ctx, arg1, header, vmConfig, blockCtx) + ret := m.ctrl.Call(m, "GetEVM", arg0, arg1, arg2, arg3, arg4) ret0, _ := ret[0].(*vm.EVM) return ret0 } // GetEVM indicates an expected call of GetEVM. -func (mr *MockBackendMockRecorder) GetEVM(ctx, arg1, header, vmConfig, blockCtx any) *gomock.Call { +func (mr *MockBackendMockRecorder) GetEVM(arg0, arg1, arg2, arg3, arg4 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetEVM", reflect.TypeOf((*MockBackend)(nil).GetEVM), ctx, arg1, header, vmConfig, blockCtx) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetEVM", reflect.TypeOf((*MockBackend)(nil).GetEVM), arg0, arg1, arg2, arg3, arg4) } // GetLogs mocks base method. -func (m *MockBackend) GetLogs(ctx context.Context, blockHash common.Hash, number uint64) ([][]*types.Log, error) { +func (m *MockBackend) GetLogs(arg0 context.Context, arg1 common.Hash, arg2 uint64) ([][]*types.Log, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetLogs", ctx, blockHash, number) + ret := m.ctrl.Call(m, "GetLogs", arg0, arg1, arg2) ret0, _ := ret[0].([][]*types.Log) ret1, _ := ret[1].(error) return ret0, ret1 } // GetLogs indicates an expected call of GetLogs. -func (mr *MockBackendMockRecorder) GetLogs(ctx, blockHash, number any) *gomock.Call { +func (mr *MockBackendMockRecorder) GetLogs(arg0, arg1, arg2 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLogs", reflect.TypeOf((*MockBackend)(nil).GetLogs), ctx, blockHash, number) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLogs", reflect.TypeOf((*MockBackend)(nil).GetLogs), arg0, arg1, arg2) } // GetPoolNonce mocks base method. -func (m *MockBackend) GetPoolNonce(ctx context.Context, addr common.Address) (uint64, error) { +func (m *MockBackend) GetPoolNonce(arg0 context.Context, arg1 common.Address) (uint64, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetPoolNonce", ctx, addr) + ret := m.ctrl.Call(m, "GetPoolNonce", arg0, arg1) ret0, _ := ret[0].(uint64) ret1, _ := ret[1].(error) return ret0, ret1 } // GetPoolNonce indicates an expected call of GetPoolNonce. -func (mr *MockBackendMockRecorder) GetPoolNonce(ctx, addr any) *gomock.Call { +func (mr *MockBackendMockRecorder) GetPoolNonce(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPoolNonce", reflect.TypeOf((*MockBackend)(nil).GetPoolNonce), ctx, addr) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPoolNonce", reflect.TypeOf((*MockBackend)(nil).GetPoolNonce), arg0, arg1) } // GetPoolTransaction mocks base method. -func (m *MockBackend) GetPoolTransaction(txHash common.Hash) *types.Transaction { +func (m *MockBackend) GetPoolTransaction(arg0 common.Hash) *types.Transaction { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetPoolTransaction", txHash) + ret := m.ctrl.Call(m, "GetPoolTransaction", arg0) ret0, _ := ret[0].(*types.Transaction) return ret0 } // GetPoolTransaction indicates an expected call of GetPoolTransaction. -func (mr *MockBackendMockRecorder) GetPoolTransaction(txHash any) *gomock.Call { +func (mr *MockBackendMockRecorder) GetPoolTransaction(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPoolTransaction", reflect.TypeOf((*MockBackend)(nil).GetPoolTransaction), txHash) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPoolTransaction", reflect.TypeOf((*MockBackend)(nil).GetPoolTransaction), arg0) } // GetPoolTransactions mocks base method. @@ -402,67 +396,67 @@ func (mr *MockBackendMockRecorder) GetPoolTransactions() *gomock.Call { } // GetReceipts mocks base method. -func (m *MockBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) { +func (m *MockBackend) GetReceipts(arg0 context.Context, arg1 common.Hash) (types.Receipts, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetReceipts", ctx, hash) + ret := m.ctrl.Call(m, "GetReceipts", arg0, arg1) ret0, _ := ret[0].(types.Receipts) ret1, _ := ret[1].(error) return ret0, ret1 } // GetReceipts indicates an expected call of GetReceipts. -func (mr *MockBackendMockRecorder) GetReceipts(ctx, hash any) *gomock.Call { +func (mr *MockBackendMockRecorder) GetReceipts(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetReceipts", reflect.TypeOf((*MockBackend)(nil).GetReceipts), ctx, hash) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetReceipts", reflect.TypeOf((*MockBackend)(nil).GetReceipts), arg0, arg1) } // GetRootHash mocks base method. -func (m *MockBackend) GetRootHash(ctx context.Context, starBlockNr, endBlockNr uint64) (string, error) { +func (m *MockBackend) GetRootHash(arg0 context.Context, arg1, arg2 uint64) (string, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetRootHash", ctx, starBlockNr, endBlockNr) + ret := m.ctrl.Call(m, "GetRootHash", arg0, arg1, arg2) ret0, _ := ret[0].(string) ret1, _ := ret[1].(error) return ret0, ret1 } // GetRootHash indicates an expected call of GetRootHash. -func (mr *MockBackendMockRecorder) GetRootHash(ctx, starBlockNr, endBlockNr any) *gomock.Call { +func (mr *MockBackendMockRecorder) GetRootHash(arg0, arg1, arg2 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetRootHash", reflect.TypeOf((*MockBackend)(nil).GetRootHash), ctx, starBlockNr, endBlockNr) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetRootHash", reflect.TypeOf((*MockBackend)(nil).GetRootHash), arg0, arg1, arg2) } // GetTd mocks base method. -func (m *MockBackend) GetTd(ctx context.Context, hash common.Hash) *big.Int { +func (m *MockBackend) GetTd(arg0 context.Context, arg1 common.Hash) *big.Int { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetTd", ctx, hash) + ret := m.ctrl.Call(m, "GetTd", arg0, arg1) ret0, _ := ret[0].(*big.Int) return ret0 } // GetTd indicates an expected call of GetTd. -func (mr *MockBackendMockRecorder) GetTd(ctx, hash any) *gomock.Call { +func (mr *MockBackendMockRecorder) GetTd(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTd", reflect.TypeOf((*MockBackend)(nil).GetTd), ctx, hash) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTd", reflect.TypeOf((*MockBackend)(nil).GetTd), arg0, arg1) } // GetTdByNumber mocks base method. -func (m *MockBackend) GetTdByNumber(ctx context.Context, blockNr rpc.BlockNumber) *big.Int { +func (m *MockBackend) GetTdByNumber(arg0 context.Context, arg1 rpc.BlockNumber) *big.Int { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetTdByNumber", ctx, blockNr) + ret := m.ctrl.Call(m, "GetTdByNumber", arg0, arg1) ret0, _ := ret[0].(*big.Int) return ret0 } // GetTdByNumber indicates an expected call of GetTdByNumber. -func (mr *MockBackendMockRecorder) GetTdByNumber(ctx, blockNr any) *gomock.Call { +func (mr *MockBackendMockRecorder) GetTdByNumber(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTdByNumber", reflect.TypeOf((*MockBackend)(nil).GetTdByNumber), ctx, blockNr) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTdByNumber", reflect.TypeOf((*MockBackend)(nil).GetTdByNumber), arg0, arg1) } // GetTransaction mocks base method. -func (m *MockBackend) GetTransaction(txHash common.Hash) (bool, *types.Transaction, common.Hash, uint64, uint64) { +func (m *MockBackend) GetTransaction(arg0 common.Hash) (bool, *types.Transaction, common.Hash, uint64, uint64) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetTransaction", txHash) + ret := m.ctrl.Call(m, "GetTransaction", arg0) ret0, _ := ret[0].(bool) ret1, _ := ret[1].(*types.Transaction) ret2, _ := ret[2].(common.Hash) @@ -472,24 +466,24 @@ func (m *MockBackend) GetTransaction(txHash common.Hash) (bool, *types.Transacti } // GetTransaction indicates an expected call of GetTransaction. -func (mr *MockBackendMockRecorder) GetTransaction(txHash any) *gomock.Call { +func (mr *MockBackendMockRecorder) GetTransaction(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTransaction", reflect.TypeOf((*MockBackend)(nil).GetTransaction), txHash) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTransaction", reflect.TypeOf((*MockBackend)(nil).GetTransaction), arg0) } // GetVoteOnHash mocks base method. -func (m *MockBackend) GetVoteOnHash(ctx context.Context, startBlockNumber, endBlockNumber uint64, hash, milestoneID string) (bool, error) { +func (m *MockBackend) GetVoteOnHash(arg0 context.Context, arg1, arg2 uint64, arg3, arg4 string) (bool, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetVoteOnHash", ctx, startBlockNumber, endBlockNumber, hash, milestoneID) + ret := m.ctrl.Call(m, "GetVoteOnHash", arg0, arg1, arg2, arg3, arg4) ret0, _ := ret[0].(bool) ret1, _ := ret[1].(error) return ret0, ret1 } // GetVoteOnHash indicates an expected call of GetVoteOnHash. -func (mr *MockBackendMockRecorder) GetVoteOnHash(ctx, startBlockNumber, endBlockNumber, hash, milestoneID any) *gomock.Call { +func (mr *MockBackendMockRecorder) GetVoteOnHash(arg0, arg1, arg2, arg3, arg4 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetVoteOnHash", reflect.TypeOf((*MockBackend)(nil).GetVoteOnHash), ctx, startBlockNumber, endBlockNumber, hash, milestoneID) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetVoteOnHash", reflect.TypeOf((*MockBackend)(nil).GetVoteOnHash), arg0, arg1, arg2, arg3, arg4) } // GetWhitelistedCheckpoint mocks base method. @@ -525,63 +519,63 @@ func (mr *MockBackendMockRecorder) GetWhitelistedMilestone() *gomock.Call { } // GetWitnesses mocks base method. -func (m *MockBackend) GetWitnesses(ctx context.Context, originBlock, totalBlocks uint64) ([]*stateless.Witness, error) { +func (m *MockBackend) GetWitnesses(arg0 context.Context, arg1, arg2 uint64) ([]*stateless.Witness, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetWitnesses", ctx, originBlock, totalBlocks) + ret := m.ctrl.Call(m, "GetWitnesses", arg0, arg1, arg2) ret0, _ := ret[0].([]*stateless.Witness) ret1, _ := ret[1].(error) return ret0, ret1 } // GetWitnesses indicates an expected call of GetWitnesses. -func (mr *MockBackendMockRecorder) GetWitnesses(ctx, originBlock, totalBlocks any) *gomock.Call { +func (mr *MockBackendMockRecorder) GetWitnesses(arg0, arg1, arg2 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetWitnesses", reflect.TypeOf((*MockBackend)(nil).GetWitnesses), ctx, originBlock, totalBlocks) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetWitnesses", reflect.TypeOf((*MockBackend)(nil).GetWitnesses), arg0, arg1, arg2) } // HeaderByHash mocks base method. -func (m *MockBackend) HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) { +func (m *MockBackend) HeaderByHash(arg0 context.Context, arg1 common.Hash) (*types.Header, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "HeaderByHash", ctx, hash) + ret := m.ctrl.Call(m, "HeaderByHash", arg0, arg1) ret0, _ := ret[0].(*types.Header) ret1, _ := ret[1].(error) return ret0, ret1 } // HeaderByHash indicates an expected call of HeaderByHash. -func (mr *MockBackendMockRecorder) HeaderByHash(ctx, hash any) *gomock.Call { +func (mr *MockBackendMockRecorder) HeaderByHash(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HeaderByHash", reflect.TypeOf((*MockBackend)(nil).HeaderByHash), ctx, hash) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HeaderByHash", reflect.TypeOf((*MockBackend)(nil).HeaderByHash), arg0, arg1) } // HeaderByNumber mocks base method. -func (m *MockBackend) HeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Header, error) { +func (m *MockBackend) HeaderByNumber(arg0 context.Context, arg1 rpc.BlockNumber) (*types.Header, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "HeaderByNumber", ctx, number) + ret := m.ctrl.Call(m, "HeaderByNumber", arg0, arg1) ret0, _ := ret[0].(*types.Header) ret1, _ := ret[1].(error) return ret0, ret1 } // HeaderByNumber indicates an expected call of HeaderByNumber. -func (mr *MockBackendMockRecorder) HeaderByNumber(ctx, number any) *gomock.Call { +func (mr *MockBackendMockRecorder) HeaderByNumber(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HeaderByNumber", reflect.TypeOf((*MockBackend)(nil).HeaderByNumber), ctx, number) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HeaderByNumber", reflect.TypeOf((*MockBackend)(nil).HeaderByNumber), arg0, arg1) } // HeaderByNumberOrHash mocks base method. -func (m *MockBackend) HeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Header, error) { +func (m *MockBackend) HeaderByNumberOrHash(arg0 context.Context, arg1 rpc.BlockNumberOrHash) (*types.Header, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "HeaderByNumberOrHash", ctx, blockNrOrHash) + ret := m.ctrl.Call(m, "HeaderByNumberOrHash", arg0, arg1) ret0, _ := ret[0].(*types.Header) ret1, _ := ret[1].(error) return ret0, ret1 } // HeaderByNumberOrHash indicates an expected call of HeaderByNumberOrHash. -func (mr *MockBackendMockRecorder) HeaderByNumberOrHash(ctx, blockNrOrHash any) *gomock.Call { +func (mr *MockBackendMockRecorder) HeaderByNumberOrHash(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HeaderByNumberOrHash", reflect.TypeOf((*MockBackend)(nil).HeaderByNumberOrHash), ctx, blockNrOrHash) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HeaderByNumberOrHash", reflect.TypeOf((*MockBackend)(nil).HeaderByNumberOrHash), arg0, arg1) } // HistoryPruningCutoff mocks base method. @@ -598,6 +592,20 @@ func (mr *MockBackendMockRecorder) HistoryPruningCutoff() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HistoryPruningCutoff", reflect.TypeOf((*MockBackend)(nil).HistoryPruningCutoff)) } +// IsParallelImportActive mocks base method. +func (m *MockBackend) IsParallelImportActive() bool { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "IsParallelImportActive") + ret0, _ := ret[0].(bool) + return ret0 +} + +// IsParallelImportActive indicates an expected call of IsParallelImportActive. +func (mr *MockBackendMockRecorder) IsParallelImportActive() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsParallelImportActive", reflect.TypeOf((*MockBackend)(nil).IsParallelImportActive)) +} + // NewMatcherBackend mocks base method. func (m *MockBackend) NewMatcherBackend() filtermaps.MatcherBackend { m.ctrl.T.Helper() @@ -613,10 +621,10 @@ func (mr *MockBackendMockRecorder) NewMatcherBackend() *gomock.Call { } // PeerStats mocks base method. -func (m *MockBackend) PeerStats() any { +func (m *MockBackend) PeerStats() interface{} { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "PeerStats") - ret0, _ := ret[0].(any) + ret0, _ := ret[0].(interface{}) return ret0 } @@ -723,35 +731,35 @@ func (mr *MockBackendMockRecorder) RPCTxFeeCap() *gomock.Call { } // SendTx mocks base method. -func (m *MockBackend) SendTx(ctx context.Context, signedTx *types.Transaction) error { +func (m *MockBackend) SendTx(arg0 context.Context, arg1 *types.Transaction) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SendTx", ctx, signedTx) + ret := m.ctrl.Call(m, "SendTx", arg0, arg1) ret0, _ := ret[0].(error) return ret0 } // SendTx indicates an expected call of SendTx. -func (mr *MockBackendMockRecorder) SendTx(ctx, signedTx any) *gomock.Call { +func (mr *MockBackendMockRecorder) SendTx(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendTx", reflect.TypeOf((*MockBackend)(nil).SendTx), ctx, signedTx) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendTx", reflect.TypeOf((*MockBackend)(nil).SendTx), arg0, arg1) } // SetHead mocks base method. -func (m *MockBackend) SetHead(number uint64) { +func (m *MockBackend) SetHead(arg0 uint64) { m.ctrl.T.Helper() - m.ctrl.Call(m, "SetHead", number) + m.ctrl.Call(m, "SetHead", arg0) } // SetHead indicates an expected call of SetHead. -func (mr *MockBackendMockRecorder) SetHead(number any) *gomock.Call { +func (mr *MockBackendMockRecorder) SetHead(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetHead", reflect.TypeOf((*MockBackend)(nil).SetHead), number) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetHead", reflect.TypeOf((*MockBackend)(nil).SetHead), arg0) } // StateAndHeaderByNumber mocks base method. -func (m *MockBackend) StateAndHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*state.StateDB, *types.Header, error) { +func (m *MockBackend) StateAndHeaderByNumber(arg0 context.Context, arg1 rpc.BlockNumber) (*state.StateDB, *types.Header, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "StateAndHeaderByNumber", ctx, number) + ret := m.ctrl.Call(m, "StateAndHeaderByNumber", arg0, arg1) ret0, _ := ret[0].(*state.StateDB) ret1, _ := ret[1].(*types.Header) ret2, _ := ret[2].(error) @@ -759,15 +767,15 @@ func (m *MockBackend) StateAndHeaderByNumber(ctx context.Context, number rpc.Blo } // StateAndHeaderByNumber indicates an expected call of StateAndHeaderByNumber. -func (mr *MockBackendMockRecorder) StateAndHeaderByNumber(ctx, number any) *gomock.Call { +func (mr *MockBackendMockRecorder) StateAndHeaderByNumber(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StateAndHeaderByNumber", reflect.TypeOf((*MockBackend)(nil).StateAndHeaderByNumber), ctx, number) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StateAndHeaderByNumber", reflect.TypeOf((*MockBackend)(nil).StateAndHeaderByNumber), arg0, arg1) } // StateAndHeaderByNumberOrHash mocks base method. -func (m *MockBackend) StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*state.StateDB, *types.Header, error) { +func (m *MockBackend) StateAndHeaderByNumberOrHash(arg0 context.Context, arg1 rpc.BlockNumberOrHash) (*state.StateDB, *types.Header, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "StateAndHeaderByNumberOrHash", ctx, blockNrOrHash) + ret := m.ctrl.Call(m, "StateAndHeaderByNumberOrHash", arg0, arg1) ret0, _ := ret[0].(*state.StateDB) ret1, _ := ret[1].(*types.Header) ret2, _ := ret[2].(error) @@ -775,9 +783,9 @@ func (m *MockBackend) StateAndHeaderByNumberOrHash(ctx context.Context, blockNrO } // StateAndHeaderByNumberOrHash indicates an expected call of StateAndHeaderByNumberOrHash. -func (mr *MockBackendMockRecorder) StateAndHeaderByNumberOrHash(ctx, blockNrOrHash any) *gomock.Call { +func (mr *MockBackendMockRecorder) StateAndHeaderByNumberOrHash(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StateAndHeaderByNumberOrHash", reflect.TypeOf((*MockBackend)(nil).StateAndHeaderByNumberOrHash), ctx, blockNrOrHash) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StateAndHeaderByNumberOrHash", reflect.TypeOf((*MockBackend)(nil).StateAndHeaderByNumberOrHash), arg0, arg1) } // Stats mocks base method. @@ -796,73 +804,73 @@ func (mr *MockBackendMockRecorder) Stats() *gomock.Call { } // StoreWitness mocks base method. -func (m *MockBackend) StoreWitness(ctx context.Context, blockHash common.Hash, witness *stateless.Witness) error { +func (m *MockBackend) StoreWitness(arg0 context.Context, arg1 common.Hash, arg2 *stateless.Witness) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "StoreWitness", ctx, blockHash, witness) + ret := m.ctrl.Call(m, "StoreWitness", arg0, arg1, arg2) ret0, _ := ret[0].(error) return ret0 } // StoreWitness indicates an expected call of StoreWitness. -func (mr *MockBackendMockRecorder) StoreWitness(ctx, blockHash, witness any) *gomock.Call { +func (mr *MockBackendMockRecorder) StoreWitness(arg0, arg1, arg2 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StoreWitness", reflect.TypeOf((*MockBackend)(nil).StoreWitness), ctx, blockHash, witness) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StoreWitness", reflect.TypeOf((*MockBackend)(nil).StoreWitness), arg0, arg1, arg2) } // SubscribeChain2HeadEvent mocks base method. -func (m *MockBackend) SubscribeChain2HeadEvent(ch chan<- core.Chain2HeadEvent) event.Subscription { +func (m *MockBackend) SubscribeChain2HeadEvent(arg0 chan<- core.Chain2HeadEvent) event.Subscription { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SubscribeChain2HeadEvent", ch) + ret := m.ctrl.Call(m, "SubscribeChain2HeadEvent", arg0) ret0, _ := ret[0].(event.Subscription) return ret0 } // SubscribeChain2HeadEvent indicates an expected call of SubscribeChain2HeadEvent. -func (mr *MockBackendMockRecorder) SubscribeChain2HeadEvent(ch any) *gomock.Call { +func (mr *MockBackendMockRecorder) SubscribeChain2HeadEvent(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubscribeChain2HeadEvent", reflect.TypeOf((*MockBackend)(nil).SubscribeChain2HeadEvent), ch) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubscribeChain2HeadEvent", reflect.TypeOf((*MockBackend)(nil).SubscribeChain2HeadEvent), arg0) } // SubscribeChainEvent mocks base method. -func (m *MockBackend) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription { +func (m *MockBackend) SubscribeChainEvent(arg0 chan<- core.ChainEvent) event.Subscription { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SubscribeChainEvent", ch) + ret := m.ctrl.Call(m, "SubscribeChainEvent", arg0) ret0, _ := ret[0].(event.Subscription) return ret0 } // SubscribeChainEvent indicates an expected call of SubscribeChainEvent. -func (mr *MockBackendMockRecorder) SubscribeChainEvent(ch any) *gomock.Call { +func (mr *MockBackendMockRecorder) SubscribeChainEvent(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubscribeChainEvent", reflect.TypeOf((*MockBackend)(nil).SubscribeChainEvent), ch) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubscribeChainEvent", reflect.TypeOf((*MockBackend)(nil).SubscribeChainEvent), arg0) } // SubscribeChainHeadEvent mocks base method. -func (m *MockBackend) SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription { +func (m *MockBackend) SubscribeChainHeadEvent(arg0 chan<- core.ChainHeadEvent) event.Subscription { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SubscribeChainHeadEvent", ch) + ret := m.ctrl.Call(m, "SubscribeChainHeadEvent", arg0) ret0, _ := ret[0].(event.Subscription) return ret0 } // SubscribeChainHeadEvent indicates an expected call of SubscribeChainHeadEvent. -func (mr *MockBackendMockRecorder) SubscribeChainHeadEvent(ch any) *gomock.Call { +func (mr *MockBackendMockRecorder) SubscribeChainHeadEvent(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubscribeChainHeadEvent", reflect.TypeOf((*MockBackend)(nil).SubscribeChainHeadEvent), ch) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubscribeChainHeadEvent", reflect.TypeOf((*MockBackend)(nil).SubscribeChainHeadEvent), arg0) } // SubscribeLogsEvent mocks base method. -func (m *MockBackend) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription { +func (m *MockBackend) SubscribeLogsEvent(arg0 chan<- []*types.Log) event.Subscription { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SubscribeLogsEvent", ch) + ret := m.ctrl.Call(m, "SubscribeLogsEvent", arg0) ret0, _ := ret[0].(event.Subscription) return ret0 } // SubscribeLogsEvent indicates an expected call of SubscribeLogsEvent. -func (mr *MockBackendMockRecorder) SubscribeLogsEvent(ch any) *gomock.Call { +func (mr *MockBackendMockRecorder) SubscribeLogsEvent(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubscribeLogsEvent", reflect.TypeOf((*MockBackend)(nil).SubscribeLogsEvent), ch) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubscribeLogsEvent", reflect.TypeOf((*MockBackend)(nil).SubscribeLogsEvent), arg0) } // SubscribeNewTxsEvent mocks base method. @@ -874,80 +882,80 @@ func (m *MockBackend) SubscribeNewTxsEvent(arg0 chan<- core.NewTxsEvent) event.S } // SubscribeNewTxsEvent indicates an expected call of SubscribeNewTxsEvent. -func (mr *MockBackendMockRecorder) SubscribeNewTxsEvent(arg0 any) *gomock.Call { +func (mr *MockBackendMockRecorder) SubscribeNewTxsEvent(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubscribeNewTxsEvent", reflect.TypeOf((*MockBackend)(nil).SubscribeNewTxsEvent), arg0) } // SubscribePendingLogsEvent mocks base method. -func (m *MockBackend) SubscribePendingLogsEvent(ch chan<- []*types.Log) event.Subscription { +func (m *MockBackend) SubscribePendingLogsEvent(arg0 chan<- []*types.Log) event.Subscription { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SubscribePendingLogsEvent", ch) + ret := m.ctrl.Call(m, "SubscribePendingLogsEvent", arg0) ret0, _ := ret[0].(event.Subscription) return ret0 } // SubscribePendingLogsEvent indicates an expected call of SubscribePendingLogsEvent. -func (mr *MockBackendMockRecorder) SubscribePendingLogsEvent(ch any) *gomock.Call { +func (mr *MockBackendMockRecorder) SubscribePendingLogsEvent(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubscribePendingLogsEvent", reflect.TypeOf((*MockBackend)(nil).SubscribePendingLogsEvent), ch) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubscribePendingLogsEvent", reflect.TypeOf((*MockBackend)(nil).SubscribePendingLogsEvent), arg0) } // SubscribeRemovedLogsEvent mocks base method. -func (m *MockBackend) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription { +func (m *MockBackend) SubscribeRemovedLogsEvent(arg0 chan<- core.RemovedLogsEvent) event.Subscription { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SubscribeRemovedLogsEvent", ch) + ret := m.ctrl.Call(m, "SubscribeRemovedLogsEvent", arg0) ret0, _ := ret[0].(event.Subscription) return ret0 } // SubscribeRemovedLogsEvent indicates an expected call of SubscribeRemovedLogsEvent. -func (mr *MockBackendMockRecorder) SubscribeRemovedLogsEvent(ch any) *gomock.Call { +func (mr *MockBackendMockRecorder) SubscribeRemovedLogsEvent(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubscribeRemovedLogsEvent", reflect.TypeOf((*MockBackend)(nil).SubscribeRemovedLogsEvent), ch) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubscribeRemovedLogsEvent", reflect.TypeOf((*MockBackend)(nil).SubscribeRemovedLogsEvent), arg0) } // SubscribeStateSyncEvent mocks base method. -func (m *MockBackend) SubscribeStateSyncEvent(ch chan<- core.StateSyncEvent) event.Subscription { +func (m *MockBackend) SubscribeStateSyncEvent(arg0 chan<- core.StateSyncEvent) event.Subscription { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SubscribeStateSyncEvent", ch) + ret := m.ctrl.Call(m, "SubscribeStateSyncEvent", arg0) ret0, _ := ret[0].(event.Subscription) return ret0 } // SubscribeStateSyncEvent indicates an expected call of SubscribeStateSyncEvent. -func (mr *MockBackendMockRecorder) SubscribeStateSyncEvent(ch any) *gomock.Call { +func (mr *MockBackendMockRecorder) SubscribeStateSyncEvent(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubscribeStateSyncEvent", reflect.TypeOf((*MockBackend)(nil).SubscribeStateSyncEvent), ch) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubscribeStateSyncEvent", reflect.TypeOf((*MockBackend)(nil).SubscribeStateSyncEvent), arg0) } // SuggestGasTipCap mocks base method. -func (m *MockBackend) SuggestGasTipCap(ctx context.Context) (*big.Int, error) { +func (m *MockBackend) SuggestGasTipCap(arg0 context.Context) (*big.Int, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SuggestGasTipCap", ctx) + ret := m.ctrl.Call(m, "SuggestGasTipCap", arg0) ret0, _ := ret[0].(*big.Int) ret1, _ := ret[1].(error) return ret0, ret1 } // SuggestGasTipCap indicates an expected call of SuggestGasTipCap. -func (mr *MockBackendMockRecorder) SuggestGasTipCap(ctx any) *gomock.Call { +func (mr *MockBackendMockRecorder) SuggestGasTipCap(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SuggestGasTipCap", reflect.TypeOf((*MockBackend)(nil).SuggestGasTipCap), ctx) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SuggestGasTipCap", reflect.TypeOf((*MockBackend)(nil).SuggestGasTipCap), arg0) } // SyncProgress mocks base method. -func (m *MockBackend) SyncProgress(ctx context.Context) ethereum.SyncProgress { +func (m *MockBackend) SyncProgress(arg0 context.Context) ethereum.SyncProgress { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SyncProgress", ctx) + ret := m.ctrl.Call(m, "SyncProgress", arg0) ret0, _ := ret[0].(ethereum.SyncProgress) return ret0 } // SyncProgress indicates an expected call of SyncProgress. -func (mr *MockBackendMockRecorder) SyncProgress(ctx any) *gomock.Call { +func (mr *MockBackendMockRecorder) SyncProgress(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SyncProgress", reflect.TypeOf((*MockBackend)(nil).SyncProgress), ctx) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SyncProgress", reflect.TypeOf((*MockBackend)(nil).SyncProgress), arg0) } // TxIndexDone mocks base method. @@ -980,18 +988,18 @@ func (mr *MockBackendMockRecorder) TxPoolContent() *gomock.Call { } // TxPoolContentFrom mocks base method. -func (m *MockBackend) TxPoolContentFrom(addr common.Address) ([]*types.Transaction, []*types.Transaction) { +func (m *MockBackend) TxPoolContentFrom(arg0 common.Address) ([]*types.Transaction, []*types.Transaction) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "TxPoolContentFrom", addr) + ret := m.ctrl.Call(m, "TxPoolContentFrom", arg0) ret0, _ := ret[0].([]*types.Transaction) ret1, _ := ret[1].([]*types.Transaction) return ret0, ret1 } // TxPoolContentFrom indicates an expected call of TxPoolContentFrom. -func (mr *MockBackendMockRecorder) TxPoolContentFrom(addr any) *gomock.Call { +func (mr *MockBackendMockRecorder) TxPoolContentFrom(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TxPoolContentFrom", reflect.TypeOf((*MockBackend)(nil).TxPoolContentFrom), addr) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TxPoolContentFrom", reflect.TypeOf((*MockBackend)(nil).TxPoolContentFrom), arg0) } // UnprotectedAllowed mocks base method. @@ -1017,9 +1025,9 @@ func (m *MockBackend) GetCanonicalReceipt(tx *types.Transaction, blockHash commo } // WitnessByHash mocks base method. -func (m *MockBackend) WitnessByHash(ctx context.Context, hash common.Hash) (*stateless.Witness, error) { +func (m *MockBackend) WitnessByHash(arg0 context.Context, arg1 common.Hash) (*stateless.Witness, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "WitnessByHash", ctx, hash) + ret := m.ctrl.Call(m, "WitnessByHash", arg0, arg1) ret0, _ := ret[0].(*stateless.Witness) ret1, _ := ret[1].(error) return ret0, ret1 @@ -1047,37 +1055,37 @@ func (mr *MockBackendMockRecorder) GetCanonicalTransaction(txHash any) *gomock.C } // WitnessByHash indicates an expected call of WitnessByHash. -func (mr *MockBackendMockRecorder) WitnessByHash(ctx, hash any) *gomock.Call { +func (mr *MockBackendMockRecorder) WitnessByHash(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WitnessByHash", reflect.TypeOf((*MockBackend)(nil).WitnessByHash), ctx, hash) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WitnessByHash", reflect.TypeOf((*MockBackend)(nil).WitnessByHash), arg0, arg1) } // WitnessByNumber mocks base method. -func (m *MockBackend) WitnessByNumber(ctx context.Context, number rpc.BlockNumber) (*stateless.Witness, error) { +func (m *MockBackend) WitnessByNumber(arg0 context.Context, arg1 rpc.BlockNumber) (*stateless.Witness, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "WitnessByNumber", ctx, number) + ret := m.ctrl.Call(m, "WitnessByNumber", arg0, arg1) ret0, _ := ret[0].(*stateless.Witness) ret1, _ := ret[1].(error) return ret0, ret1 } // WitnessByNumber indicates an expected call of WitnessByNumber. -func (mr *MockBackendMockRecorder) WitnessByNumber(ctx, number any) *gomock.Call { +func (mr *MockBackendMockRecorder) WitnessByNumber(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WitnessByNumber", reflect.TypeOf((*MockBackend)(nil).WitnessByNumber), ctx, number) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WitnessByNumber", reflect.TypeOf((*MockBackend)(nil).WitnessByNumber), arg0, arg1) } // WitnessByNumberOrHash mocks base method. -func (m *MockBackend) WitnessByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*stateless.Witness, error) { +func (m *MockBackend) WitnessByNumberOrHash(arg0 context.Context, arg1 rpc.BlockNumberOrHash) (*stateless.Witness, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "WitnessByNumberOrHash", ctx, blockNrOrHash) + ret := m.ctrl.Call(m, "WitnessByNumberOrHash", arg0, arg1) ret0, _ := ret[0].(*stateless.Witness) ret1, _ := ret[1].(error) return ret0, ret1 } // WitnessByNumberOrHash indicates an expected call of WitnessByNumberOrHash. -func (mr *MockBackendMockRecorder) WitnessByNumberOrHash(ctx, blockNrOrHash any) *gomock.Call { +func (mr *MockBackendMockRecorder) WitnessByNumberOrHash(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WitnessByNumberOrHash", reflect.TypeOf((*MockBackend)(nil).WitnessByNumberOrHash), ctx, blockNrOrHash) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WitnessByNumberOrHash", reflect.TypeOf((*MockBackend)(nil).WitnessByNumberOrHash), arg0, arg1) } diff --git a/internal/cli/server/config.go b/internal/cli/server/config.go index 6e1ecdb88a..b923d5006f 100644 --- a/internal/cli/server/config.go +++ b/internal/cli/server/config.go @@ -685,6 +685,12 @@ type WitnessConfig struct { // ProduceWitnesses enables producing witnesses while syncing ProduceWitnesses bool `hcl:"producewitnesses,optional" toml:"producewitnesses,optional"` + // Parallel stateless import (download path) toggle + EnableParallelStatelessImport bool `hcl:"parallel-stateless-import,optional" toml:"parallel-stateless-import,optional"` + + // Number of workers (CPUs) to use for parallel stateless import. If 0, uses GOMAXPROCS. + ParallelStatelessImportWorkers int `hcl:"parallel-stateless-import-workers,optional" toml:"parallel-stateless-import-workers,optional"` + // WitnessAPI enables witness API endpoints WitnessAPI bool `hcl:"witnessapi,optional" toml:"witnessapi,optional"` @@ -900,11 +906,13 @@ func DefaultConfig() *Config { Enforce: false, }, Witness: &WitnessConfig{ - Enable: false, - SyncWithWitnesses: false, - ProduceWitnesses: false, - WitnessAPI: false, - FastForwardThreshold: 6400, + Enable: false, + SyncWithWitnesses: false, + ProduceWitnesses: false, + EnableParallelStatelessImport: false, + ParallelStatelessImportWorkers: 0, + WitnessAPI: false, + FastForwardThreshold: 6400, }, History: &HistoryConfig{ TransactionHistory: ethconfig.Defaults.TransactionHistory, @@ -1374,6 +1382,8 @@ func (c *Config) buildEth(stack *node.Node, accountManager *accounts.Manager) (* } n.SyncWithWitnesses = c.Witness.SyncWithWitnesses n.SyncAndProduceWitnesses = c.Witness.ProduceWitnesses + n.EnableParallelStatelessImport = c.Witness.EnableParallelStatelessImport + n.EnableParallelStatelessImportWorkers = c.Witness.ParallelStatelessImportWorkers n.WitnessAPIEnabled = c.Witness.WitnessAPI n.FastForwardThreshold = c.Witness.FastForwardThreshold diff --git a/internal/cli/server/flags.go b/internal/cli/server/flags.go index 35c75d909e..5472f1f097 100644 --- a/internal/cli/server/flags.go +++ b/internal/cli/server/flags.go @@ -1078,6 +1078,18 @@ func (c *Command) Flags(config *Config) *flagset.Flagset { Value: &c.cliConfig.Witness.ProduceWitnesses, Default: c.cliConfig.Witness.ProduceWitnesses, }) + f.BoolFlag(&flagset.BoolFlag{ + Name: "witness.parallelstatelessimport", + Usage: "Enable parallel stateless block import", + Value: &c.cliConfig.Witness.EnableParallelStatelessImport, + Default: c.cliConfig.Witness.EnableParallelStatelessImport, + }) + f.IntFlag(&flagset.IntFlag{ + Name: "witness.parallelstatelessimportworkers", + Usage: "Number of workers to use for parallel stateless import (0 = GOMAXPROCS)", + Value: &c.cliConfig.Witness.ParallelStatelessImportWorkers, + Default: c.cliConfig.Witness.ParallelStatelessImportWorkers, + }) f.BoolFlag(&flagset.BoolFlag{ Name: "witness.witnessapi", Usage: "Enable witness API endpoints (by default disabled)", diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index e2cc33a39c..a678a89004 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -949,7 +949,13 @@ func DoCall(ctx context.Context, b Backend, args TransactionArgs, blockNrOrHash // can be multiple headers with same number. header, err = b.HeaderByHash(ctx, *blockNrOrHash.BlockHash) if header == nil || err != nil { - log.Warn("Error fetching header on CallWithState", "err", err) + // Suppress warning during parallel stateless import as headers may not be immediately available + // TODO: the ideal way is to avoid relying previous block header post veblop for state sync + if b.IsParallelImportActive() && header == nil { + log.Debug("Header not yet available during parallel stateless import, operation will be retried once headers are imported", "hash", blockNrOrHash.BlockHash, "err", err) + } else { + log.Warn("Error fetching header on CallWithState", "err", err) + } return nil, err } } diff --git a/internal/ethapi/api_test.go b/internal/ethapi/api_test.go index 3da975d138..b7e2be897d 100644 --- a/internal/ethapi/api_test.go +++ b/internal/ethapi/api_test.go @@ -781,6 +781,10 @@ func (b testBackend) HistoryPruningCutoff() uint64 { return bn } +func (b testBackend) IsParallelImportActive() bool { + return false +} + func TestEstimateGas(t *testing.T) { t.Parallel() // Initialize test accounts diff --git a/internal/ethapi/backend.go b/internal/ethapi/backend.go index d8e15caa9e..d066b3bfd8 100644 --- a/internal/ethapi/backend.go +++ b/internal/ethapi/backend.go @@ -130,6 +130,10 @@ type Backend interface { CurrentView() *filtermaps.ChainView NewMatcherBackend() filtermaps.MatcherBackend + + // TODO: remove once we stop relying on previous headers for state sync + // IsParallelImportActive returns true if parallel stateless import is currently active + IsParallelImportActive() bool } func GetAPIs(apiBackend Backend) []rpc.API { diff --git a/internal/ethapi/transaction_args_test.go b/internal/ethapi/transaction_args_test.go index 1ec672030b..4afe6fec89 100644 --- a/internal/ethapi/transaction_args_test.go +++ b/internal/ethapi/transaction_args_test.go @@ -506,3 +506,7 @@ func (b *backendMock) CurrentView() *filtermaps.ChainView { return nil } func (b *backendMock) NewMatcherBackend() filtermaps.MatcherBackend { return nil } func (b *backendMock) HistoryPruningCutoff() uint64 { return 0 } + +func (b *backendMock) IsParallelImportActive() bool { + return false +}