Merge branch 'master' into multicall

This commit is contained in:
Sina Mahmoodi 2024-09-04 16:32:46 +02:00
commit 24151101bb
70 changed files with 1159 additions and 461 deletions

View file

@ -34,6 +34,7 @@ func (e ExecutableData) MarshalJSON() ([]byte, error) {
Withdrawals []*types.Withdrawal `json:"withdrawals"` Withdrawals []*types.Withdrawal `json:"withdrawals"`
BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed"` BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed"`
ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas"` ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas"`
Deposits types.Deposits `json:"depositRequests"`
ExecutionWitness *types.ExecutionWitness `json:"executionWitness,omitempty"` ExecutionWitness *types.ExecutionWitness `json:"executionWitness,omitempty"`
} }
var enc ExecutableData var enc ExecutableData
@ -59,6 +60,7 @@ func (e ExecutableData) MarshalJSON() ([]byte, error) {
enc.Withdrawals = e.Withdrawals enc.Withdrawals = e.Withdrawals
enc.BlobGasUsed = (*hexutil.Uint64)(e.BlobGasUsed) enc.BlobGasUsed = (*hexutil.Uint64)(e.BlobGasUsed)
enc.ExcessBlobGas = (*hexutil.Uint64)(e.ExcessBlobGas) enc.ExcessBlobGas = (*hexutil.Uint64)(e.ExcessBlobGas)
enc.Deposits = e.Deposits
enc.ExecutionWitness = e.ExecutionWitness enc.ExecutionWitness = e.ExecutionWitness
return json.Marshal(&enc) return json.Marshal(&enc)
} }
@ -83,6 +85,7 @@ func (e *ExecutableData) UnmarshalJSON(input []byte) error {
Withdrawals []*types.Withdrawal `json:"withdrawals"` Withdrawals []*types.Withdrawal `json:"withdrawals"`
BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed"` BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed"`
ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas"` ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas"`
Deposits *types.Deposits `json:"depositRequests"`
ExecutionWitness *types.ExecutionWitness `json:"executionWitness,omitempty"` ExecutionWitness *types.ExecutionWitness `json:"executionWitness,omitempty"`
} }
var dec ExecutableData var dec ExecutableData
@ -157,6 +160,9 @@ func (e *ExecutableData) UnmarshalJSON(input []byte) error {
if dec.ExcessBlobGas != nil { if dec.ExcessBlobGas != nil {
e.ExcessBlobGas = (*uint64)(dec.ExcessBlobGas) e.ExcessBlobGas = (*uint64)(dec.ExcessBlobGas)
} }
if dec.Deposits != nil {
e.Deposits = *dec.Deposits
}
if dec.ExecutionWitness != nil { if dec.ExecutionWitness != nil {
e.ExecutionWitness = dec.ExecutionWitness e.ExecutionWitness = dec.ExecutionWitness
} }

View file

@ -36,6 +36,7 @@ var (
PayloadV1 PayloadVersion = 0x1 PayloadV1 PayloadVersion = 0x1
PayloadV2 PayloadVersion = 0x2 PayloadV2 PayloadVersion = 0x2
PayloadV3 PayloadVersion = 0x3 PayloadV3 PayloadVersion = 0x3
PayloadV4 PayloadVersion = 0x4
) )
//go:generate go run github.com/fjl/gencodec -type PayloadAttributes -field-override payloadAttributesMarshaling -out gen_blockparams.go //go:generate go run github.com/fjl/gencodec -type PayloadAttributes -field-override payloadAttributesMarshaling -out gen_blockparams.go
@ -76,6 +77,7 @@ type ExecutableData struct {
Withdrawals []*types.Withdrawal `json:"withdrawals"` Withdrawals []*types.Withdrawal `json:"withdrawals"`
BlobGasUsed *uint64 `json:"blobGasUsed"` BlobGasUsed *uint64 `json:"blobGasUsed"`
ExcessBlobGas *uint64 `json:"excessBlobGas"` ExcessBlobGas *uint64 `json:"excessBlobGas"`
Deposits types.Deposits `json:"depositRequests"`
ExecutionWitness *types.ExecutionWitness `json:"executionWitness,omitempty"` ExecutionWitness *types.ExecutionWitness `json:"executionWitness,omitempty"`
} }
@ -231,6 +233,19 @@ func ExecutableDataToBlock(data ExecutableData, versionedHashes []common.Hash, b
h := types.DeriveSha(types.Withdrawals(data.Withdrawals), trie.NewStackTrie(nil)) h := types.DeriveSha(types.Withdrawals(data.Withdrawals), trie.NewStackTrie(nil))
withdrawalsRoot = &h withdrawalsRoot = &h
} }
// Compute requestsHash if any requests are non-nil.
var (
requestsHash *common.Hash
requests types.Requests
)
if data.Deposits != nil {
requests = make(types.Requests, 0)
for _, d := range data.Deposits {
requests = append(requests, types.NewRequest(d))
}
h := types.DeriveSha(requests, trie.NewStackTrie(nil))
requestsHash = &h
}
header := &types.Header{ header := &types.Header{
ParentHash: data.ParentHash, ParentHash: data.ParentHash,
UncleHash: types.EmptyUncleHash, UncleHash: types.EmptyUncleHash,
@ -251,9 +266,10 @@ func ExecutableDataToBlock(data ExecutableData, versionedHashes []common.Hash, b
ExcessBlobGas: data.ExcessBlobGas, ExcessBlobGas: data.ExcessBlobGas,
BlobGasUsed: data.BlobGasUsed, BlobGasUsed: data.BlobGasUsed,
ParentBeaconRoot: beaconRoot, ParentBeaconRoot: beaconRoot,
RequestsHash: requestsHash,
} }
block := types.NewBlockWithHeader(header) block := types.NewBlockWithHeader(header)
block = block.WithBody(types.Body{Transactions: txs, Uncles: nil, Withdrawals: data.Withdrawals}) block = block.WithBody(types.Body{Transactions: txs, Uncles: nil, Withdrawals: data.Withdrawals, Requests: requests})
block = block.WithWitness(data.ExecutionWitness) block = block.WithWitness(data.ExecutionWitness)
if block.Hash() != data.BlockHash { if block.Hash() != data.BlockHash {
return nil, fmt.Errorf("blockhash mismatch, want %x, got %x", data.BlockHash, block.Hash()) return nil, fmt.Errorf("blockhash mismatch, want %x, got %x", data.BlockHash, block.Hash())
@ -296,13 +312,30 @@ func BlockToExecutableData(block *types.Block, fees *big.Int, sidecars []*types.
bundle.Proofs = append(bundle.Proofs, hexutil.Bytes(sidecar.Proofs[j][:])) bundle.Proofs = append(bundle.Proofs, hexutil.Bytes(sidecar.Proofs[j][:]))
} }
} }
setRequests(block.Requests(), data)
return &ExecutionPayloadEnvelope{ExecutionPayload: data, BlockValue: fees, BlobsBundle: &bundle, Override: false} return &ExecutionPayloadEnvelope{ExecutionPayload: data, BlockValue: fees, BlobsBundle: &bundle, Override: false}
} }
// ExecutionPayloadBodyV1 is used in the response to GetPayloadBodiesByHashV1 and GetPayloadBodiesByRangeV1 // setRequests differentiates the different request types and
type ExecutionPayloadBodyV1 struct { // assigns them to the associated fields in ExecutableData.
func setRequests(requests types.Requests, data *ExecutableData) {
if requests != nil {
// If requests is non-nil, it means deposits are available in block and we
// should return an empty slice instead of nil if there are no deposits.
data.Deposits = make(types.Deposits, 0)
}
for _, r := range requests {
if d, ok := r.Inner().(*types.Deposit); ok {
data.Deposits = append(data.Deposits, d)
}
}
}
// ExecutionPayloadBody is used in the response to GetPayloadBodiesByHash and GetPayloadBodiesByRange
type ExecutionPayloadBody struct {
TransactionData []hexutil.Bytes `json:"transactions"` TransactionData []hexutil.Bytes `json:"transactions"`
Withdrawals []*types.Withdrawal `json:"withdrawals"` Withdrawals []*types.Withdrawal `json:"withdrawals"`
Deposits types.Deposits `json:"depositRequests"`
} }
// Client identifiers to support ClientVersionV1. // Client identifiers to support ClientVersionV1.

View file

@ -66,6 +66,8 @@ type ExecutionResult struct {
WithdrawalsRoot *common.Hash `json:"withdrawalsRoot,omitempty"` WithdrawalsRoot *common.Hash `json:"withdrawalsRoot,omitempty"`
CurrentExcessBlobGas *math.HexOrDecimal64 `json:"currentExcessBlobGas,omitempty"` CurrentExcessBlobGas *math.HexOrDecimal64 `json:"currentExcessBlobGas,omitempty"`
CurrentBlobGasUsed *math.HexOrDecimal64 `json:"blobGasUsed,omitempty"` CurrentBlobGasUsed *math.HexOrDecimal64 `json:"blobGasUsed,omitempty"`
RequestsHash *common.Hash `json:"requestsRoot,omitempty"`
DepositRequests *types.Deposits `json:"depositRequests,omitempty"`
} }
type ommer struct { type ommer struct {
@ -377,6 +379,28 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
execRs.CurrentExcessBlobGas = (*math.HexOrDecimal64)(&excessBlobGas) execRs.CurrentExcessBlobGas = (*math.HexOrDecimal64)(&excessBlobGas)
execRs.CurrentBlobGasUsed = (*math.HexOrDecimal64)(&blobGasUsed) execRs.CurrentBlobGasUsed = (*math.HexOrDecimal64)(&blobGasUsed)
} }
if chainConfig.IsPrague(vmContext.BlockNumber, vmContext.Time) {
// Parse the requests from the logs
var allLogs []*types.Log
for _, receipt := range receipts {
allLogs = append(allLogs, receipt.Logs...)
}
requests, err := core.ParseDepositLogs(allLogs, chainConfig)
if err != nil {
return nil, nil, nil, NewError(ErrorEVM, fmt.Errorf("could not parse requests logs: %v", err))
}
// Calculate the requests root
h := types.DeriveSha(requests, trie.NewStackTrie(nil))
execRs.RequestsHash = &h
// Get the deposits from the requests
deposits := make(types.Deposits, 0)
for _, req := range requests {
if dep, ok := req.Inner().(*types.Deposit); ok {
deposits = append(deposits, dep)
}
}
execRs.DepositRequests = &deposits
}
// Re-create statedb instance with new root upon the updated database // Re-create statedb instance with new root upon the updated database
// for accessing latest states. // for accessing latest states.
statedb, err = state.New(root, statedb.Database(), nil) statedb, err = state.New(root, statedb.Database(), nil)

View file

@ -262,7 +262,6 @@ func ImportHistory(chain *core.BlockChain, db ethdb.Database, dir string, networ
start = time.Now() start = time.Now()
reported = time.Now() reported = time.Now()
imported = 0 imported = 0
forker = core.NewForkChoice(chain, nil)
h = sha256.New() h = sha256.New()
buf = bytes.NewBuffer(nil) buf = bytes.NewBuffer(nil)
) )
@ -305,7 +304,7 @@ func ImportHistory(chain *core.BlockChain, db ethdb.Database, dir string, networ
if err != nil { if err != nil {
return fmt.Errorf("error reading receipts %d: %w", it.Number(), err) return fmt.Errorf("error reading receipts %d: %w", it.Number(), err)
} }
if status, err := chain.HeaderChain().InsertHeaderChain([]*types.Header{block.Header()}, start, forker); err != nil { if status, err := chain.HeaderChain().InsertHeaderChain([]*types.Header{block.Header()}, start); err != nil {
return fmt.Errorf("error inserting header %d: %w", it.Number(), err) return fmt.Errorf("error inserting header %d: %w", it.Number(), err)
} else if status != core.CanonStatTy { } else if status != core.CanonStatTy {
return fmt.Errorf("error inserting header %d, not canon: %v", it.Number(), status) return fmt.Errorf("error inserting header %d, not canon: %v", it.Number(), status)

View file

@ -2210,7 +2210,7 @@ func MakeChain(ctx *cli.Context, stack *node.Node, readonly bool) (*core.BlockCh
} }
} }
// Disable transaction indexing/unindexing by default. // Disable transaction indexing/unindexing by default.
chain, err := core.NewBlockChain(chainDb, cache, gspec, nil, engine, vmcfg, nil, nil) chain, err := core.NewBlockChain(chainDb, cache, gspec, nil, engine, vmcfg, nil)
if err != nil { if err != nil {
Fatalf("Can't create BlockChain: %v", err) Fatalf("Can't create BlockChain: %v", err)
} }

View file

@ -78,7 +78,7 @@ func TestHistoryImportAndExport(t *testing.T) {
}) })
// Initialize BlockChain. // Initialize BlockChain.
chain, err := core.NewBlockChain(db, nil, genesis, nil, ethash.NewFaker(), vm.Config{}, nil, nil) chain, err := core.NewBlockChain(db, nil, genesis, nil, ethash.NewFaker(), vm.Config{}, nil)
if err != nil { if err != nil {
t.Fatalf("unable to initialize chain: %v", err) t.Fatalf("unable to initialize chain: %v", err)
} }
@ -171,7 +171,7 @@ func TestHistoryImportAndExport(t *testing.T) {
}) })
genesis.MustCommit(db2, triedb.NewDatabase(db, triedb.HashDefaults)) genesis.MustCommit(db2, triedb.NewDatabase(db, triedb.HashDefaults))
imported, err := core.NewBlockChain(db2, nil, genesis, nil, ethash.NewFaker(), vm.Config{}, nil, nil) imported, err := core.NewBlockChain(db2, nil, genesis, nil, ethash.NewFaker(), vm.Config{}, nil)
if err != nil { if err != nil {
t.Fatalf("unable to initialize chain: %v", err) t.Fatalf("unable to initialize chain: %v", err)
} }

View file

@ -55,7 +55,7 @@ func TestReimportMirroredState(t *testing.T) {
copy(genspec.ExtraData[extraVanity:], addr[:]) copy(genspec.ExtraData[extraVanity:], addr[:])
// Generate a batch of blocks, each properly signed // Generate a batch of blocks, each properly signed
chain, _ := core.NewBlockChain(rawdb.NewMemoryDatabase(), nil, genspec, nil, engine, vm.Config{}, nil, nil) chain, _ := core.NewBlockChain(rawdb.NewMemoryDatabase(), nil, genspec, nil, engine, vm.Config{}, nil)
defer chain.Stop() defer chain.Stop()
_, blocks, _ := core.GenerateChainWithGenesis(genspec, engine, 3, func(i int, block *core.BlockGen) { _, blocks, _ := core.GenerateChainWithGenesis(genspec, engine, 3, func(i int, block *core.BlockGen) {
@ -87,7 +87,7 @@ func TestReimportMirroredState(t *testing.T) {
} }
// Insert the first two blocks and make sure the chain is valid // Insert the first two blocks and make sure the chain is valid
db = rawdb.NewMemoryDatabase() db = rawdb.NewMemoryDatabase()
chain, _ = core.NewBlockChain(db, nil, genspec, nil, engine, vm.Config{}, nil, nil) chain, _ = core.NewBlockChain(db, nil, genspec, nil, engine, vm.Config{}, nil)
defer chain.Stop() defer chain.Stop()
if _, err := chain.InsertChain(blocks[:2]); err != nil { if _, err := chain.InsertChain(blocks[:2]); err != nil {
@ -100,7 +100,7 @@ func TestReimportMirroredState(t *testing.T) {
// Simulate a crash by creating a new chain on top of the database, without // Simulate a crash by creating a new chain on top of the database, without
// flushing the dirty states out. Insert the last block, triggering a sidechain // flushing the dirty states out. Insert the last block, triggering a sidechain
// reimport. // reimport.
chain, _ = core.NewBlockChain(db, nil, genspec, nil, engine, vm.Config{}, nil, nil) chain, _ = core.NewBlockChain(db, nil, genspec, nil, engine, vm.Config{}, nil)
defer chain.Stop() defer chain.Stop()
if _, err := chain.InsertChain(blocks[2:]); err != nil { if _, err := chain.InsertChain(blocks[2:]); err != nil {

View file

@ -458,7 +458,7 @@ func (tt *cliqueTest) run(t *testing.T) {
batches[len(batches)-1] = append(batches[len(batches)-1], block) batches[len(batches)-1] = append(batches[len(batches)-1], block)
} }
// Pass all the headers through clique and ensure tallying succeeds // Pass all the headers through clique and ensure tallying succeeds
chain, err := core.NewBlockChain(rawdb.NewMemoryDatabase(), nil, genesis, nil, engine, vm.Config{}, nil, nil) chain, err := core.NewBlockChain(rawdb.NewMemoryDatabase(), nil, genesis, nil, engine, vm.Config{}, nil)
if err != nil { if err != nil {
t.Fatalf("failed to create test chain: %v", err) t.Fatalf("failed to create test chain: %v", err)
} }

View file

@ -195,7 +195,7 @@ func benchInsertChain(b *testing.B, disk bool, gen func(int, *BlockGen)) {
// Time the insertion of the new chain. // Time the insertion of the new chain.
// State and blocks are stored in the same DB. // State and blocks are stored in the same DB.
chainman, _ := NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) chainman, _ := NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil)
defer chainman.Stop() defer chainman.Stop()
b.ReportAllocs() b.ReportAllocs()
b.ResetTimer() b.ResetTimer()
@ -312,7 +312,7 @@ func benchReadChain(b *testing.B, full bool, count uint64) {
if err != nil { if err != nil {
b.Fatalf("error opening database at %v: %v", dir, err) b.Fatalf("error opening database at %v: %v", dir, err)
} }
chain, err := NewBlockChain(db, &cacheConfig, genesis, nil, ethash.NewFaker(), vm.Config{}, nil, nil) chain, err := NewBlockChain(db, &cacheConfig, genesis, nil, ethash.NewFaker(), vm.Config{}, nil)
if err != nil { if err != nil {
b.Fatalf("error creating chain: %v", err) b.Fatalf("error creating chain: %v", err)
} }

View file

@ -121,14 +121,17 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error {
// ValidateState validates the various changes that happen after a state transition, // ValidateState validates the various changes that happen after a state transition,
// such as amount of used gas, the receipt roots and the state root itself. // such as amount of used gas, the receipt roots and the state root itself.
func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateDB, receipts types.Receipts, usedGas uint64, stateless bool) error { func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateDB, res *ProcessResult, stateless bool) error {
if res == nil {
return fmt.Errorf("nil ProcessResult value")
}
header := block.Header() header := block.Header()
if block.GasUsed() != usedGas { if block.GasUsed() != res.GasUsed {
return fmt.Errorf("invalid gas used (remote: %d local: %d)", block.GasUsed(), usedGas) return fmt.Errorf("invalid gas used (remote: %d local: %d)", block.GasUsed(), res.GasUsed)
} }
// Validate the received block's bloom with the one derived from the generated receipts. // Validate the received block's bloom with the one derived from the generated receipts.
// For valid blocks this should always validate to true. // For valid blocks this should always validate to true.
rbloom := types.CreateBloom(receipts) rbloom := types.CreateBloom(res.Receipts)
if rbloom != header.Bloom { if rbloom != header.Bloom {
return fmt.Errorf("invalid bloom (remote: %x local: %x)", header.Bloom, rbloom) return fmt.Errorf("invalid bloom (remote: %x local: %x)", header.Bloom, rbloom)
} }
@ -138,10 +141,17 @@ func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateD
return nil return nil
} }
// The receipt Trie's root (R = (Tr [[H1, R1], ... [Hn, Rn]])) // The receipt Trie's root (R = (Tr [[H1, R1], ... [Hn, Rn]]))
receiptSha := types.DeriveSha(receipts, trie.NewStackTrie(nil)) receiptSha := types.DeriveSha(res.Receipts, trie.NewStackTrie(nil))
if receiptSha != header.ReceiptHash { if receiptSha != header.ReceiptHash {
return fmt.Errorf("invalid receipt root hash (remote: %x local: %x)", header.ReceiptHash, receiptSha) return fmt.Errorf("invalid receipt root hash (remote: %x local: %x)", header.ReceiptHash, receiptSha)
} }
// Validate the parsed requests match the expected header value.
if header.RequestsHash != nil {
depositSha := types.DeriveSha(res.Requests, trie.NewStackTrie(nil))
if depositSha != *header.RequestsHash {
return fmt.Errorf("invalid deposit root hash (remote: %x local: %x)", *header.RequestsHash, depositSha)
}
}
// Validate the state root against the received state root and throw // Validate the state root against the received state root and throw
// an error if they don't match. // an error if they don't match.
if root := statedb.IntermediateRoot(v.config.IsEIP158(header.Number)); header.Root != root { if root := statedb.IntermediateRoot(v.config.IsEIP158(header.Number)); header.Root != root {

View file

@ -50,7 +50,7 @@ func testHeaderVerification(t *testing.T, scheme string) {
headers[i] = block.Header() headers[i] = block.Header()
} }
// Run the header checker for blocks one-by-one, checking for both valid and invalid nonces // Run the header checker for blocks one-by-one, checking for both valid and invalid nonces
chain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) chain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil)
defer chain.Stop() defer chain.Stop()
for i := 0; i < len(blocks); i++ { for i := 0; i < len(blocks); i++ {
@ -160,7 +160,7 @@ func testHeaderVerificationForMerging(t *testing.T, isClique bool) {
postHeaders[i] = block.Header() postHeaders[i] = block.Header()
} }
// Run the header checker for blocks one-by-one, checking for both valid and invalid nonces // Run the header checker for blocks one-by-one, checking for both valid and invalid nonces
chain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{}, nil, nil) chain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{}, nil)
defer chain.Stop() defer chain.Stop()
// Verify the blocks before the merging // Verify the blocks before the merging

View file

@ -259,7 +259,6 @@ type BlockChain struct {
validator Validator // Block and state validator interface validator Validator // Block and state validator interface
prefetcher Prefetcher prefetcher Prefetcher
processor Processor // Block transaction processor interface processor Processor // Block transaction processor interface
forker *ForkChoice
vmConfig vm.Config vmConfig vm.Config
logger *tracing.Hooks logger *tracing.Hooks
} }
@ -267,7 +266,7 @@ type BlockChain struct {
// NewBlockChain returns a fully initialised block chain using information // NewBlockChain returns a fully initialised block chain using information
// available in the database. It initialises the default Ethereum Validator // available in the database. It initialises the default Ethereum Validator
// and Processor. // and Processor.
func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis, overrides *ChainOverrides, engine consensus.Engine, vmConfig vm.Config, shouldPreserve func(header *types.Header) bool, txLookupLimit *uint64) (*BlockChain, error) { func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis, overrides *ChainOverrides, engine consensus.Engine, vmConfig vm.Config, txLookupLimit *uint64) (*BlockChain, error) {
if cacheConfig == nil { if cacheConfig == nil {
cacheConfig = defaultCacheConfig cacheConfig = defaultCacheConfig
} }
@ -312,7 +311,6 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
return nil, err return nil, err
} }
bc.flushInterval.Store(int64(cacheConfig.TrieTimeLimit)) bc.flushInterval.Store(int64(cacheConfig.TrieTimeLimit))
bc.forker = NewForkChoice(bc, shouldPreserve)
bc.stateCache = state.NewDatabaseWithNodeDB(bc.db, bc.triedb) bc.stateCache = state.NewDatabaseWithNodeDB(bc.db, bc.triedb)
bc.validator = NewBlockValidator(chainConfig, bc) bc.validator = NewBlockValidator(chainConfig, bc)
bc.prefetcher = newStatePrefetcher(chainConfig, bc.hc) bc.prefetcher = newStatePrefetcher(chainConfig, bc.hc)
@ -1243,13 +1241,6 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [
// Rewind may have occurred, skip in that case. // Rewind may have occurred, skip in that case.
if bc.CurrentHeader().Number.Cmp(head.Number()) >= 0 { if bc.CurrentHeader().Number.Cmp(head.Number()) >= 0 {
reorg, err := bc.forker.ReorgNeeded(bc.CurrentSnapBlock(), head.Header())
if err != nil {
log.Warn("Reorg failed", "err", err)
return false
} else if !reorg {
return false
}
rawdb.WriteHeadFastBlockHash(bc.db, head.Hash()) rawdb.WriteHeadFastBlockHash(bc.db, head.Hash())
bc.currentSnapBlock.Store(head.Header()) bc.currentSnapBlock.Store(head.Header())
headFastBlockGauge.Update(int64(head.NumberU64())) headFastBlockGauge.Update(int64(head.NumberU64()))
@ -1548,26 +1539,17 @@ func (bc *BlockChain) writeBlockAndSetHead(block *types.Block, receipts []*types
return NonStatTy, err return NonStatTy, err
} }
currentBlock := bc.CurrentBlock() currentBlock := bc.CurrentBlock()
reorg, err := bc.forker.ReorgNeeded(currentBlock, block.Header())
if err != nil {
return NonStatTy, err
}
if reorg {
// Reorganise the chain if the parent is not the head block // Reorganise the chain if the parent is not the head block
if block.ParentHash() != currentBlock.Hash() { if block.ParentHash() != currentBlock.Hash() {
if err := bc.reorg(currentBlock, block); err != nil { if err := bc.reorg(currentBlock, block); err != nil {
return NonStatTy, err return NonStatTy, err
} }
} }
status = CanonStatTy
} else {
status = SideStatTy
}
// Set new head. // Set new head.
if status == CanonStatTy {
bc.writeHeadBlock(block) bc.writeHeadBlock(block)
}
if status == CanonStatTy {
bc.chainFeed.Send(ChainEvent{Block: block, Hash: block.Hash(), Logs: logs}) bc.chainFeed.Send(ChainEvent{Block: block, Hash: block.Hash(), Logs: logs})
if len(logs) > 0 { if len(logs) > 0 {
bc.logsFeed.Send(logs) bc.logsFeed.Send(logs)
@ -1580,10 +1562,7 @@ func (bc *BlockChain) writeBlockAndSetHead(block *types.Block, receipts []*types
if emitHeadEvent { if emitHeadEvent {
bc.chainHeadFeed.Send(ChainHeadEvent{Block: block}) bc.chainHeadFeed.Send(ChainHeadEvent{Block: block})
} }
} else { return CanonStatTy, nil
bc.chainSideFeed.Send(ChainSideEvent{Block: block})
}
return status, nil
} }
// InsertChain attempts to insert the given batch of blocks in to the canonical // InsertChain attempts to insert the given batch of blocks in to the canonical
@ -1634,7 +1613,6 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
if bc.insertStopped() { if bc.insertStopped() {
return 0, nil return 0, nil
} }
// Start a parallel signature recovery (signer will fluke on fork transition, minimal perf loss) // Start a parallel signature recovery (signer will fluke on fork transition, minimal perf loss)
SenderCacher.RecoverFromBlocks(types.MakeSigner(bc.chainConfig, chain[0].Number(), chain[0].Time()), chain) SenderCacher.RecoverFromBlocks(types.MakeSigner(bc.chainConfig, chain[0].Number(), chain[0].Time()), chain)
@ -1667,25 +1645,11 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
// 2. The block is stored as a sidechain, and is lying about it's stateroot, and passes a stateroot // 2. The block is stored as a sidechain, and is lying about it's stateroot, and passes a stateroot
// from the canonical chain, which has not been verified. // from the canonical chain, which has not been verified.
// Skip all known blocks that are behind us. // Skip all known blocks that are behind us.
var ( current := bc.CurrentBlock()
reorg bool
current = bc.CurrentBlock()
)
for block != nil && bc.skipBlock(err, it) { for block != nil && bc.skipBlock(err, it) {
reorg, err = bc.forker.ReorgNeeded(current, block.Header())
if err != nil {
return it.index, err
}
if reorg {
// Switch to import mode if the forker says the reorg is necessary
// and also the block is not on the canonical chain.
// In eth2 the forker always returns true for reorg decision (blindly trusting
// the external consensus engine), but in order to prevent the unnecessary
// reorgs when importing known blocks, the special case is handled here.
if block.NumberU64() > current.Number.Uint64() || bc.GetCanonicalHash(block.NumberU64()) != block.Hash() { if block.NumberU64() > current.Number.Uint64() || bc.GetCanonicalHash(block.NumberU64()) != block.Hash() {
break break
} }
}
log.Debug("Ignoring already known block", "number", block.Number(), "hash", block.Hash()) log.Debug("Ignoring already known block", "number", block.Number(), "hash", block.Hash())
stats.ignored++ stats.ignored++
@ -1927,23 +1891,23 @@ func (bc *BlockChain) processBlock(block *types.Block, statedb *state.StateDB, s
// Process block using the parent state as reference point // Process block using the parent state as reference point
pstart := time.Now() pstart := time.Now()
receipts, logs, usedGas, err := bc.processor.Process(block, statedb, bc.vmConfig) res, err := bc.processor.Process(block, statedb, bc.vmConfig)
if err != nil { if err != nil {
bc.reportBlock(block, receipts, err) bc.reportBlock(block, res, err)
return nil, err return nil, err
} }
ptime := time.Since(pstart) ptime := time.Since(pstart)
vstart := time.Now() vstart := time.Now()
if err := bc.validator.ValidateState(block, statedb, receipts, usedGas, false); err != nil { if err := bc.validator.ValidateState(block, statedb, res, false); err != nil {
bc.reportBlock(block, receipts, err) bc.reportBlock(block, res, err)
return nil, err return nil, err
} }
vtime := time.Since(vstart) vtime := time.Since(vstart)
if witness := statedb.Witness(); witness != nil { if witness := statedb.Witness(); witness != nil {
if err = bc.validator.ValidateWitness(witness, block.ReceiptHash(), block.Root()); err != nil { if err = bc.validator.ValidateWitness(witness, block.ReceiptHash(), block.Root()); err != nil {
bc.reportBlock(block, receipts, err) bc.reportBlock(block, res, err)
return nil, fmt.Errorf("cross verification failed: %v", err) return nil, fmt.Errorf("cross verification failed: %v", err)
} }
} }
@ -1978,9 +1942,9 @@ func (bc *BlockChain) processBlock(block *types.Block, statedb *state.StateDB, s
) )
if !setHead { if !setHead {
// Don't set the head, only insert the block // Don't set the head, only insert the block
err = bc.writeBlockWithState(block, receipts, statedb) err = bc.writeBlockWithState(block, res.Receipts, statedb)
} else { } else {
status, err = bc.writeBlockAndSetHead(block, receipts, logs, statedb, false) status, err = bc.writeBlockAndSetHead(block, res.Receipts, res.Logs, statedb, false)
} }
if err != nil { if err != nil {
return nil, err return nil, err
@ -1994,7 +1958,7 @@ func (bc *BlockChain) processBlock(block *types.Block, statedb *state.StateDB, s
blockWriteTimer.Update(time.Since(wstart) - max(statedb.AccountCommits, statedb.StorageCommits) /* concurrent */ - statedb.SnapshotCommits - statedb.TrieDBCommits) blockWriteTimer.Update(time.Since(wstart) - max(statedb.AccountCommits, statedb.StorageCommits) /* concurrent */ - statedb.SnapshotCommits - statedb.TrieDBCommits)
blockInsertTimer.UpdateSince(start) blockInsertTimer.UpdateSince(start)
return &blockProcessingResult{usedGas: usedGas, procTime: proctime, status: status}, nil return &blockProcessingResult{usedGas: res.GasUsed, procTime: proctime, status: status}, nil
} }
// insertSideChain is called when an import batch hits upon a pruned ancestor // insertSideChain is called when an import batch hits upon a pruned ancestor
@ -2007,7 +1971,6 @@ func (bc *BlockChain) processBlock(block *types.Block, statedb *state.StateDB, s
func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator) (int, error) { func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator) (int, error) {
var ( var (
externTd *big.Int externTd *big.Int
lastBlock = block
current = bc.CurrentBlock() current = bc.CurrentBlock()
) )
// The first sidechain block error is already verified to be ErrPrunedAncestor. // The first sidechain block error is already verified to be ErrPrunedAncestor.
@ -2059,22 +2022,6 @@ func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator) (i
"txs", len(block.Transactions()), "gas", block.GasUsed(), "uncles", len(block.Uncles()), "txs", len(block.Transactions()), "gas", block.GasUsed(), "uncles", len(block.Uncles()),
"root", block.Root()) "root", block.Root())
} }
lastBlock = block
}
// At this point, we've written all sidechain blocks to database. Loop ended
// either on some other error or all were processed. If there was some other
// error, we can ignore the rest of those blocks.
//
// If the externTd was larger than our local TD, we now need to reimport the previous
// blocks to regenerate the required state
reorg, err := bc.forker.ReorgNeeded(current, lastBlock.Header())
if err != nil {
return it.index, err
}
if !reorg {
localTd := bc.GetTd(current.Hash(), current.Number.Uint64())
log.Info("Sidechain written to disk", "start", it.first().NumberU64(), "end", it.previous().Number, "sidetd", externTd, "localtd", localTd)
return it.index, err
} }
// Gather all the sidechain hashes (full blocks may be memory heavy) // Gather all the sidechain hashes (full blocks may be memory heavy)
var ( var (
@ -2491,7 +2438,11 @@ func (bc *BlockChain) skipBlock(err error, it *insertIterator) bool {
} }
// reportBlock logs a bad block error. // reportBlock logs a bad block error.
func (bc *BlockChain) reportBlock(block *types.Block, receipts types.Receipts, err error) { func (bc *BlockChain) reportBlock(block *types.Block, res *ProcessResult, err error) {
var receipts types.Receipts
if res != nil {
receipts = res.Receipts
}
rawdb.WriteBadBlock(bc.db, block) rawdb.WriteBadBlock(bc.db, block)
log.Error(summarizeBadBlock(block, receipts, bc.Config(), err)) log.Error(summarizeBadBlock(block, receipts, bc.Config(), err))
} }
@ -2537,7 +2488,7 @@ func (bc *BlockChain) InsertHeaderChain(chain []*types.Header) (int, error) {
return 0, errChainStopped return 0, errChainStopped
} }
defer bc.chainmu.Unlock() defer bc.chainmu.Unlock()
_, err := bc.hc.InsertHeaderChain(chain, start, bc.forker) _, err := bc.hc.InsertHeaderChain(chain, start)
return 0, err return 0, err
} }

View file

@ -170,11 +170,6 @@ func (it *insertIterator) current() *types.Header {
return it.chain[it.index].Header() return it.chain[it.index].Header()
} }
// first returns the first block in it.
func (it *insertIterator) first() *types.Block {
return it.chain[0]
}
// remaining returns the number of remaining blocks. // remaining returns the number of remaining blocks.
func (it *insertIterator) remaining() int { func (it *insertIterator) remaining() int {
return len(it.chain) - it.index return len(it.chain) - it.index

View file

@ -1794,7 +1794,7 @@ func testRepairWithScheme(t *testing.T, tt *rewindTest, snapshots bool, scheme s
config.SnapshotLimit = 256 config.SnapshotLimit = 256
config.SnapshotWait = true config.SnapshotWait = true
} }
chain, err := NewBlockChain(db, config, gspec, nil, engine, vm.Config{}, nil, nil) chain, err := NewBlockChain(db, config, gspec, nil, engine, vm.Config{}, nil)
if err != nil { if err != nil {
t.Fatalf("Failed to create chain: %v", err) t.Fatalf("Failed to create chain: %v", err)
} }
@ -1859,7 +1859,7 @@ func testRepairWithScheme(t *testing.T, tt *rewindTest, snapshots bool, scheme s
} }
defer db.Close() defer db.Close()
newChain, err := NewBlockChain(db, config, gspec, nil, engine, vm.Config{}, nil, nil) newChain, err := NewBlockChain(db, config, gspec, nil, engine, vm.Config{}, nil)
if err != nil { if err != nil {
t.Fatalf("Failed to recreate chain: %v", err) t.Fatalf("Failed to recreate chain: %v", err)
} }
@ -1931,7 +1931,7 @@ func testIssue23496(t *testing.T, scheme string) {
} }
engine = ethash.NewFullFaker() engine = ethash.NewFullFaker()
) )
chain, err := NewBlockChain(db, DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{}, nil, nil) chain, err := NewBlockChain(db, DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{}, nil)
if err != nil { if err != nil {
t.Fatalf("Failed to create chain: %v", err) t.Fatalf("Failed to create chain: %v", err)
} }
@ -1981,7 +1981,7 @@ func testIssue23496(t *testing.T, scheme string) {
} }
defer db.Close() defer db.Close()
chain, err = NewBlockChain(db, DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{}, nil, nil) chain, err = NewBlockChain(db, DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{}, nil)
if err != nil { if err != nil {
t.Fatalf("Failed to recreate chain: %v", err) t.Fatalf("Failed to recreate chain: %v", err)
} }

View file

@ -1997,7 +1997,7 @@ func testSetHeadWithScheme(t *testing.T, tt *rewindTest, snapshots bool, scheme
config.SnapshotLimit = 256 config.SnapshotLimit = 256
config.SnapshotWait = true config.SnapshotWait = true
} }
chain, err := NewBlockChain(db, config, gspec, nil, engine, vm.Config{}, nil, nil) chain, err := NewBlockChain(db, config, gspec, nil, engine, vm.Config{}, nil)
if err != nil { if err != nil {
t.Fatalf("Failed to create chain: %v", err) t.Fatalf("Failed to create chain: %v", err)
} }

View file

@ -81,7 +81,7 @@ func (basic *snapshotTestBasic) prepare(t *testing.T) (*BlockChain, []*types.Blo
} }
engine = ethash.NewFullFaker() engine = ethash.NewFullFaker()
) )
chain, err := NewBlockChain(db, DefaultCacheConfigWithScheme(basic.scheme), gspec, nil, engine, vm.Config{}, nil, nil) chain, err := NewBlockChain(db, DefaultCacheConfigWithScheme(basic.scheme), gspec, nil, engine, vm.Config{}, nil)
if err != nil { if err != nil {
t.Fatalf("Failed to create chain: %v", err) t.Fatalf("Failed to create chain: %v", err)
} }
@ -228,7 +228,7 @@ func (snaptest *snapshotTest) test(t *testing.T) {
// Restart the chain normally // Restart the chain normally
chain.Stop() chain.Stop()
newchain, err := NewBlockChain(snaptest.db, DefaultCacheConfigWithScheme(snaptest.scheme), snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil) newchain, err := NewBlockChain(snaptest.db, DefaultCacheConfigWithScheme(snaptest.scheme), snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil)
if err != nil { if err != nil {
t.Fatalf("Failed to recreate chain: %v", err) t.Fatalf("Failed to recreate chain: %v", err)
} }
@ -270,13 +270,13 @@ func (snaptest *crashSnapshotTest) test(t *testing.T) {
// the crash, we do restart twice here: one after the crash and one // the crash, we do restart twice here: one after the crash and one
// after the normal stop. It's used to ensure the broken snapshot // after the normal stop. It's used to ensure the broken snapshot
// can be detected all the time. // can be detected all the time.
newchain, err := NewBlockChain(newdb, DefaultCacheConfigWithScheme(snaptest.scheme), snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil) newchain, err := NewBlockChain(newdb, DefaultCacheConfigWithScheme(snaptest.scheme), snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil)
if err != nil { if err != nil {
t.Fatalf("Failed to recreate chain: %v", err) t.Fatalf("Failed to recreate chain: %v", err)
} }
newchain.Stop() newchain.Stop()
newchain, err = NewBlockChain(newdb, DefaultCacheConfigWithScheme(snaptest.scheme), snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil) newchain, err = NewBlockChain(newdb, DefaultCacheConfigWithScheme(snaptest.scheme), snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil)
if err != nil { if err != nil {
t.Fatalf("Failed to recreate chain: %v", err) t.Fatalf("Failed to recreate chain: %v", err)
} }
@ -313,7 +313,7 @@ func (snaptest *gappedSnapshotTest) test(t *testing.T) {
SnapshotLimit: 0, SnapshotLimit: 0,
StateScheme: snaptest.scheme, StateScheme: snaptest.scheme,
} }
newchain, err := NewBlockChain(snaptest.db, cacheConfig, snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil) newchain, err := NewBlockChain(snaptest.db, cacheConfig, snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil)
if err != nil { if err != nil {
t.Fatalf("Failed to recreate chain: %v", err) t.Fatalf("Failed to recreate chain: %v", err)
} }
@ -321,7 +321,7 @@ func (snaptest *gappedSnapshotTest) test(t *testing.T) {
newchain.Stop() newchain.Stop()
// Restart the chain with enabling the snapshot // Restart the chain with enabling the snapshot
newchain, err = NewBlockChain(snaptest.db, DefaultCacheConfigWithScheme(snaptest.scheme), snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil) newchain, err = NewBlockChain(snaptest.db, DefaultCacheConfigWithScheme(snaptest.scheme), snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil)
if err != nil { if err != nil {
t.Fatalf("Failed to recreate chain: %v", err) t.Fatalf("Failed to recreate chain: %v", err)
} }
@ -349,7 +349,7 @@ func (snaptest *setHeadSnapshotTest) test(t *testing.T) {
chain.SetHead(snaptest.setHead) chain.SetHead(snaptest.setHead)
chain.Stop() chain.Stop()
newchain, err := NewBlockChain(snaptest.db, DefaultCacheConfigWithScheme(snaptest.scheme), snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil) newchain, err := NewBlockChain(snaptest.db, DefaultCacheConfigWithScheme(snaptest.scheme), snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil)
if err != nil { if err != nil {
t.Fatalf("Failed to recreate chain: %v", err) t.Fatalf("Failed to recreate chain: %v", err)
} }
@ -385,7 +385,7 @@ func (snaptest *wipeCrashSnapshotTest) test(t *testing.T) {
SnapshotLimit: 0, SnapshotLimit: 0,
StateScheme: snaptest.scheme, StateScheme: snaptest.scheme,
} }
newchain, err := NewBlockChain(snaptest.db, config, snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil) newchain, err := NewBlockChain(snaptest.db, config, snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil)
if err != nil { if err != nil {
t.Fatalf("Failed to recreate chain: %v", err) t.Fatalf("Failed to recreate chain: %v", err)
} }
@ -402,7 +402,7 @@ func (snaptest *wipeCrashSnapshotTest) test(t *testing.T) {
SnapshotWait: false, // Don't wait rebuild SnapshotWait: false, // Don't wait rebuild
StateScheme: snaptest.scheme, StateScheme: snaptest.scheme,
} }
tmp, err := NewBlockChain(snaptest.db, config, snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil) tmp, err := NewBlockChain(snaptest.db, config, snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil)
if err != nil { if err != nil {
t.Fatalf("Failed to recreate chain: %v", err) t.Fatalf("Failed to recreate chain: %v", err)
} }
@ -411,7 +411,7 @@ func (snaptest *wipeCrashSnapshotTest) test(t *testing.T) {
tmp.triedb.Close() tmp.triedb.Close()
tmp.stopWithoutSaving() tmp.stopWithoutSaving()
newchain, err = NewBlockChain(snaptest.db, DefaultCacheConfigWithScheme(snaptest.scheme), snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil) newchain, err = NewBlockChain(snaptest.db, DefaultCacheConfigWithScheme(snaptest.scheme), snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil)
if err != nil { if err != nil {
t.Fatalf("Failed to recreate chain: %v", err) t.Fatalf("Failed to recreate chain: %v", err)
} }

View file

@ -22,6 +22,7 @@ import (
"math/big" "math/big"
"math/rand" "math/rand"
"os" "os"
"path"
"sync" "sync"
"testing" "testing"
"time" "time"
@ -61,7 +62,7 @@ func newCanonical(engine consensus.Engine, n int, full bool, scheme string) (eth
} }
) )
// Initialize a fresh chain with only a genesis block // Initialize a fresh chain with only a genesis block
blockchain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil, nil) blockchain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil)
// Create and inject the requested chain // Create and inject the requested chain
if n == 0 { if n == 0 {
@ -163,13 +164,14 @@ func testBlockChainImport(chain types.Blocks, blockchain *BlockChain) error {
if err != nil { if err != nil {
return err return err
} }
receipts, _, usedGas, err := blockchain.processor.Process(block, statedb, vm.Config{}) res, err := blockchain.processor.Process(block, statedb, vm.Config{})
if err != nil { if err != nil {
blockchain.reportBlock(block, receipts, err) blockchain.reportBlock(block, res, err)
return err return err
} }
if err = blockchain.validator.ValidateState(block, statedb, receipts, usedGas, false); err != nil { err = blockchain.validator.ValidateState(block, statedb, res, false)
blockchain.reportBlock(block, receipts, err) if err != nil {
blockchain.reportBlock(block, res, err)
return err return err
} }
@ -762,7 +764,7 @@ func testFastVsFullChains(t *testing.T, scheme string) {
}) })
// Import the chain as an archive node for the comparison baseline // Import the chain as an archive node for the comparison baseline
archiveDb := rawdb.NewMemoryDatabase() archiveDb := rawdb.NewMemoryDatabase()
archive, _ := NewBlockChain(archiveDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) archive, _ := NewBlockChain(archiveDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil)
defer archive.Stop() defer archive.Stop()
if n, err := archive.InsertChain(blocks); err != nil { if n, err := archive.InsertChain(blocks); err != nil {
@ -770,7 +772,7 @@ func testFastVsFullChains(t *testing.T, scheme string) {
} }
// Fast import the chain as a non-archive node to test // Fast import the chain as a non-archive node to test
fastDb := rawdb.NewMemoryDatabase() fastDb := rawdb.NewMemoryDatabase()
fast, _ := NewBlockChain(fastDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) fast, _ := NewBlockChain(fastDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil)
defer fast.Stop() defer fast.Stop()
headers := make([]*types.Header, len(blocks)) headers := make([]*types.Header, len(blocks))
@ -790,7 +792,7 @@ func testFastVsFullChains(t *testing.T, scheme string) {
} }
defer ancientDb.Close() defer ancientDb.Close()
ancient, _ := NewBlockChain(ancientDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) ancient, _ := NewBlockChain(ancientDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil)
defer ancient.Stop() defer ancient.Stop()
if n, err := ancient.InsertHeaderChain(headers); err != nil { if n, err := ancient.InsertHeaderChain(headers); err != nil {
@ -910,7 +912,7 @@ func testLightVsFastVsFullChainHeads(t *testing.T, scheme string) {
archiveCaching.TrieDirtyDisabled = true archiveCaching.TrieDirtyDisabled = true
archiveCaching.StateScheme = scheme archiveCaching.StateScheme = scheme
archive, _ := NewBlockChain(archiveDb, &archiveCaching, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) archive, _ := NewBlockChain(archiveDb, &archiveCaching, gspec, nil, ethash.NewFaker(), vm.Config{}, nil)
if n, err := archive.InsertChain(blocks); err != nil { if n, err := archive.InsertChain(blocks); err != nil {
t.Fatalf("failed to process block %d: %v", n, err) t.Fatalf("failed to process block %d: %v", n, err)
} }
@ -923,7 +925,7 @@ func testLightVsFastVsFullChainHeads(t *testing.T, scheme string) {
// Import the chain as a non-archive node and ensure all pointers are updated // Import the chain as a non-archive node and ensure all pointers are updated
fastDb := makeDb() fastDb := makeDb()
defer fastDb.Close() defer fastDb.Close()
fast, _ := NewBlockChain(fastDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) fast, _ := NewBlockChain(fastDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil)
defer fast.Stop() defer fast.Stop()
headers := make([]*types.Header, len(blocks)) headers := make([]*types.Header, len(blocks))
@ -943,7 +945,7 @@ func testLightVsFastVsFullChainHeads(t *testing.T, scheme string) {
// Import the chain as a ancient-first node and ensure all pointers are updated // Import the chain as a ancient-first node and ensure all pointers are updated
ancientDb := makeDb() ancientDb := makeDb()
defer ancientDb.Close() defer ancientDb.Close()
ancient, _ := NewBlockChain(ancientDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) ancient, _ := NewBlockChain(ancientDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil)
defer ancient.Stop() defer ancient.Stop()
if n, err := ancient.InsertHeaderChain(headers); err != nil { if n, err := ancient.InsertHeaderChain(headers); err != nil {
@ -962,7 +964,7 @@ func testLightVsFastVsFullChainHeads(t *testing.T, scheme string) {
// Import the chain as a light node and ensure all pointers are updated // Import the chain as a light node and ensure all pointers are updated
lightDb := makeDb() lightDb := makeDb()
defer lightDb.Close() defer lightDb.Close()
light, _ := NewBlockChain(lightDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) light, _ := NewBlockChain(lightDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil)
if n, err := light.InsertHeaderChain(headers); err != nil { if n, err := light.InsertHeaderChain(headers); err != nil {
t.Fatalf("failed to insert header %d: %v", n, err) t.Fatalf("failed to insert header %d: %v", n, err)
} }
@ -1035,7 +1037,7 @@ func testChainTxReorgs(t *testing.T, scheme string) {
}) })
// Import the chain. This runs all block validation rules. // Import the chain. This runs all block validation rules.
db := rawdb.NewMemoryDatabase() db := rawdb.NewMemoryDatabase()
blockchain, _ := NewBlockChain(db, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) blockchain, _ := NewBlockChain(db, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil)
if i, err := blockchain.InsertChain(chain); err != nil { if i, err := blockchain.InsertChain(chain); err != nil {
t.Fatalf("failed to insert original chain[%d]: %v", i, err) t.Fatalf("failed to insert original chain[%d]: %v", i, err)
} }
@ -1109,7 +1111,7 @@ func testLogReorgs(t *testing.T, scheme string) {
signer = types.LatestSigner(gspec.Config) signer = types.LatestSigner(gspec.Config)
) )
blockchain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) blockchain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil)
defer blockchain.Stop() defer blockchain.Stop()
rmLogsCh := make(chan RemovedLogsEvent) rmLogsCh := make(chan RemovedLogsEvent)
@ -1165,7 +1167,7 @@ func testLogRebirth(t *testing.T, scheme string) {
gspec = &Genesis{Config: params.TestChainConfig, Alloc: types.GenesisAlloc{addr1: {Balance: big.NewInt(10000000000000000)}}} gspec = &Genesis{Config: params.TestChainConfig, Alloc: types.GenesisAlloc{addr1: {Balance: big.NewInt(10000000000000000)}}}
signer = types.LatestSigner(gspec.Config) signer = types.LatestSigner(gspec.Config)
engine = ethash.NewFaker() engine = ethash.NewFaker()
blockchain, _ = NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{}, nil, nil) blockchain, _ = NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{}, nil)
) )
defer blockchain.Stop() defer blockchain.Stop()
@ -1246,7 +1248,7 @@ func testSideLogRebirth(t *testing.T, scheme string) {
addr1 = crypto.PubkeyToAddress(key1.PublicKey) addr1 = crypto.PubkeyToAddress(key1.PublicKey)
gspec = &Genesis{Config: params.TestChainConfig, Alloc: types.GenesisAlloc{addr1: {Balance: big.NewInt(10000000000000000)}}} gspec = &Genesis{Config: params.TestChainConfig, Alloc: types.GenesisAlloc{addr1: {Balance: big.NewInt(10000000000000000)}}}
signer = types.LatestSigner(gspec.Config) signer = types.LatestSigner(gspec.Config)
blockchain, _ = NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) blockchain, _ = NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil)
) )
defer blockchain.Stop() defer blockchain.Stop()
@ -1265,7 +1267,7 @@ func testSideLogRebirth(t *testing.T, scheme string) {
} }
checkLogEvents(t, newLogCh, rmLogsCh, 0, 0) checkLogEvents(t, newLogCh, rmLogsCh, 0, 0)
// Generate side chain with lower difficulty // Generate side chain with lower difficulty, after the merge, the chain will be accepted even if it is lower difficulty
genDb, sideChain, _ := GenerateChainWithGenesis(gspec, ethash.NewFaker(), 2, func(i int, gen *BlockGen) { genDb, sideChain, _ := GenerateChainWithGenesis(gspec, ethash.NewFaker(), 2, func(i int, gen *BlockGen) {
if i == 1 { if i == 1 {
tx, err := types.SignTx(types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), 1000000, gen.header.BaseFee, logCode), signer, key1) tx, err := types.SignTx(types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), 1000000, gen.header.BaseFee, logCode), signer, key1)
@ -1278,14 +1280,14 @@ func testSideLogRebirth(t *testing.T, scheme string) {
if _, err := blockchain.InsertChain(sideChain); err != nil { if _, err := blockchain.InsertChain(sideChain); err != nil {
t.Fatalf("failed to insert forked chain: %v", err) t.Fatalf("failed to insert forked chain: %v", err)
} }
checkLogEvents(t, newLogCh, rmLogsCh, 0, 0) checkLogEvents(t, newLogCh, rmLogsCh, 1, 0)
// Generate a new block based on side chain. // Generate a new block based on side chain. Should not emit any events anymore.
newBlocks, _ := GenerateChain(gspec.Config, sideChain[len(sideChain)-1], ethash.NewFaker(), genDb, 1, func(i int, gen *BlockGen) {}) newBlocks, _ := GenerateChain(gspec.Config, sideChain[len(sideChain)-1], ethash.NewFaker(), genDb, 1, func(i int, gen *BlockGen) {})
if _, err := blockchain.InsertChain(newBlocks); err != nil { if _, err := blockchain.InsertChain(newBlocks); err != nil {
t.Fatalf("failed to insert forked chain: %v", err) t.Fatalf("failed to insert forked chain: %v", err)
} }
checkLogEvents(t, newLogCh, rmLogsCh, 1, 0) checkLogEvents(t, newLogCh, rmLogsCh, 0, 0)
} }
func checkLogEvents(t *testing.T, logsCh <-chan []*types.Log, rmLogsCh <-chan RemovedLogsEvent, wantNew, wantRemoved int) { func checkLogEvents(t *testing.T, logsCh <-chan []*types.Log, rmLogsCh <-chan RemovedLogsEvent, wantNew, wantRemoved int) {
@ -1345,7 +1347,7 @@ func testReorgSideEvent(t *testing.T, scheme string) {
} }
signer = types.LatestSigner(gspec.Config) signer = types.LatestSigner(gspec.Config)
) )
blockchain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) blockchain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil)
defer blockchain.Stop() defer blockchain.Stop()
_, chain, _ := GenerateChainWithGenesis(gspec, ethash.NewFaker(), 3, func(i int, gen *BlockGen) {}) _, chain, _ := GenerateChainWithGenesis(gspec, ethash.NewFaker(), 3, func(i int, gen *BlockGen) {})
@ -1369,12 +1371,7 @@ func testReorgSideEvent(t *testing.T, scheme string) {
t.Fatalf("failed to insert chain: %v", err) t.Fatalf("failed to insert chain: %v", err)
} }
// first two block of the secondary chain are for a brief moment considered
// side chains because up to that point the first one is considered the
// heavier chain.
expectedSideHashes := map[common.Hash]bool{ expectedSideHashes := map[common.Hash]bool{
replacementBlocks[0].Hash(): true,
replacementBlocks[1].Hash(): true,
chain[0].Hash(): true, chain[0].Hash(): true,
chain[1].Hash(): true, chain[1].Hash(): true,
chain[2].Hash(): true, chain[2].Hash(): true,
@ -1402,7 +1399,7 @@ done:
timeout.Reset(timeoutDura) timeout.Reset(timeoutDura)
case <-timeout.C: case <-timeout.C:
t.Fatal("Timeout. Possibly not all blocks were triggered for sideevent") t.Fatalf("Timeout. Possibly not all blocks were triggered for sideevent: %v", i)
} }
} }
@ -1529,7 +1526,7 @@ func testEIP155Transition(t *testing.T, scheme string) {
} }
}) })
blockchain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) blockchain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil)
defer blockchain.Stop() defer blockchain.Stop()
if _, err := blockchain.InsertChain(blocks); err != nil { if _, err := blockchain.InsertChain(blocks); err != nil {
@ -1622,7 +1619,7 @@ func testEIP161AccountRemoval(t *testing.T, scheme string) {
block.AddTx(tx) block.AddTx(tx)
}) })
// account must exist pre eip 161 // account must exist pre eip 161
blockchain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) blockchain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil)
defer blockchain.Stop() defer blockchain.Stop()
if _, err := blockchain.InsertChain(types.Blocks{blocks[0]}); err != nil { if _, err := blockchain.InsertChain(types.Blocks{blocks[0]}); err != nil {
@ -1680,7 +1677,7 @@ func testBlockchainHeaderchainReorgConsistency(t *testing.T, scheme string) {
} }
// Import the canonical and fork chain side by side, verifying the current block // Import the canonical and fork chain side by side, verifying the current block
// and current header consistency // and current header consistency
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil, nil) chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil)
if err != nil { if err != nil {
t.Fatalf("failed to create tester chain: %v", err) t.Fatalf("failed to create tester chain: %v", err)
} }
@ -1724,7 +1721,7 @@ func TestTrieForkGC(t *testing.T) {
forks[i] = fork[0] forks[i] = fork[0]
} }
// Import the canonical and fork chain side by side, forcing the trie cache to cache both // Import the canonical and fork chain side by side, forcing the trie cache to cache both
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, genesis, nil, engine, vm.Config{}, nil, nil) chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, genesis, nil, engine, vm.Config{}, nil)
if err != nil { if err != nil {
t.Fatalf("failed to create tester chain: %v", err) t.Fatalf("failed to create tester chain: %v", err)
} }
@ -1770,7 +1767,7 @@ func testLargeReorgTrieGC(t *testing.T, scheme string) {
db, _ := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), "", "", false) db, _ := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), "", "", false)
defer db.Close() defer db.Close()
chain, err := NewBlockChain(db, DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil, nil) chain, err := NewBlockChain(db, DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil)
if err != nil { if err != nil {
t.Fatalf("failed to create tester chain: %v", err) t.Fatalf("failed to create tester chain: %v", err)
} }
@ -1786,18 +1783,15 @@ func testLargeReorgTrieGC(t *testing.T, scheme string) {
if chain.HasState(shared[len(shared)-1].Root()) { if chain.HasState(shared[len(shared)-1].Root()) {
t.Fatalf("common-but-old ancestor still cache") t.Fatalf("common-but-old ancestor still cache")
} }
// Import the competitor chain without exceeding the canonical's TD and ensure // Import the competitor chain without exceeding the canonical's TD.
// we have not processed any of the blocks (protection against malicious blocks) // Post-merge the side chain should be executed
if _, err := chain.InsertChain(competitor[:len(competitor)-2]); err != nil { if _, err := chain.InsertChain(competitor[:len(competitor)-2]); err != nil {
t.Fatalf("failed to insert competitor chain: %v", err) t.Fatalf("failed to insert competitor chain: %v", err)
} }
for i, block := range competitor[:len(competitor)-2] { if !chain.HasState(competitor[len(competitor)-3].Root()) {
if chain.HasState(block.Root()) { t.Fatalf("failed to insert low-TD chain")
t.Fatalf("competitor %d: low TD chain became processed", i)
} }
} // Import the head of the competitor chain.
// Import the head of the competitor chain, triggering the reorg and ensure we
// successfully reprocess all the stashed away blocks.
if _, err := chain.InsertChain(competitor[len(competitor)-2:]); err != nil { if _, err := chain.InsertChain(competitor[len(competitor)-2:]); err != nil {
t.Fatalf("failed to finalize competitor chain: %v", err) t.Fatalf("failed to finalize competitor chain: %v", err)
} }
@ -1841,7 +1835,7 @@ func testBlockchainRecovery(t *testing.T, scheme string) {
t.Fatalf("failed to create temp freezer db: %v", err) t.Fatalf("failed to create temp freezer db: %v", err)
} }
defer ancientDb.Close() defer ancientDb.Close()
ancient, _ := NewBlockChain(ancientDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) ancient, _ := NewBlockChain(ancientDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil)
headers := make([]*types.Header, len(blocks)) headers := make([]*types.Header, len(blocks))
for i, block := range blocks { for i, block := range blocks {
@ -1861,7 +1855,7 @@ func testBlockchainRecovery(t *testing.T, scheme string) {
rawdb.WriteHeadFastBlockHash(ancientDb, midBlock.Hash()) rawdb.WriteHeadFastBlockHash(ancientDb, midBlock.Hash())
// Reopen broken blockchain again // Reopen broken blockchain again
ancient, _ = NewBlockChain(ancientDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) ancient, _ = NewBlockChain(ancientDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil)
defer ancient.Stop() defer ancient.Stop()
if num := ancient.CurrentBlock().Number.Uint64(); num != 0 { if num := ancient.CurrentBlock().Number.Uint64(); num != 0 {
t.Errorf("head block mismatch: have #%v, want #%v", num, 0) t.Errorf("head block mismatch: have #%v, want #%v", num, 0)
@ -1913,7 +1907,7 @@ func testInsertReceiptChainRollback(t *testing.T, scheme string) {
} }
defer ancientDb.Close() defer ancientDb.Close()
ancientChain, _ := NewBlockChain(ancientDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) ancientChain, _ := NewBlockChain(ancientDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil)
defer ancientChain.Stop() defer ancientChain.Stop()
// Import the canonical header chain. // Import the canonical header chain.
@ -1980,7 +1974,7 @@ func testLowDiffLongChain(t *testing.T, scheme string) {
diskdb, _ := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), "", "", false) diskdb, _ := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), "", "", false)
defer diskdb.Close() defer diskdb.Close()
chain, err := NewBlockChain(diskdb, DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil, nil) chain, err := NewBlockChain(diskdb, DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil)
if err != nil { if err != nil {
t.Fatalf("failed to create tester chain: %v", err) t.Fatalf("failed to create tester chain: %v", err)
} }
@ -2041,7 +2035,7 @@ func testSideImport(t *testing.T, numCanonBlocksInSidechain, blocksBetweenCommon
mergeBlock = math.MaxInt32 mergeBlock = math.MaxInt32
) )
// Generate and import the canonical chain // Generate and import the canonical chain
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{}, nil, nil) chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{}, nil)
if err != nil { if err != nil {
t.Fatalf("failed to create tester chain: %v", err) t.Fatalf("failed to create tester chain: %v", err)
} }
@ -2195,7 +2189,7 @@ func testInsertKnownChainData(t *testing.T, typ string, scheme string) {
} }
defer chaindb.Close() defer chaindb.Close()
chain, err := NewBlockChain(chaindb, DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil, nil) chain, err := NewBlockChain(chaindb, DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil)
if err != nil { if err != nil {
t.Fatalf("failed to create tester chain: %v", err) t.Fatalf("failed to create tester chain: %v", err)
} }
@ -2279,10 +2273,10 @@ func testInsertKnownChainData(t *testing.T, typ string, scheme string) {
if err := inserter(append(blocks, blocks2...), append(receipts, receipts2...)); err != nil { if err := inserter(append(blocks, blocks2...), append(receipts, receipts2...)); err != nil {
t.Fatalf("failed to insert chain data: %v", err) t.Fatalf("failed to insert chain data: %v", err)
} }
// The head shouldn't change. // Post-merge the chain should change even if td is lower.
asserter(t, blocks3[len(blocks3)-1]) asserter(t, blocks2[len(blocks2)-1])
// Rollback the heavier chain and re-insert the longer chain again // Rollback the heavier chain and re-insert the longer chain again.
chain.SetHead(rollback - 1) chain.SetHead(rollback - 1)
if err := inserter(append(blocks, blocks2...), append(receipts, receipts2...)); err != nil { if err := inserter(append(blocks, blocks2...), append(receipts, receipts2...)); err != nil {
t.Fatalf("failed to insert chain data: %v", err) t.Fatalf("failed to insert chain data: %v", err)
@ -2366,7 +2360,7 @@ func testInsertKnownChainDataWithMerging(t *testing.T, typ string, mergeHeight i
} }
defer chaindb.Close() defer chaindb.Close()
chain, err := NewBlockChain(chaindb, nil, genesis, nil, engine, vm.Config{}, nil, nil) chain, err := NewBlockChain(chaindb, nil, genesis, nil, engine, vm.Config{}, nil)
if err != nil { if err != nil {
t.Fatalf("failed to create tester chain: %v", err) t.Fatalf("failed to create tester chain: %v", err)
} }
@ -2480,7 +2474,7 @@ func getLongAndShortChains(scheme string) (*BlockChain, []*types.Block, []*types
genDb, longChain, _ := GenerateChainWithGenesis(genesis, engine, 80, func(i int, b *BlockGen) { genDb, longChain, _ := GenerateChainWithGenesis(genesis, engine, 80, func(i int, b *BlockGen) {
b.SetCoinbase(common.Address{1}) b.SetCoinbase(common.Address{1})
}) })
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil, nil) chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil)
if err != nil { if err != nil {
return nil, nil, nil, nil, fmt.Errorf("failed to create tester chain: %v", err) return nil, nil, nil, nil, fmt.Errorf("failed to create tester chain: %v", err)
} }
@ -2656,7 +2650,7 @@ func benchmarkLargeNumberOfValueToNonexisting(b *testing.B, numTxs, numBlocks in
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
// Import the shared chain and the original canonical one // Import the shared chain and the original canonical one
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{}, nil, nil) chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{}, nil)
if err != nil { if err != nil {
b.Fatalf("failed to create tester chain: %v", err) b.Fatalf("failed to create tester chain: %v", err)
} }
@ -2743,7 +2737,21 @@ func testSideImportPrunedBlocks(t *testing.T, scheme string) {
// Generate and import the canonical chain // Generate and import the canonical chain
_, blocks, _ := GenerateChainWithGenesis(genesis, engine, 2*state.TriesInMemory, nil) _, blocks, _ := GenerateChainWithGenesis(genesis, engine, 2*state.TriesInMemory, nil)
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil, nil) // Construct a database with freezer enabled
datadir := t.TempDir()
ancient := path.Join(datadir, "ancient")
db, err := rawdb.Open(rawdb.OpenOptions{
Directory: datadir,
AncientsDirectory: ancient,
Ephemeral: true,
})
if err != nil {
t.Fatalf("Failed to create persistent database: %v", err)
}
defer db.Close()
chain, err := NewBlockChain(db, DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil)
if err != nil { if err != nil {
t.Fatalf("failed to create tester chain: %v", err) t.Fatalf("failed to create tester chain: %v", err)
} }
@ -2770,7 +2778,6 @@ func testSideImportPrunedBlocks(t *testing.T, scheme string) {
if !chain.HasBlockAndState(firstNonPrunedBlock.Hash(), firstNonPrunedBlock.NumberU64()) { if !chain.HasBlockAndState(firstNonPrunedBlock.Hash(), firstNonPrunedBlock.NumberU64()) {
t.Errorf("Block %d pruned", firstNonPrunedBlock.NumberU64()) t.Errorf("Block %d pruned", firstNonPrunedBlock.NumberU64())
} }
// Now re-import some old blocks
blockToReimport := blocks[5:8] blockToReimport := blocks[5:8]
_, err = chain.InsertChain(blockToReimport) _, err = chain.InsertChain(blockToReimport)
if err != nil { if err != nil {
@ -2843,7 +2850,7 @@ func testDeleteCreateRevert(t *testing.T, scheme string) {
b.AddTx(tx) b.AddTx(tx)
}) })
// Import the canonical chain // Import the canonical chain
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{}, nil, nil) chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{}, nil)
if err != nil { if err != nil {
t.Fatalf("failed to create tester chain: %v", err) t.Fatalf("failed to create tester chain: %v", err)
} }
@ -2958,7 +2965,7 @@ func testDeleteRecreateSlots(t *testing.T, scheme string) {
// Import the canonical chain // Import the canonical chain
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{ chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{
Tracer: logger.NewJSONLogger(nil, os.Stdout), Tracer: logger.NewJSONLogger(nil, os.Stdout),
}, nil, nil) }, nil)
if err != nil { if err != nil {
t.Fatalf("failed to create tester chain: %v", err) t.Fatalf("failed to create tester chain: %v", err)
} }
@ -3040,7 +3047,7 @@ func testDeleteRecreateAccount(t *testing.T, scheme string) {
// Import the canonical chain // Import the canonical chain
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{ chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{
Tracer: logger.NewJSONLogger(nil, os.Stdout), Tracer: logger.NewJSONLogger(nil, os.Stdout),
}, nil, nil) }, nil)
if err != nil { if err != nil {
t.Fatalf("failed to create tester chain: %v", err) t.Fatalf("failed to create tester chain: %v", err)
} }
@ -3216,7 +3223,7 @@ func testDeleteRecreateSlotsAcrossManyBlocks(t *testing.T, scheme string) {
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{ chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{
//Debug: true, //Debug: true,
//Tracer: vm.NewJSONLogger(nil, os.Stdout), //Tracer: vm.NewJSONLogger(nil, os.Stdout),
}, nil, nil) }, nil)
if err != nil { if err != nil {
t.Fatalf("failed to create tester chain: %v", err) t.Fatalf("failed to create tester chain: %v", err)
} }
@ -3354,7 +3361,7 @@ func testInitThenFailCreateContract(t *testing.T, scheme string) {
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{ chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{
//Debug: true, //Debug: true,
//Tracer: vm.NewJSONLogger(nil, os.Stdout), //Tracer: vm.NewJSONLogger(nil, os.Stdout),
}, nil, nil) }, nil)
if err != nil { if err != nil {
t.Fatalf("failed to create tester chain: %v", err) t.Fatalf("failed to create tester chain: %v", err)
} }
@ -3441,7 +3448,7 @@ func testEIP2718Transition(t *testing.T, scheme string) {
}) })
// Import the canonical chain // Import the canonical chain
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{}, nil, nil) chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{}, nil)
if err != nil { if err != nil {
t.Fatalf("failed to create tester chain: %v", err) t.Fatalf("failed to create tester chain: %v", err)
} }
@ -3535,7 +3542,7 @@ func testEIP1559Transition(t *testing.T, scheme string) {
b.AddTx(tx) b.AddTx(tx)
}) })
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{}, nil, nil) chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{}, nil)
if err != nil { if err != nil {
t.Fatalf("failed to create tester chain: %v", err) t.Fatalf("failed to create tester chain: %v", err)
} }
@ -3648,7 +3655,7 @@ func testSetCanonical(t *testing.T, scheme string) {
diskdb, _ := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), "", "", false) diskdb, _ := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), "", "", false)
defer diskdb.Close() defer diskdb.Close()
chain, err := NewBlockChain(diskdb, DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{}, nil, nil) chain, err := NewBlockChain(diskdb, DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{}, nil)
if err != nil { if err != nil {
t.Fatalf("failed to create tester chain: %v", err) t.Fatalf("failed to create tester chain: %v", err)
} }
@ -3757,7 +3764,7 @@ func testCanonicalHashMarker(t *testing.T, scheme string) {
_, forkB, _ := GenerateChainWithGenesis(gspec, engine, c.forkB, func(i int, gen *BlockGen) {}) _, forkB, _ := GenerateChainWithGenesis(gspec, engine, c.forkB, func(i int, gen *BlockGen) {})
// Initialize test chain // Initialize test chain
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{}, nil, nil) chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{}, nil)
if err != nil { if err != nil {
t.Fatalf("failed to create tester chain: %v", err) t.Fatalf("failed to create tester chain: %v", err)
} }
@ -3894,7 +3901,7 @@ func testCreateThenDelete(t *testing.T, config *params.ChainConfig) {
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{ chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{
//Debug: true, //Debug: true,
//Tracer: logger.NewJSONLogger(nil, os.Stdout), //Tracer: logger.NewJSONLogger(nil, os.Stdout),
}, nil, nil) }, nil)
if err != nil { if err != nil {
t.Fatalf("failed to create tester chain: %v", err) t.Fatalf("failed to create tester chain: %v", err)
} }
@ -4006,7 +4013,7 @@ func TestDeleteThenCreate(t *testing.T) {
} }
}) })
// Import the canonical chain // Import the canonical chain
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{}, nil, nil) chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{}, nil)
if err != nil { if err != nil {
t.Fatalf("failed to create tester chain: %v", err) t.Fatalf("failed to create tester chain: %v", err)
} }
@ -4091,7 +4098,7 @@ func TestTransientStorageReset(t *testing.T) {
}) })
// Initialize the blockchain with 1153 enabled. // Initialize the blockchain with 1153 enabled.
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vmConfig, nil, nil) chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vmConfig, nil)
if err != nil { if err != nil {
t.Fatalf("failed to create tester chain: %v", err) t.Fatalf("failed to create tester chain: %v", err)
} }
@ -4186,7 +4193,7 @@ func TestEIP3651(t *testing.T) {
b.AddTx(tx) b.AddTx(tx)
}) })
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{Tracer: logger.NewMarkdownLogger(&logger.Config{}, os.Stderr).Hooks()}, nil, nil) chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{Tracer: logger.NewMarkdownLogger(&logger.Config{}, os.Stderr).Hooks()}, nil)
if err != nil { if err != nil {
t.Fatalf("failed to create tester chain: %v", err) t.Fatalf("failed to create tester chain: %v", err)
} }
@ -4220,3 +4227,90 @@ func TestEIP3651(t *testing.T) {
t.Fatalf("sender balance incorrect: expected %d, got %d", expected, actual) t.Fatalf("sender balance incorrect: expected %d, got %d", expected, actual)
} }
} }
func TestEIP6110(t *testing.T) {
var (
engine = beacon.NewFaker()
// A sender who makes transactions, has some funds
key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
addr = crypto.PubkeyToAddress(key.PublicKey)
funds = new(big.Int).Mul(common.Big1, big.NewInt(params.Ether))
config = *params.AllEthashProtocolChanges
gspec = &Genesis{
Config: &config,
Alloc: types.GenesisAlloc{
addr: {Balance: funds},
config.DepositContractAddress: {
// Simple deposit generator, source: https://gist.github.com/lightclient/54abb2af2465d6969fa6d1920b9ad9d7
Code: common.Hex2Bytes("6080604052366103aa575f603067ffffffffffffffff811115610025576100246103ae565b5b6040519080825280601f01601f1916602001820160405280156100575781602001600182028036833780820191505090505b5090505f8054906101000a900460ff1660f81b815f8151811061007d5761007c6103db565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053505f602067ffffffffffffffff8111156100c7576100c66103ae565b5b6040519080825280601f01601f1916602001820160405280156100f95781602001600182028036833780820191505090505b5090505f8054906101000a900460ff1660f81b815f8151811061011f5761011e6103db565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053505f600867ffffffffffffffff811115610169576101686103ae565b5b6040519080825280601f01601f19166020018201604052801561019b5781602001600182028036833780820191505090505b5090505f8054906101000a900460ff1660f81b815f815181106101c1576101c06103db565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053505f606067ffffffffffffffff81111561020b5761020a6103ae565b5b6040519080825280601f01601f19166020018201604052801561023d5781602001600182028036833780820191505090505b5090505f8054906101000a900460ff1660f81b815f81518110610263576102626103db565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053505f600867ffffffffffffffff8111156102ad576102ac6103ae565b5b6040519080825280601f01601f1916602001820160405280156102df5781602001600182028036833780820191505090505b5090505f8054906101000a900460ff1660f81b815f81518110610305576103046103db565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053505f8081819054906101000a900460ff168092919061035090610441565b91906101000a81548160ff021916908360ff160217905550507f649bbc62d0e31342afea4e5cd82d4049e7e1ee912fc0889aa790803be39038c585858585856040516103a09594939291906104d9565b60405180910390a1005b5f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f60ff82169050919050565b5f61044b82610435565b915060ff820361045e5761045d610408565b5b600182019050919050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f6104ab82610469565b6104b58185610473565b93506104c5818560208601610483565b6104ce81610491565b840191505092915050565b5f60a0820190508181035f8301526104f181886104a1565b9050818103602083015261050581876104a1565b9050818103604083015261051981866104a1565b9050818103606083015261052d81856104a1565b9050818103608083015261054181846104a1565b9050969550505050505056fea26469706673582212208569967e58690162d7d6fe3513d07b393b4c15e70f41505cbbfd08f53eba739364736f6c63430008190033"),
Nonce: 0,
Balance: big.NewInt(0),
},
},
}
)
gspec.Config.BerlinBlock = common.Big0
gspec.Config.LondonBlock = common.Big0
gspec.Config.TerminalTotalDifficulty = common.Big0
gspec.Config.TerminalTotalDifficultyPassed = true
gspec.Config.ShanghaiTime = u64(0)
gspec.Config.CancunTime = u64(0)
gspec.Config.PragueTime = u64(0)
signer := types.LatestSigner(gspec.Config)
_, blocks, _ := GenerateChainWithGenesis(gspec, engine, 1, func(i int, b *BlockGen) {
for i := 0; i < 5; i++ {
txdata := &types.DynamicFeeTx{
ChainID: gspec.Config.ChainID,
Nonce: uint64(i),
To: &config.DepositContractAddress,
Gas: 500000,
GasFeeCap: newGwei(5),
GasTipCap: big.NewInt(2),
AccessList: nil,
Data: []byte{},
}
tx := types.NewTx(txdata)
tx, _ = types.SignTx(tx, signer, key)
b.AddTx(tx)
}
})
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{Tracer: logger.NewMarkdownLogger(&logger.Config{DisableStack: true}, os.Stderr).Hooks()}, nil)
if err != nil {
t.Fatalf("failed to create tester chain: %v", err)
}
defer chain.Stop()
if n, err := chain.InsertChain(blocks); err != nil {
t.Fatalf("block %d: failed to insert into chain: %v", n, err)
}
block := chain.GetBlockByNumber(1)
if len(block.Requests()) != 5 {
t.Fatalf("failed to retrieve deposits: have %d, want %d", len(block.Requests()), 5)
}
// Verify each index is correct.
for want, req := range block.Requests() {
d, ok := req.Inner().(*types.Deposit)
if !ok {
t.Fatalf("expected deposit object")
}
if got := int(d.PublicKey[0]); got != want {
t.Fatalf("invalid pubkey: have %d, want %d", got, want)
}
if got := int(d.WithdrawalCredentials[0]); got != want {
t.Fatalf("invalid withdrawal credentials: have %d, want %d", got, want)
}
if d.Amount != uint64(want) {
t.Fatalf("invalid amounbt: have %d, want %d", d.Amount, want)
}
if got := int(d.Signature[0]); got != want {
t.Fatalf("invalid signature: have %d, want %d", got, want)
}
if d.Index != uint64(want) {
t.Fatalf("invalid index: have %d, want %d", d.Index, want)
}
}
}

View file

@ -346,7 +346,18 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
gen(i, b) gen(i, b)
} }
body := types.Body{Transactions: b.txs, Uncles: b.uncles, Withdrawals: b.withdrawals} var requests types.Requests
if config.IsPrague(b.header.Number, b.header.Time) {
for _, r := range b.receipts {
d, err := ParseDepositLogs(r.Logs, config)
if err != nil {
panic(fmt.Sprintf("failed to parse deposit log: %v", err))
}
requests = append(requests, d...)
}
}
body := types.Body{Transactions: b.txs, Uncles: b.uncles, Withdrawals: b.withdrawals, Requests: requests}
block, err := b.engine.FinalizeAndAssemble(cm, b.header, statedb, &body, b.receipts) block, err := b.engine.FinalizeAndAssemble(cm, b.header, statedb, &body, b.receipts)
if err != nil { if err != nil {
panic(err) panic(err)

View file

@ -123,7 +123,7 @@ func TestGeneratePOSChain(t *testing.T) {
}) })
// Import the chain. This runs all block validation rules. // Import the chain. This runs all block validation rules.
blockchain, _ := NewBlockChain(db, nil, gspec, nil, beacon.NewFaker(), vm.Config{}, nil, nil) blockchain, _ := NewBlockChain(db, nil, gspec, nil, beacon.NewFaker(), vm.Config{}, nil)
defer blockchain.Stop() defer blockchain.Stop()
if i, err := blockchain.InsertChain(genchain); err != nil { if i, err := blockchain.InsertChain(genchain); err != nil {
@ -238,7 +238,7 @@ func ExampleGenerateChain() {
}) })
// Import the chain. This runs all block validation rules. // Import the chain. This runs all block validation rules.
blockchain, _ := NewBlockChain(db, DefaultCacheConfigWithScheme(rawdb.HashScheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) blockchain, _ := NewBlockChain(db, DefaultCacheConfigWithScheme(rawdb.HashScheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil)
defer blockchain.Stop() defer blockchain.Stop()
if i, err := blockchain.InsertChain(chain); err != nil { if i, err := blockchain.InsertChain(chain); err != nil {

View file

@ -50,7 +50,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
BaseFee: big.NewInt(params.InitialBaseFee), BaseFee: big.NewInt(params.InitialBaseFee),
Config: &proConf, Config: &proConf,
} }
proBc, _ := NewBlockChain(proDb, nil, progspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) proBc, _ := NewBlockChain(proDb, nil, progspec, nil, ethash.NewFaker(), vm.Config{}, nil)
defer proBc.Stop() defer proBc.Stop()
conDb := rawdb.NewMemoryDatabase() conDb := rawdb.NewMemoryDatabase()
@ -62,7 +62,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
BaseFee: big.NewInt(params.InitialBaseFee), BaseFee: big.NewInt(params.InitialBaseFee),
Config: &conConf, Config: &conConf,
} }
conBc, _ := NewBlockChain(conDb, nil, congspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) conBc, _ := NewBlockChain(conDb, nil, congspec, nil, ethash.NewFaker(), vm.Config{}, nil)
defer conBc.Stop() defer conBc.Stop()
if _, err := proBc.InsertChain(prefix); err != nil { if _, err := proBc.InsertChain(prefix); err != nil {
@ -74,7 +74,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
// Try to expand both pro-fork and non-fork chains iteratively with other camp's blocks // Try to expand both pro-fork and non-fork chains iteratively with other camp's blocks
for i := int64(0); i < params.DAOForkExtraRange.Int64(); i++ { for i := int64(0); i < params.DAOForkExtraRange.Int64(); i++ {
// Create a pro-fork block, and try to feed into the no-fork chain // Create a pro-fork block, and try to feed into the no-fork chain
bc, _ := NewBlockChain(rawdb.NewMemoryDatabase(), nil, congspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) bc, _ := NewBlockChain(rawdb.NewMemoryDatabase(), nil, congspec, nil, ethash.NewFaker(), vm.Config{}, nil)
blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().Number.Uint64())) blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().Number.Uint64()))
for j := 0; j < len(blocks)/2; j++ { for j := 0; j < len(blocks)/2; j++ {
@ -97,7 +97,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
t.Fatalf("contra-fork chain didn't accepted no-fork block: %v", err) t.Fatalf("contra-fork chain didn't accepted no-fork block: %v", err)
} }
// Create a no-fork block, and try to feed into the pro-fork chain // Create a no-fork block, and try to feed into the pro-fork chain
bc, _ = NewBlockChain(rawdb.NewMemoryDatabase(), nil, progspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) bc, _ = NewBlockChain(rawdb.NewMemoryDatabase(), nil, progspec, nil, ethash.NewFaker(), vm.Config{}, nil)
blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().Number.Uint64())) blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().Number.Uint64()))
for j := 0; j < len(blocks)/2; j++ { for j := 0; j < len(blocks)/2; j++ {
@ -121,7 +121,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
} }
} }
// Verify that contra-forkers accept pro-fork extra-datas after forking finishes // Verify that contra-forkers accept pro-fork extra-datas after forking finishes
bc, _ := NewBlockChain(rawdb.NewMemoryDatabase(), nil, congspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) bc, _ := NewBlockChain(rawdb.NewMemoryDatabase(), nil, congspec, nil, ethash.NewFaker(), vm.Config{}, nil)
defer bc.Stop() defer bc.Stop()
blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().Number.Uint64())) blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().Number.Uint64()))
@ -139,7 +139,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
t.Fatalf("contra-fork chain didn't accept pro-fork block post-fork: %v", err) t.Fatalf("contra-fork chain didn't accept pro-fork block post-fork: %v", err)
} }
// Verify that pro-forkers accept contra-fork extra-datas after forking finishes // Verify that pro-forkers accept contra-fork extra-datas after forking finishes
bc, _ = NewBlockChain(rawdb.NewMemoryDatabase(), nil, progspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) bc, _ = NewBlockChain(rawdb.NewMemoryDatabase(), nil, progspec, nil, ethash.NewFaker(), vm.Config{}, nil)
defer bc.Stop() defer bc.Stop()
blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().Number.Uint64())) blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().Number.Uint64()))

View file

@ -1,113 +0,0 @@
// Copyright 2021 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package core
import (
crand "crypto/rand"
"errors"
"math/big"
mrand "math/rand"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
)
// ChainReader defines a small collection of methods needed to access the local
// blockchain during header verification. It's implemented by both blockchain
// and lightchain.
type ChainReader interface {
// Config retrieves the header chain's chain configuration.
Config() *params.ChainConfig
// GetTd returns the total difficulty of a local block.
GetTd(common.Hash, uint64) *big.Int
}
// ForkChoice is the fork chooser based on the highest total difficulty of the
// chain(the fork choice used in the eth1) and the external fork choice (the fork
// choice used in the eth2). This main goal of this ForkChoice is not only for
// offering fork choice during the eth1/2 merge phase, but also keep the compatibility
// for all other proof-of-work networks.
type ForkChoice struct {
chain ChainReader
rand *mrand.Rand
// preserve is a helper function used in td fork choice.
// Miners will prefer to choose the local mined block if the
// local td is equal to the extern one. It can be nil for light
// client
preserve func(header *types.Header) bool
}
func NewForkChoice(chainReader ChainReader, preserve func(header *types.Header) bool) *ForkChoice {
// Seed a fast but crypto originating random generator
seed, err := crand.Int(crand.Reader, big.NewInt(math.MaxInt64))
if err != nil {
log.Crit("Failed to initialize random seed", "err", err)
}
return &ForkChoice{
chain: chainReader,
rand: mrand.New(mrand.NewSource(seed.Int64())),
preserve: preserve,
}
}
// ReorgNeeded returns whether the reorg should be applied
// based on the given external header and local canonical chain.
// In the td mode, the new head is chosen if the corresponding
// total difficulty is higher. In the extern mode, the trusted
// header is always selected as the head.
func (f *ForkChoice) ReorgNeeded(current *types.Header, extern *types.Header) (bool, error) {
var (
localTD = f.chain.GetTd(current.Hash(), current.Number.Uint64())
externTd = f.chain.GetTd(extern.Hash(), extern.Number.Uint64())
)
if localTD == nil || externTd == nil {
return false, errors.New("missing td")
}
// Accept the new header as the chain head if the transition
// is already triggered. We assume all the headers after the
// transition come from the trusted consensus layer.
if ttd := f.chain.Config().TerminalTotalDifficulty; ttd != nil && ttd.Cmp(externTd) <= 0 {
return true, nil
}
// If the total difficulty is higher than our known, add it to the canonical chain
if diff := externTd.Cmp(localTD); diff > 0 {
return true, nil
} else if diff < 0 {
return false, nil
}
// Local and external difficulty is identical.
// Second clause in the if statement reduces the vulnerability to selfish mining.
// Please refer to http://www.cs.cornell.edu/~ie53/publications/btcProcFC.pdf
reorg := false
externNum, localNum := extern.Number.Uint64(), current.Number.Uint64()
if externNum < localNum {
reorg = true
} else if externNum == localNum {
var currentPreserve, externPreserve bool
if f.preserve != nil {
currentPreserve, externPreserve = f.preserve(current), f.preserve(extern)
}
reorg = !currentPreserve && (externPreserve || f.rand.Float64() < 0.5)
}
return reorg, nil
}

View file

@ -447,7 +447,10 @@ func (g *Genesis) toBlockWithRoot(root common.Hash) *types.Block {
head.BaseFee = new(big.Int).SetUint64(params.InitialBaseFee) head.BaseFee = new(big.Int).SetUint64(params.InitialBaseFee)
} }
} }
var withdrawals []*types.Withdrawal var (
withdrawals []*types.Withdrawal
requests types.Requests
)
if conf := g.Config; conf != nil { if conf := g.Config; conf != nil {
num := big.NewInt(int64(g.Number)) num := big.NewInt(int64(g.Number))
if conf.IsShanghai(num, g.Timestamp) { if conf.IsShanghai(num, g.Timestamp) {
@ -469,8 +472,12 @@ func (g *Genesis) toBlockWithRoot(root common.Hash) *types.Block {
head.BlobGasUsed = new(uint64) head.BlobGasUsed = new(uint64)
} }
} }
if conf.IsPrague(num, g.Timestamp) {
head.RequestsHash = &types.EmptyRequestsHash
requests = make(types.Requests, 0)
} }
return types.NewBlock(head, &types.Body{Withdrawals: withdrawals}, nil, trie.NewStackTrie(nil)) }
return types.NewBlock(head, &types.Body{Withdrawals: withdrawals, Requests: requests}, nil, trie.NewStackTrie(nil))
} }
// Commit writes the block and state of a genesis specification to the database. // Commit writes the block and state of a genesis specification to the database.

View file

@ -124,7 +124,7 @@ func testSetupGenesis(t *testing.T, scheme string) {
tdb := triedb.NewDatabase(db, newDbConfig(scheme)) tdb := triedb.NewDatabase(db, newDbConfig(scheme))
oldcustomg.Commit(db, tdb) oldcustomg.Commit(db, tdb)
bc, _ := NewBlockChain(db, DefaultCacheConfigWithScheme(scheme), &oldcustomg, nil, ethash.NewFullFaker(), vm.Config{}, nil, nil) bc, _ := NewBlockChain(db, DefaultCacheConfigWithScheme(scheme), &oldcustomg, nil, ethash.NewFullFaker(), vm.Config{}, nil)
defer bc.Stop() defer bc.Stop()
_, blocks, _ := GenerateChainWithGenesis(&oldcustomg, ethash.NewFaker(), 4, nil) _, blocks, _ := GenerateChainWithGenesis(&oldcustomg, ethash.NewFaker(), 4, nil)

View file

@ -254,7 +254,7 @@ func (hc *HeaderChain) WriteHeaders(headers []*types.Header) (int, error) {
// without the real blocks. Hence, writing headers directly should only be done // without the real blocks. Hence, writing headers directly should only be done
// in two scenarios: pure-header mode of operation (light clients), or properly // in two scenarios: pure-header mode of operation (light clients), or properly
// separated header/block phases (non-archive clients). // separated header/block phases (non-archive clients).
func (hc *HeaderChain) writeHeadersAndSetHead(headers []*types.Header, forker *ForkChoice) (*headerWriteResult, error) { func (hc *HeaderChain) writeHeadersAndSetHead(headers []*types.Header) (*headerWriteResult, error) {
inserted, err := hc.WriteHeaders(headers) inserted, err := hc.WriteHeaders(headers)
if err != nil { if err != nil {
return nil, err return nil, err
@ -270,15 +270,6 @@ func (hc *HeaderChain) writeHeadersAndSetHead(headers []*types.Header, forker *F
lastHeader: lastHeader, lastHeader: lastHeader,
} }
) )
// Ask the fork choicer if the reorg is necessary
if reorg, err := forker.ReorgNeeded(hc.CurrentHeader(), lastHeader); err != nil {
return nil, err
} else if !reorg {
if inserted != 0 {
result.status = SideStatTy
}
return result, nil
}
// Special case, all the inserted headers are already on the canonical // Special case, all the inserted headers are already on the canonical
// header chain, skip the reorg operation. // header chain, skip the reorg operation.
if hc.GetCanonicalHash(lastHeader.Number.Uint64()) == lastHash && lastHeader.Number.Uint64() <= hc.CurrentHeader().Number.Uint64() { if hc.GetCanonicalHash(lastHeader.Number.Uint64()) == lastHash && lastHeader.Number.Uint64() <= hc.CurrentHeader().Number.Uint64() {
@ -336,11 +327,11 @@ func (hc *HeaderChain) ValidateHeaderChain(chain []*types.Header) (int, error) {
// //
// The returned 'write status' says if the inserted headers are part of the canonical chain // The returned 'write status' says if the inserted headers are part of the canonical chain
// or a side chain. // or a side chain.
func (hc *HeaderChain) InsertHeaderChain(chain []*types.Header, start time.Time, forker *ForkChoice) (WriteStatus, error) { func (hc *HeaderChain) InsertHeaderChain(chain []*types.Header, start time.Time) (WriteStatus, error) {
if hc.procInterrupt() { if hc.procInterrupt() {
return 0, errors.New("aborted") return 0, errors.New("aborted")
} }
res, err := hc.writeHeadersAndSetHead(chain, forker) res, err := hc.writeHeadersAndSetHead(chain)
if err != nil { if err != nil {
return 0, err return 0, err
} }

View file

@ -51,10 +51,10 @@ func verifyUnbrokenCanonchain(hc *HeaderChain) error {
return nil return nil
} }
func testInsert(t *testing.T, hc *HeaderChain, chain []*types.Header, wantStatus WriteStatus, wantErr error, forker *ForkChoice) { func testInsert(t *testing.T, hc *HeaderChain, chain []*types.Header, wantStatus WriteStatus, wantErr error) {
t.Helper() t.Helper()
status, err := hc.InsertHeaderChain(chain, time.Now(), forker) status, err := hc.InsertHeaderChain(chain, time.Now())
if status != wantStatus { if status != wantStatus {
t.Errorf("wrong write status from InsertHeaderChain: got %v, want %v", status, wantStatus) t.Errorf("wrong write status from InsertHeaderChain: got %v, want %v", status, wantStatus)
} }
@ -83,34 +83,33 @@ func TestHeaderInsertion(t *testing.T) {
// chain B: G->A1->B1...B128 // chain B: G->A1->B1...B128
chainB := makeHeaderChain(gspec.Config, chainA[0], 128, ethash.NewFaker(), genDb, 10) chainB := makeHeaderChain(gspec.Config, chainA[0], 128, ethash.NewFaker(), genDb, 10)
forker := NewForkChoice(hc, nil)
// Inserting 64 headers on an empty chain, expecting // Inserting 64 headers on an empty chain, expecting
// 1 callbacks, 1 canon-status, 0 sidestatus, // 1 callbacks, 1 canon-status, 0 sidestatus,
testInsert(t, hc, chainA[:64], CanonStatTy, nil, forker) testInsert(t, hc, chainA[:64], CanonStatTy, nil)
// Inserting 64 identical headers, expecting // Inserting 64 identical headers, expecting
// 0 callbacks, 0 canon-status, 0 sidestatus, // 0 callbacks, 0 canon-status, 0 sidestatus,
testInsert(t, hc, chainA[:64], NonStatTy, nil, forker) testInsert(t, hc, chainA[:64], NonStatTy, nil)
// Inserting the same some old, some new headers // Inserting the same some old, some new headers
// 1 callbacks, 1 canon, 0 side // 1 callbacks, 1 canon, 0 side
testInsert(t, hc, chainA[32:96], CanonStatTy, nil, forker) testInsert(t, hc, chainA[32:96], CanonStatTy, nil)
// Inserting side blocks, but not overtaking the canon chain // Inserting headers from chain B, overtaking the canon chain blindly
testInsert(t, hc, chainB[0:32], SideStatTy, nil, forker) testInsert(t, hc, chainB[0:32], CanonStatTy, nil)
// Inserting more side blocks, but we don't have the parent // Inserting more headers on chain B, but we don't have the parent
testInsert(t, hc, chainB[34:36], NonStatTy, consensus.ErrUnknownAncestor, forker) testInsert(t, hc, chainB[34:36], NonStatTy, consensus.ErrUnknownAncestor)
// Inserting more sideblocks, overtaking the canon chain // Inserting more headers on chain B, extend the canon chain
testInsert(t, hc, chainB[32:97], CanonStatTy, nil, forker) testInsert(t, hc, chainB[32:97], CanonStatTy, nil)
// Inserting more A-headers, taking back the canonicality // Inserting more headers on chain A, taking back the canonicality
testInsert(t, hc, chainA[90:100], CanonStatTy, nil, forker) testInsert(t, hc, chainA[90:100], CanonStatTy, nil)
// And B becomes canon again // And B becomes canon again
testInsert(t, hc, chainB[97:107], CanonStatTy, nil, forker) testInsert(t, hc, chainB[97:107], CanonStatTy, nil)
// And B becomes even longer // And B becomes even longer
testInsert(t, hc, chainB[107:128], CanonStatTy, nil, forker) testInsert(t, hc, chainB[107:128], CanonStatTy, nil)
} }

View file

@ -53,7 +53,7 @@ func NewStateProcessor(config *params.ChainConfig, chain *HeaderChain) *StatePro
// Process returns the receipts and logs accumulated during the process and // Process returns the receipts and logs accumulated during the process and
// returns the amount of gas that was used in the process. If any of the // returns the amount of gas that was used in the process. If any of the
// transactions failed to execute due to insufficient gas it will return an error. // transactions failed to execute due to insufficient gas it will return an error.
func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, []*types.Log, uint64, error) { func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (*ProcessResult, error) {
var ( var (
receipts types.Receipts receipts types.Receipts
usedGas = new(uint64) usedGas = new(uint64)
@ -71,6 +71,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
var ( var (
context vm.BlockContext context vm.BlockContext
signer = types.MakeSigner(p.config, header.Number, header.Time) signer = types.MakeSigner(p.config, header.Number, header.Time)
err error
) )
context = NewEVMBlockContext(header, p.chain, nil) context = NewEVMBlockContext(header, p.chain, nil)
vmenv := vm.NewEVM(context, vm.TxContext{}, statedb, p.config, cfg) vmenv := vm.NewEVM(context, vm.TxContext{}, statedb, p.config, cfg)
@ -84,21 +85,35 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
for i, tx := range block.Transactions() { for i, tx := range block.Transactions() {
msg, err := TransactionToMessage(tx, signer, header.BaseFee) msg, err := TransactionToMessage(tx, signer, header.BaseFee)
if err != nil { if err != nil {
return nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) return nil, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err)
} }
statedb.SetTxContext(tx.Hash(), i) statedb.SetTxContext(tx.Hash(), i)
receipt, err := ApplyTransactionWithEVM(msg, p.config, gp, statedb, blockNumber, blockHash, tx, usedGas, vmenv) receipt, err := ApplyTransactionWithEVM(msg, p.config, gp, statedb, blockNumber, blockHash, tx, usedGas, vmenv)
if err != nil { if err != nil {
return nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) return nil, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err)
} }
receipts = append(receipts, receipt) receipts = append(receipts, receipt)
allLogs = append(allLogs, receipt.Logs...) allLogs = append(allLogs, receipt.Logs...)
} }
// Read requests if Prague is enabled.
var requests types.Requests
if p.config.IsPrague(block.Number(), block.Time()) {
requests, err = ParseDepositLogs(allLogs, p.config)
if err != nil {
return nil, err
}
}
// Finalize the block, applying any consensus engine specific extras (e.g. block rewards) // Finalize the block, applying any consensus engine specific extras (e.g. block rewards)
p.chain.engine.Finalize(p.chain, header, statedb, block.Body()) p.chain.engine.Finalize(p.chain, header, statedb, block.Body())
return receipts, allLogs, *usedGas, nil return &ProcessResult{
Receipts: receipts,
Requests: requests,
Logs: allLogs,
GasUsed: *usedGas,
}, nil
} }
// ApplyTransactionWithEVM attempts to apply a transaction to the given state database // ApplyTransactionWithEVM attempts to apply a transaction to the given state database
@ -244,3 +259,19 @@ func ProcessParentBlockHash(prevHash common.Hash, vmenv *vm.EVM, statedb *state.
_, _, _ = vmenv.Call(vm.AccountRef(msg.From), *msg.To, msg.Data, 30_000_000, common.U2560) _, _, _ = vmenv.Call(vm.AccountRef(msg.From), *msg.To, msg.Data, 30_000_000, common.U2560)
statedb.Finalise(true) statedb.Finalise(true)
} }
// ParseDepositLogs extracts the EIP-6110 deposit values from logs emitted by
// BeaconDepositContract.
func ParseDepositLogs(logs []*types.Log, config *params.ChainConfig) (types.Requests, error) {
deposits := make(types.Requests, 0)
for _, log := range logs {
if log.Address == config.DepositContractAddress {
d, err := types.UnpackIntoDeposit(log.Data)
if err != nil {
return nil, fmt.Errorf("unable to parse deposit data: %v", err)
}
deposits = append(deposits, types.NewRequest(d))
}
}
return deposits, nil
}

View file

@ -133,7 +133,7 @@ func TestStateProcessorErrors(t *testing.T) {
}, },
}, },
} }
blockchain, _ = NewBlockChain(db, nil, gspec, nil, beacon.New(ethash.NewFaker()), vm.Config{}, nil, nil) blockchain, _ = NewBlockChain(db, nil, gspec, nil, beacon.New(ethash.NewFaker()), vm.Config{}, nil)
tooBigInitCode = [params.MaxInitCodeSize + 1]byte{} tooBigInitCode = [params.MaxInitCodeSize + 1]byte{}
) )
@ -293,7 +293,7 @@ func TestStateProcessorErrors(t *testing.T) {
}, },
}, },
} }
blockchain, _ = NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) blockchain, _ = NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil)
) )
defer blockchain.Stop() defer blockchain.Stop()
for i, tt := range []struct { for i, tt := range []struct {
@ -332,7 +332,7 @@ func TestStateProcessorErrors(t *testing.T) {
}, },
}, },
} }
blockchain, _ = NewBlockChain(db, nil, gspec, nil, beacon.New(ethash.NewFaker()), vm.Config{}, nil, nil) blockchain, _ = NewBlockChain(db, nil, gspec, nil, beacon.New(ethash.NewFaker()), vm.Config{}, nil)
) )
defer blockchain.Stop() defer blockchain.Stop()
for i, tt := range []struct { for i, tt := range []struct {
@ -481,7 +481,7 @@ func TestProcessVerkle(t *testing.T) {
// genesis := gspec.MustCommit(bcdb, triedb) // genesis := gspec.MustCommit(bcdb, triedb)
cacheConfig := DefaultCacheConfigWithScheme("path") cacheConfig := DefaultCacheConfigWithScheme("path")
cacheConfig.SnapshotLimit = 0 cacheConfig.SnapshotLimit = 0
blockchain, _ := NewBlockChain(bcdb, cacheConfig, gspec, nil, beacon.New(ethash.NewFaker()), vm.Config{}, nil, nil) blockchain, _ := NewBlockChain(bcdb, cacheConfig, gspec, nil, beacon.New(ethash.NewFaker()), vm.Config{}, nil)
defer blockchain.Stop() defer blockchain.Stop()
txCost1 := params.TxGas txCost1 := params.TxGas

View file

@ -58,15 +58,15 @@ func ExecuteStateless(config *params.ChainConfig, witness *stateless.Witness) (c
validator := NewBlockValidator(config, nil) // No chain, we only validate the state, not the block validator := NewBlockValidator(config, nil) // No chain, we only validate the state, not the block
// Run the stateless blocks processing and self-validate certain fields // Run the stateless blocks processing and self-validate certain fields
receipts, _, usedGas, err := processor.Process(witness.Block, db, vm.Config{}) res, err := processor.Process(witness.Block, db, vm.Config{})
if err != nil { if err != nil {
return common.Hash{}, common.Hash{}, err return common.Hash{}, common.Hash{}, err
} }
if err = validator.ValidateState(witness.Block, db, receipts, usedGas, true); err != nil { if err = validator.ValidateState(witness.Block, db, res, true); err != nil {
return common.Hash{}, common.Hash{}, err return common.Hash{}, common.Hash{}, err
} }
// Almost everything validated, but receipt and state root needs to be returned // Almost everything validated, but receipt and state root needs to be returned
receiptRoot := types.DeriveSha(receipts, trie.NewStackTrie(nil)) receiptRoot := types.DeriveSha(res.Receipts, trie.NewStackTrie(nil))
stateRoot := db.IntermediateRoot(config.IsEIP158(witness.Block.Number())) stateRoot := db.IntermediateRoot(config.IsEIP158(witness.Block.Number()))
return receiptRoot, stateRoot, nil return receiptRoot, stateRoot, nil

View file

@ -33,9 +33,8 @@ type Validator interface {
// ValidateBody validates the given block's content. // ValidateBody validates the given block's content.
ValidateBody(block *types.Block) error ValidateBody(block *types.Block) error
// ValidateState validates the given statedb and optionally the receipts and // ValidateState validates the given statedb and optionally the process result.
// gas used. ValidateState(block *types.Block, state *state.StateDB, res *ProcessResult, stateless bool) error
ValidateState(block *types.Block, state *state.StateDB, receipts types.Receipts, usedGas uint64, stateless bool) error
// ValidateWitness cross validates a block execution with stateless remote clients. // ValidateWitness cross validates a block execution with stateless remote clients.
ValidateWitness(witness *stateless.Witness, receiptRoot common.Hash, stateRoot common.Hash) error ValidateWitness(witness *stateless.Witness, receiptRoot common.Hash, stateRoot common.Hash) error
@ -54,5 +53,13 @@ type Processor interface {
// Process processes the state changes according to the Ethereum rules by running // Process processes the state changes according to the Ethereum rules by running
// the transaction messages using the statedb and applying any rewards to both // the transaction messages using the statedb and applying any rewards to both
// the processor (coinbase) and any included uncles. // the processor (coinbase) and any included uncles.
Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, []*types.Log, uint64, error) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (*ProcessResult, error)
}
// ProcessResult contains the values computed by Process.
type ProcessResult struct {
Receipts types.Receipts
Requests types.Requests
Logs []*types.Log
GasUsed uint64
} }

View file

@ -102,6 +102,9 @@ type Header struct {
// ParentBeaconRoot was added by EIP-4788 and is ignored in legacy headers. // ParentBeaconRoot was added by EIP-4788 and is ignored in legacy headers.
ParentBeaconRoot *common.Hash `json:"parentBeaconBlockRoot" rlp:"optional"` ParentBeaconRoot *common.Hash `json:"parentBeaconBlockRoot" rlp:"optional"`
// RequestsHash was added by EIP-7685 and is ignored in legacy headers.
RequestsHash *common.Hash `json:"requestsRoot" rlp:"optional"`
} }
// field type overrides for gencodec // field type overrides for gencodec
@ -163,10 +166,11 @@ func (h *Header) SanityCheck() error {
// EmptyBody returns true if there is no additional 'body' to complete the header // EmptyBody returns true if there is no additional 'body' to complete the header
// that is: no transactions, no uncles and no withdrawals. // that is: no transactions, no uncles and no withdrawals.
func (h *Header) EmptyBody() bool { func (h *Header) EmptyBody() bool {
if h.WithdrawalsHash != nil { var (
return h.TxHash == EmptyTxsHash && *h.WithdrawalsHash == EmptyWithdrawalsHash emptyWithdrawals = h.WithdrawalsHash == nil || *h.WithdrawalsHash == EmptyWithdrawalsHash
} emptyRequests = h.RequestsHash == nil || *h.RequestsHash == EmptyReceiptsHash
return h.TxHash == EmptyTxsHash && h.UncleHash == EmptyUncleHash )
return h.TxHash == EmptyTxsHash && h.UncleHash == EmptyUncleHash && emptyWithdrawals && emptyRequests
} }
// EmptyReceipts returns true if there are no receipts for this header/block. // EmptyReceipts returns true if there are no receipts for this header/block.
@ -180,6 +184,7 @@ type Body struct {
Transactions []*Transaction Transactions []*Transaction
Uncles []*Header Uncles []*Header
Withdrawals []*Withdrawal `rlp:"optional"` Withdrawals []*Withdrawal `rlp:"optional"`
Requests []*Request `rlp:"optional"`
} }
// Block represents an Ethereum block. // Block represents an Ethereum block.
@ -204,6 +209,7 @@ type Block struct {
uncles []*Header uncles []*Header
transactions Transactions transactions Transactions
withdrawals Withdrawals withdrawals Withdrawals
requests Requests
// witness is not an encoded part of the block body. // witness is not an encoded part of the block body.
// It is held in Block in order for easy relaying to the places // It is held in Block in order for easy relaying to the places
@ -226,6 +232,7 @@ type extblock struct {
Txs []*Transaction Txs []*Transaction
Uncles []*Header Uncles []*Header
Withdrawals []*Withdrawal `rlp:"optional"` Withdrawals []*Withdrawal `rlp:"optional"`
Requests []*Request `rlp:"optional"`
} }
// NewBlock creates a new block. The input data is copied, changes to header and to the // NewBlock creates a new block. The input data is copied, changes to header and to the
@ -242,6 +249,7 @@ func NewBlock(header *Header, body *Body, receipts []*Receipt, hasher TrieHasher
txs = body.Transactions txs = body.Transactions
uncles = body.Uncles uncles = body.Uncles
withdrawals = body.Withdrawals withdrawals = body.Withdrawals
requests = body.Requests
) )
if len(txs) == 0 { if len(txs) == 0 {
@ -280,6 +288,17 @@ func NewBlock(header *Header, body *Body, receipts []*Receipt, hasher TrieHasher
b.withdrawals = slices.Clone(withdrawals) b.withdrawals = slices.Clone(withdrawals)
} }
if requests == nil {
b.header.RequestsHash = nil
} else if len(requests) == 0 {
b.header.RequestsHash = &EmptyRequestsHash
b.requests = Requests{}
} else {
h := DeriveSha(Requests(requests), hasher)
b.header.RequestsHash = &h
b.requests = slices.Clone(requests)
}
return b return b
} }
@ -315,6 +334,10 @@ func CopyHeader(h *Header) *Header {
cpy.ParentBeaconRoot = new(common.Hash) cpy.ParentBeaconRoot = new(common.Hash)
*cpy.ParentBeaconRoot = *h.ParentBeaconRoot *cpy.ParentBeaconRoot = *h.ParentBeaconRoot
} }
if h.RequestsHash != nil {
cpy.RequestsHash = new(common.Hash)
*cpy.RequestsHash = *h.RequestsHash
}
return &cpy return &cpy
} }
@ -325,7 +348,7 @@ func (b *Block) DecodeRLP(s *rlp.Stream) error {
if err := s.Decode(&eb); err != nil { if err := s.Decode(&eb); err != nil {
return err return err
} }
b.header, b.uncles, b.transactions, b.withdrawals = eb.Header, eb.Uncles, eb.Txs, eb.Withdrawals b.header, b.uncles, b.transactions, b.withdrawals, b.requests = eb.Header, eb.Uncles, eb.Txs, eb.Withdrawals, eb.Requests
b.size.Store(rlp.ListSize(size)) b.size.Store(rlp.ListSize(size))
return nil return nil
} }
@ -337,13 +360,14 @@ func (b *Block) EncodeRLP(w io.Writer) error {
Txs: b.transactions, Txs: b.transactions,
Uncles: b.uncles, Uncles: b.uncles,
Withdrawals: b.withdrawals, Withdrawals: b.withdrawals,
Requests: b.requests,
}) })
} }
// Body returns the non-header content of the block. // Body returns the non-header content of the block.
// Note the returned data is not an independent copy. // Note the returned data is not an independent copy.
func (b *Block) Body() *Body { func (b *Block) Body() *Body {
return &Body{b.transactions, b.uncles, b.withdrawals} return &Body{b.transactions, b.uncles, b.withdrawals, b.requests}
} }
// Accessors for body data. These do not return a copy because the content // Accessors for body data. These do not return a copy because the content
@ -352,6 +376,7 @@ func (b *Block) Body() *Body {
func (b *Block) Uncles() []*Header { return b.uncles } func (b *Block) Uncles() []*Header { return b.uncles }
func (b *Block) Transactions() Transactions { return b.transactions } func (b *Block) Transactions() Transactions { return b.transactions }
func (b *Block) Withdrawals() Withdrawals { return b.withdrawals } func (b *Block) Withdrawals() Withdrawals { return b.withdrawals }
func (b *Block) Requests() Requests { return b.requests }
func (b *Block) Transaction(hash common.Hash) *Transaction { func (b *Block) Transaction(hash common.Hash) *Transaction {
for _, transaction := range b.transactions { for _, transaction := range b.transactions {
@ -476,6 +501,7 @@ func (b *Block) WithBody(body Body) *Block {
transactions: slices.Clone(body.Transactions), transactions: slices.Clone(body.Transactions),
uncles: make([]*Header, len(body.Uncles)), uncles: make([]*Header, len(body.Uncles)),
withdrawals: slices.Clone(body.Withdrawals), withdrawals: slices.Clone(body.Withdrawals),
requests: slices.Clone(body.Requests),
witness: b.witness, witness: b.witness,
} }
for i := range body.Uncles { for i := range body.Uncles {
@ -490,6 +516,7 @@ func (b *Block) WithWitness(witness *ExecutionWitness) *Block {
transactions: b.transactions, transactions: b.transactions,
uncles: b.uncles, uncles: b.uncles,
withdrawals: b.withdrawals, withdrawals: b.withdrawals,
requests: b.requests,
witness: witness, witness: witness,
} }
} }

103
core/types/deposit.go Normal file
View file

@ -0,0 +1,103 @@
// Copyright 2024 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package types
import (
"bytes"
"encoding/binary"
"fmt"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/rlp"
)
//go:generate go run github.com/fjl/gencodec -type Deposit -field-override depositMarshaling -out gen_deposit_json.go
// Deposit contains EIP-6110 deposit data.
type Deposit struct {
PublicKey [48]byte `json:"pubkey"` // public key of validator
WithdrawalCredentials common.Hash `json:"withdrawalCredentials"` // beneficiary of the validator funds
Amount uint64 `json:"amount"` // deposit size in Gwei
Signature [96]byte `json:"signature"` // signature over deposit msg
Index uint64 `json:"index"` // deposit count value
}
// field type overrides for gencodec
type depositMarshaling struct {
PublicKey hexutil.Bytes
WithdrawalCredentials hexutil.Bytes
Amount hexutil.Uint64
Signature hexutil.Bytes
Index hexutil.Uint64
}
// Deposits implements DerivableList for requests.
type Deposits []*Deposit
// Len returns the length of s.
func (s Deposits) Len() int { return len(s) }
// EncodeIndex encodes the i'th deposit to s.
func (s Deposits) EncodeIndex(i int, w *bytes.Buffer) {
rlp.Encode(w, s[i])
}
// UnpackIntoDeposit unpacks a serialized DepositEvent.
func UnpackIntoDeposit(data []byte) (*Deposit, error) {
if len(data) != 576 {
return nil, fmt.Errorf("deposit wrong length: want 576, have %d", len(data))
}
var d Deposit
// The ABI encodes the position of dynamic elements first. Since there are 5
// elements, skip over the positional data. The first 32 bytes of dynamic
// elements also encode their actual length. Skip over that value too.
b := 32*5 + 32
// PublicKey is the first element. ABI encoding pads values to 32 bytes, so
// despite BLS public keys being length 48, the value length here is 64. Then
// skip over the next length value.
copy(d.PublicKey[:], data[b:b+48])
b += 48 + 16 + 32
// WithdrawalCredentials is 32 bytes. Read that value then skip over next
// length.
copy(d.WithdrawalCredentials[:], data[b:b+32])
b += 32 + 32
// Amount is 8 bytes, but it is padded to 32. Skip over it and the next
// length.
d.Amount = binary.LittleEndian.Uint64(data[b : b+8])
b += 8 + 24 + 32
// Signature is 96 bytes. Skip over it and the next length.
copy(d.Signature[:], data[b:b+96])
b += 96 + 32
// Amount is 8 bytes.
d.Index = binary.LittleEndian.Uint64(data[b : b+8])
return &d, nil
}
func (d *Deposit) requestType() byte { return DepositRequestType }
func (d *Deposit) encode(b *bytes.Buffer) error { return rlp.Encode(b, d) }
func (d *Deposit) decode(input []byte) error { return rlp.DecodeBytes(input, d) }
func (d *Deposit) copy() RequestData {
return &Deposit{
PublicKey: d.PublicKey,
WithdrawalCredentials: d.WithdrawalCredentials,
Amount: d.Amount,
Signature: d.Signature,
Index: d.Index,
}
}

View file

@ -0,0 +1,93 @@
// Copyright 2024 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package types
import (
"encoding/binary"
"reflect"
"testing"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
)
var (
depositABI = abi.ABI{Methods: map[string]abi.Method{"DepositEvent": depositEvent}}
bytesT, _ = abi.NewType("bytes", "", nil)
depositEvent = abi.NewMethod("DepositEvent", "DepositEvent", abi.Function, "", false, false, []abi.Argument{
{Name: "pubkey", Type: bytesT, Indexed: false},
{Name: "withdrawal_credentials", Type: bytesT, Indexed: false},
{Name: "amount", Type: bytesT, Indexed: false},
{Name: "signature", Type: bytesT, Indexed: false},
{Name: "index", Type: bytesT, Indexed: false}}, nil,
)
)
// FuzzUnpackIntoDeposit tries roundtrip packing and unpacking of deposit events.
func FuzzUnpackIntoDeposit(f *testing.F) {
for _, tt := range []struct {
pubkey string
wxCred string
amount string
sig string
index string
}{
{
pubkey: "111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111",
wxCred: "2222222222222222222222222222222222222222222222222222222222222222",
amount: "3333333333333333",
sig: "444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444",
index: "5555555555555555",
},
} {
f.Add(common.FromHex(tt.pubkey), common.FromHex(tt.wxCred), common.FromHex(tt.amount), common.FromHex(tt.sig), common.FromHex(tt.index))
}
f.Fuzz(func(t *testing.T, p []byte, w []byte, a []byte, s []byte, i []byte) {
var (
pubkey [48]byte
wxCred [32]byte
amount [8]byte
sig [96]byte
index [8]byte
)
copy(pubkey[:], p)
copy(wxCred[:], w)
copy(amount[:], a)
copy(sig[:], s)
copy(index[:], i)
want := Deposit{
PublicKey: pubkey,
WithdrawalCredentials: wxCred,
Amount: binary.LittleEndian.Uint64(amount[:]),
Signature: sig,
Index: binary.LittleEndian.Uint64(index[:]),
}
out, err := depositABI.Pack("DepositEvent", want.PublicKey[:], want.WithdrawalCredentials[:], amount[:], want.Signature[:], index[:])
if err != nil {
t.Fatalf("error packing deposit: %v", err)
}
got, err := UnpackIntoDeposit(out[4:])
if err != nil {
t.Errorf("error unpacking deposit: %v", err)
}
if !reflect.DeepEqual(want, *got) {
t.Errorf("roundtrip failed: want %v, got %v", want, got)
}
})
}

View file

@ -0,0 +1,70 @@
// Code generated by github.com/fjl/gencodec. DO NOT EDIT.
package types
import (
"encoding/json"
"errors"
"github.com/ethereum/go-ethereum/common/hexutil"
)
var _ = (*depositMarshaling)(nil)
// MarshalJSON marshals as JSON.
func (d Deposit) MarshalJSON() ([]byte, error) {
type Deposit struct {
PublicKey hexutil.Bytes `json:"pubkey"`
WithdrawalCredentials hexutil.Bytes `json:"withdrawalCredentials"`
Amount hexutil.Uint64 `json:"amount"`
Signature hexutil.Bytes `json:"signature"`
Index hexutil.Uint64 `json:"index"`
}
var enc Deposit
enc.PublicKey = d.PublicKey[:]
enc.WithdrawalCredentials = d.WithdrawalCredentials[:]
enc.Amount = hexutil.Uint64(d.Amount)
enc.Signature = d.Signature[:]
enc.Index = hexutil.Uint64(d.Index)
return json.Marshal(&enc)
}
// UnmarshalJSON unmarshals from JSON.
func (d *Deposit) UnmarshalJSON(input []byte) error {
type Deposit struct {
PublicKey *hexutil.Bytes `json:"pubkey"`
WithdrawalCredentials *hexutil.Bytes `json:"withdrawalCredentials"`
Amount *hexutil.Uint64 `json:"amount"`
Signature *hexutil.Bytes `json:"signature"`
Index *hexutil.Uint64 `json:"index"`
}
var dec Deposit
if err := json.Unmarshal(input, &dec); err != nil {
return err
}
if dec.PublicKey != nil {
if len(*dec.PublicKey) != len(d.PublicKey) {
return errors.New("field 'pubkey' has wrong length, need 48 items")
}
copy(d.PublicKey[:], *dec.PublicKey)
}
if dec.WithdrawalCredentials != nil {
if len(*dec.WithdrawalCredentials) != len(d.WithdrawalCredentials) {
return errors.New("field 'withdrawalCredentials' has wrong length, need 32 items")
}
copy(d.WithdrawalCredentials[:], *dec.WithdrawalCredentials)
}
if dec.Amount != nil {
d.Amount = uint64(*dec.Amount)
}
if dec.Signature != nil {
if len(*dec.Signature) != len(d.Signature) {
return errors.New("field 'signature' has wrong length, need 96 items")
}
copy(d.Signature[:], *dec.Signature)
}
if dec.Index != nil {
d.Index = uint64(*dec.Index)
}
return nil
}

View file

@ -36,6 +36,7 @@ func (h Header) MarshalJSON() ([]byte, error) {
BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed" rlp:"optional"` BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed" rlp:"optional"`
ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas" rlp:"optional"` ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas" rlp:"optional"`
ParentBeaconRoot *common.Hash `json:"parentBeaconBlockRoot" rlp:"optional"` ParentBeaconRoot *common.Hash `json:"parentBeaconBlockRoot" rlp:"optional"`
RequestsHash *common.Hash `json:"requestsRoot" rlp:"optional"`
Hash common.Hash `json:"hash"` Hash common.Hash `json:"hash"`
} }
var enc Header var enc Header
@ -59,6 +60,7 @@ func (h Header) MarshalJSON() ([]byte, error) {
enc.BlobGasUsed = (*hexutil.Uint64)(h.BlobGasUsed) enc.BlobGasUsed = (*hexutil.Uint64)(h.BlobGasUsed)
enc.ExcessBlobGas = (*hexutil.Uint64)(h.ExcessBlobGas) enc.ExcessBlobGas = (*hexutil.Uint64)(h.ExcessBlobGas)
enc.ParentBeaconRoot = h.ParentBeaconRoot enc.ParentBeaconRoot = h.ParentBeaconRoot
enc.RequestsHash = h.RequestsHash
enc.Hash = h.Hash() enc.Hash = h.Hash()
return json.Marshal(&enc) return json.Marshal(&enc)
} }
@ -86,6 +88,7 @@ func (h *Header) UnmarshalJSON(input []byte) error {
BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed" rlp:"optional"` BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed" rlp:"optional"`
ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas" rlp:"optional"` ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas" rlp:"optional"`
ParentBeaconRoot *common.Hash `json:"parentBeaconBlockRoot" rlp:"optional"` ParentBeaconRoot *common.Hash `json:"parentBeaconBlockRoot" rlp:"optional"`
RequestsHash *common.Hash `json:"requestsRoot" rlp:"optional"`
} }
var dec Header var dec Header
if err := json.Unmarshal(input, &dec); err != nil { if err := json.Unmarshal(input, &dec); err != nil {
@ -163,5 +166,8 @@ func (h *Header) UnmarshalJSON(input []byte) error {
if dec.ParentBeaconRoot != nil { if dec.ParentBeaconRoot != nil {
h.ParentBeaconRoot = dec.ParentBeaconRoot h.ParentBeaconRoot = dec.ParentBeaconRoot
} }
if dec.RequestsHash != nil {
h.RequestsHash = dec.RequestsHash
}
return nil return nil
} }

View file

@ -42,7 +42,8 @@ func (obj *Header) EncodeRLP(_w io.Writer) error {
_tmp3 := obj.BlobGasUsed != nil _tmp3 := obj.BlobGasUsed != nil
_tmp4 := obj.ExcessBlobGas != nil _tmp4 := obj.ExcessBlobGas != nil
_tmp5 := obj.ParentBeaconRoot != nil _tmp5 := obj.ParentBeaconRoot != nil
if _tmp1 || _tmp2 || _tmp3 || _tmp4 || _tmp5 { _tmp6 := obj.RequestsHash != nil
if _tmp1 || _tmp2 || _tmp3 || _tmp4 || _tmp5 || _tmp6 {
if obj.BaseFee == nil { if obj.BaseFee == nil {
w.Write(rlp.EmptyString) w.Write(rlp.EmptyString)
} else { } else {
@ -52,34 +53,41 @@ func (obj *Header) EncodeRLP(_w io.Writer) error {
w.WriteBigInt(obj.BaseFee) w.WriteBigInt(obj.BaseFee)
} }
} }
if _tmp2 || _tmp3 || _tmp4 || _tmp5 { if _tmp2 || _tmp3 || _tmp4 || _tmp5 || _tmp6 {
if obj.WithdrawalsHash == nil { if obj.WithdrawalsHash == nil {
w.Write([]byte{0x80}) w.Write([]byte{0x80})
} else { } else {
w.WriteBytes(obj.WithdrawalsHash[:]) w.WriteBytes(obj.WithdrawalsHash[:])
} }
} }
if _tmp3 || _tmp4 || _tmp5 { if _tmp3 || _tmp4 || _tmp5 || _tmp6 {
if obj.BlobGasUsed == nil { if obj.BlobGasUsed == nil {
w.Write([]byte{0x80}) w.Write([]byte{0x80})
} else { } else {
w.WriteUint64((*obj.BlobGasUsed)) w.WriteUint64((*obj.BlobGasUsed))
} }
} }
if _tmp4 || _tmp5 { if _tmp4 || _tmp5 || _tmp6 {
if obj.ExcessBlobGas == nil { if obj.ExcessBlobGas == nil {
w.Write([]byte{0x80}) w.Write([]byte{0x80})
} else { } else {
w.WriteUint64((*obj.ExcessBlobGas)) w.WriteUint64((*obj.ExcessBlobGas))
} }
} }
if _tmp5 { if _tmp5 || _tmp6 {
if obj.ParentBeaconRoot == nil { if obj.ParentBeaconRoot == nil {
w.Write([]byte{0x80}) w.Write([]byte{0x80})
} else { } else {
w.WriteBytes(obj.ParentBeaconRoot[:]) w.WriteBytes(obj.ParentBeaconRoot[:])
} }
} }
if _tmp6 {
if obj.RequestsHash == nil {
w.Write([]byte{0x80})
} else {
w.WriteBytes(obj.RequestsHash[:])
}
}
w.ListEnd(_tmp0) w.ListEnd(_tmp0)
return w.Flush() return w.Flush()
} }

View file

@ -41,6 +41,9 @@ var (
// EmptyWithdrawalsHash is the known hash of the empty withdrawal set. // EmptyWithdrawalsHash is the known hash of the empty withdrawal set.
EmptyWithdrawalsHash = common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421") EmptyWithdrawalsHash = common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
// EmptyRequestsHash is the known hash of the empty requests set.
EmptyRequestsHash = common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
// EmptyVerkleHash is the known hash of an empty verkle trie. // EmptyVerkleHash is the known hash of an empty verkle trie.
EmptyVerkleHash = common.Hash{} EmptyVerkleHash = common.Hash{}
) )

157
core/types/request.go Normal file
View file

@ -0,0 +1,157 @@
// Copyright 2024 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package types
import (
"bytes"
"errors"
"fmt"
"io"
"github.com/ethereum/go-ethereum/rlp"
)
var (
ErrRequestTypeNotSupported = errors.New("request type not supported")
errShortTypedRequest = errors.New("typed request too short")
)
// Request types.
const (
DepositRequestType = 0x00
)
// Request is an EIP-7685 request object. It represents execution layer
// triggered messages bound for the consensus layer.
type Request struct {
inner RequestData
}
// Type returns the EIP-7685 type of the request.
func (r *Request) Type() byte {
return r.inner.requestType()
}
// Inner returns the inner request data.
func (r *Request) Inner() RequestData {
return r.inner
}
// NewRequest creates a new request.
func NewRequest(inner RequestData) *Request {
req := new(Request)
req.inner = inner.copy()
return req
}
// Requests implements DerivableList for requests.
type Requests []*Request
// Len returns the length of s.
func (s Requests) Len() int { return len(s) }
// EncodeIndex encodes the i'th request to s.
func (s Requests) EncodeIndex(i int, w *bytes.Buffer) {
s[i].encode(w)
}
// RequestData is the underlying data of a request.
type RequestData interface {
requestType() byte
encode(*bytes.Buffer) error
decode([]byte) error
copy() RequestData // creates a deep copy and initializes all fields
}
// EncodeRLP implements rlp.Encoder
func (r *Request) EncodeRLP(w io.Writer) error {
buf := encodeBufferPool.Get().(*bytes.Buffer)
defer encodeBufferPool.Put(buf)
buf.Reset()
if err := r.encode(buf); err != nil {
return err
}
return rlp.Encode(w, buf.Bytes())
}
// encode writes the canonical encoding of a request to w.
func (r *Request) encode(w *bytes.Buffer) error {
w.WriteByte(r.Type())
return r.inner.encode(w)
}
// MarshalBinary returns the canonical encoding of the request.
func (r *Request) MarshalBinary() ([]byte, error) {
var buf bytes.Buffer
err := r.encode(&buf)
return buf.Bytes(), err
}
// DecodeRLP implements rlp.Decoder
func (r *Request) DecodeRLP(s *rlp.Stream) error {
kind, size, err := s.Kind()
switch {
case err != nil:
return err
case kind == rlp.List:
return fmt.Errorf("untyped request")
case kind == rlp.Byte:
return errShortTypedRequest
default:
// First read the request payload bytes into a temporary buffer.
b, buf, err := getPooledBuffer(size)
if err != nil {
return err
}
defer encodeBufferPool.Put(buf)
if err := s.ReadBytes(b); err != nil {
return err
}
// Now decode the inner request.
inner, err := r.decode(b)
if err == nil {
r.inner = inner
}
return err
}
}
// UnmarshalBinary decodes the canonical encoding of requests.
func (r *Request) UnmarshalBinary(b []byte) error {
inner, err := r.decode(b)
if err != nil {
return err
}
r.inner = inner
return nil
}
// decode decodes a request from the canonical format.
func (r *Request) decode(b []byte) (RequestData, error) {
if len(b) <= 1 {
return nil, errShortTypedRequest
}
var inner RequestData
switch b[0] {
case DepositRequestType:
inner = new(Deposit)
default:
return nil, ErrRequestTypeNotSupported
}
err := inner.decode(b[1:])
return inner, err
}

View file

@ -216,11 +216,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
if config.OverrideVerkle != nil { if config.OverrideVerkle != nil {
overrides.OverrideVerkle = config.OverrideVerkle overrides.OverrideVerkle = config.OverrideVerkle
} }
// TODO (MariusVanDerWijden) get rid of shouldPreserve in a follow-up PR eth.blockchain, err = core.NewBlockChain(chainDb, cacheConfig, config.Genesis, &overrides, eth.engine, vmConfig, &config.TransactionHistory)
shouldPreserve := func(header *types.Header) bool {
return false
}
eth.blockchain, err = core.NewBlockChain(chainDb, cacheConfig, config.Genesis, &overrides, eth.engine, vmConfig, shouldPreserve, &config.TransactionHistory)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -86,11 +86,15 @@ var caps = []string{
"engine_getPayloadV1", "engine_getPayloadV1",
"engine_getPayloadV2", "engine_getPayloadV2",
"engine_getPayloadV3", "engine_getPayloadV3",
"engine_getPayloadV4",
"engine_newPayloadV1", "engine_newPayloadV1",
"engine_newPayloadV2", "engine_newPayloadV2",
"engine_newPayloadV3", "engine_newPayloadV3",
"engine_newPayloadV4",
"engine_getPayloadBodiesByHashV1", "engine_getPayloadBodiesByHashV1",
"engine_getPayloadBodiesByHashV2",
"engine_getPayloadBodiesByRangeV1", "engine_getPayloadBodiesByRangeV1",
"engine_getPayloadBodiesByRangeV2",
"engine_getClientVersionV1", "engine_getClientVersionV1",
} }
@ -220,7 +224,7 @@ func (api *ConsensusAPI) ForkchoiceUpdatedV3(update engine.ForkchoiceStateV1, pa
if params.BeaconRoot == nil { if params.BeaconRoot == nil {
return engine.STATUS_INVALID, engine.InvalidPayloadAttributes.With(errors.New("missing beacon root")) return engine.STATUS_INVALID, engine.InvalidPayloadAttributes.With(errors.New("missing beacon root"))
} }
if api.eth.BlockChain().Config().LatestFork(params.Timestamp) != forks.Cancun { if api.eth.BlockChain().Config().LatestFork(params.Timestamp) != forks.Cancun && api.eth.BlockChain().Config().LatestFork(params.Timestamp) != forks.Prague {
return engine.STATUS_INVALID, engine.UnsupportedFork.With(errors.New("forkchoiceUpdatedV3 must only be called for cancun payloads")) return engine.STATUS_INVALID, engine.UnsupportedFork.With(errors.New("forkchoiceUpdatedV3 must only be called for cancun payloads"))
} }
} }
@ -443,6 +447,14 @@ func (api *ConsensusAPI) GetPayloadV3(payloadID engine.PayloadID) (*engine.Execu
return api.getPayload(payloadID, false) return api.getPayload(payloadID, false)
} }
// GetPayloadV4 returns a cached payload by id.
func (api *ConsensusAPI) GetPayloadV4(payloadID engine.PayloadID) (*engine.ExecutionPayloadEnvelope, error) {
if !payloadID.Is(engine.PayloadV4) {
return nil, engine.UnsupportedFork
}
return api.getPayload(payloadID, false)
}
func (api *ConsensusAPI) getPayload(payloadID engine.PayloadID, full bool) (*engine.ExecutionPayloadEnvelope, error) { func (api *ConsensusAPI) getPayload(payloadID engine.PayloadID, full bool) (*engine.ExecutionPayloadEnvelope, error) {
log.Trace("Engine API request received", "method", "GetPayload", "id", payloadID) log.Trace("Engine API request received", "method", "GetPayload", "id", payloadID)
data := api.localBlocks.get(payloadID, full) data := api.localBlocks.get(payloadID, full)
@ -508,6 +520,34 @@ func (api *ConsensusAPI) NewPayloadV3(params engine.ExecutableData, versionedHas
return api.newPayload(params, versionedHashes, beaconRoot) return api.newPayload(params, versionedHashes, beaconRoot)
} }
// NewPayloadV4 creates an Eth1 block, inserts it in the chain, and returns the status of the chain.
func (api *ConsensusAPI) NewPayloadV4(params engine.ExecutableData, versionedHashes []common.Hash, beaconRoot *common.Hash) (engine.PayloadStatusV1, error) {
if params.Withdrawals == nil {
return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("nil withdrawals post-shanghai"))
}
if params.ExcessBlobGas == nil {
return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("nil excessBlobGas post-cancun"))
}
if params.BlobGasUsed == nil {
return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("nil blobGasUsed post-cancun"))
}
if params.Deposits == nil {
return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("nil deposits post-prague"))
}
if versionedHashes == nil {
return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("nil versionedHashes post-cancun"))
}
if beaconRoot == nil {
return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("nil beaconRoot post-cancun"))
}
if api.eth.BlockChain().Config().LatestFork(params.Timestamp) != forks.Prague {
return engine.PayloadStatusV1{Status: engine.INVALID}, engine.UnsupportedFork.With(errors.New("newPayloadV4 must only be called for prague payloads"))
}
return api.newPayload(params, versionedHashes, beaconRoot)
}
func (api *ConsensusAPI) newPayload(params engine.ExecutableData, versionedHashes []common.Hash, beaconRoot *common.Hash) (engine.PayloadStatusV1, error) { func (api *ConsensusAPI) newPayload(params engine.ExecutableData, versionedHashes []common.Hash, beaconRoot *common.Hash) (engine.PayloadStatusV1, error) {
// The locking here is, strictly, not required. Without these locks, this can happen: // The locking here is, strictly, not required. Without these locks, this can happen:
// //
@ -553,6 +593,7 @@ func (api *ConsensusAPI) newPayload(params engine.ExecutableData, versionedHashe
"params.ExcessBlobGas", ebg, "params.ExcessBlobGas", ebg,
"len(params.Transactions)", len(params.Transactions), "len(params.Transactions)", len(params.Transactions),
"len(params.Withdrawals)", len(params.Withdrawals), "len(params.Withdrawals)", len(params.Withdrawals),
"len(params.Deposits)", len(params.Deposits),
"beaconRoot", beaconRoot, "beaconRoot", beaconRoot,
"error", err) "error", err)
return api.invalid(err, nil), nil return api.invalid(err, nil), nil
@ -826,8 +867,25 @@ func (api *ConsensusAPI) GetClientVersionV1(info engine.ClientVersionV1) []engin
// GetPayloadBodiesByHashV1 implements engine_getPayloadBodiesByHashV1 which allows for retrieval of a list // GetPayloadBodiesByHashV1 implements engine_getPayloadBodiesByHashV1 which allows for retrieval of a list
// of block bodies by the engine api. // of block bodies by the engine api.
func (api *ConsensusAPI) GetPayloadBodiesByHashV1(hashes []common.Hash) []*engine.ExecutionPayloadBodyV1 { func (api *ConsensusAPI) GetPayloadBodiesByHashV1(hashes []common.Hash) []*engine.ExecutionPayloadBody {
bodies := make([]*engine.ExecutionPayloadBodyV1, len(hashes)) bodies := make([]*engine.ExecutionPayloadBody, len(hashes))
for i, hash := range hashes {
block := api.eth.BlockChain().GetBlockByHash(hash)
body := getBody(block)
if body != nil {
// Nil out the V2 values, clients should know to not request V1 objects
// after Prague.
body.Deposits = nil
}
bodies[i] = body
}
return bodies
}
// GetPayloadBodiesByHashV2 implements engine_getPayloadBodiesByHashV1 which allows for retrieval of a list
// of block bodies by the engine api.
func (api *ConsensusAPI) GetPayloadBodiesByHashV2(hashes []common.Hash) []*engine.ExecutionPayloadBody {
bodies := make([]*engine.ExecutionPayloadBody, len(hashes))
for i, hash := range hashes { for i, hash := range hashes {
block := api.eth.BlockChain().GetBlockByHash(hash) block := api.eth.BlockChain().GetBlockByHash(hash)
bodies[i] = getBody(block) bodies[i] = getBody(block)
@ -837,7 +895,28 @@ func (api *ConsensusAPI) GetPayloadBodiesByHashV1(hashes []common.Hash) []*engin
// GetPayloadBodiesByRangeV1 implements engine_getPayloadBodiesByRangeV1 which allows for retrieval of a range // GetPayloadBodiesByRangeV1 implements engine_getPayloadBodiesByRangeV1 which allows for retrieval of a range
// of block bodies by the engine api. // of block bodies by the engine api.
func (api *ConsensusAPI) GetPayloadBodiesByRangeV1(start, count hexutil.Uint64) ([]*engine.ExecutionPayloadBodyV1, error) { func (api *ConsensusAPI) GetPayloadBodiesByRangeV1(start, count hexutil.Uint64) ([]*engine.ExecutionPayloadBody, error) {
bodies, err := api.getBodiesByRange(start, count)
if err != nil {
return nil, err
}
// Nil out the V2 values, clients should know to not request V1 objects
// after Prague.
for i := range bodies {
if bodies[i] != nil {
bodies[i].Deposits = nil
}
}
return bodies, nil
}
// GetPayloadBodiesByRangeV2 implements engine_getPayloadBodiesByRangeV1 which allows for retrieval of a range
// of block bodies by the engine api.
func (api *ConsensusAPI) GetPayloadBodiesByRangeV2(start, count hexutil.Uint64) ([]*engine.ExecutionPayloadBody, error) {
return api.getBodiesByRange(start, count)
}
func (api *ConsensusAPI) getBodiesByRange(start, count hexutil.Uint64) ([]*engine.ExecutionPayloadBody, error) {
if start == 0 || count == 0 { if start == 0 || count == 0 {
return nil, engine.InvalidParams.With(fmt.Errorf("invalid start or count, start: %v count: %v", start, count)) return nil, engine.InvalidParams.With(fmt.Errorf("invalid start or count, start: %v count: %v", start, count))
} }
@ -850,7 +929,7 @@ func (api *ConsensusAPI) GetPayloadBodiesByRangeV1(start, count hexutil.Uint64)
if last > current { if last > current {
last = current last = current
} }
bodies := make([]*engine.ExecutionPayloadBodyV1, 0, uint64(count)) bodies := make([]*engine.ExecutionPayloadBody, 0, uint64(count))
for i := uint64(start); i <= last; i++ { for i := uint64(start); i <= last; i++ {
block := api.eth.BlockChain().GetBlockByNumber(i) block := api.eth.BlockChain().GetBlockByNumber(i)
bodies = append(bodies, getBody(block)) bodies = append(bodies, getBody(block))
@ -858,7 +937,7 @@ func (api *ConsensusAPI) GetPayloadBodiesByRangeV1(start, count hexutil.Uint64)
return bodies, nil return bodies, nil
} }
func getBody(block *types.Block) *engine.ExecutionPayloadBodyV1 { func getBody(block *types.Block) *engine.ExecutionPayloadBody {
if block == nil { if block == nil {
return nil return nil
} }
@ -867,6 +946,7 @@ func getBody(block *types.Block) *engine.ExecutionPayloadBodyV1 {
body = block.Body() body = block.Body()
txs = make([]hexutil.Bytes, len(body.Transactions)) txs = make([]hexutil.Bytes, len(body.Transactions))
withdrawals = body.Withdrawals withdrawals = body.Withdrawals
depositRequests types.Deposits
) )
for j, tx := range body.Transactions { for j, tx := range body.Transactions {
@ -878,8 +958,20 @@ func getBody(block *types.Block) *engine.ExecutionPayloadBodyV1 {
withdrawals = make([]*types.Withdrawal, 0) withdrawals = make([]*types.Withdrawal, 0)
} }
return &engine.ExecutionPayloadBodyV1{ if block.Header().RequestsHash != nil {
// TODO: this isn't future proof because we can't determine if a request
// type has activated yet or if there are just no requests of that type from
// only the block.
for _, req := range block.Requests() {
if d, ok := req.Inner().(*types.Deposit); ok {
depositRequests = append(depositRequests, d)
}
}
}
return &engine.ExecutionPayloadBody{
TransactionData: txs, TransactionData: txs,
Withdrawals: withdrawals, Withdrawals: withdrawals,
Deposits: depositRequests,
} }
} }

View file

@ -74,6 +74,12 @@ func generateMergeChain(n int, merged bool) (*core.Genesis, []*types.Block) {
Alloc: types.GenesisAlloc{ Alloc: types.GenesisAlloc{
testAddr: {Balance: testBalance}, testAddr: {Balance: testBalance},
params.BeaconRootsAddress: {Balance: common.Big0, Code: common.Hex2Bytes("3373fffffffffffffffffffffffffffffffffffffffe14604457602036146024575f5ffd5b620180005f350680545f35146037575f5ffd5b6201800001545f5260205ff35b6201800042064281555f359062018000015500")}, params.BeaconRootsAddress: {Balance: common.Big0, Code: common.Hex2Bytes("3373fffffffffffffffffffffffffffffffffffffffe14604457602036146024575f5ffd5b620180005f350680545f35146037575f5ffd5b6201800001545f5260205ff35b6201800042064281555f359062018000015500")},
config.DepositContractAddress: {
// Simple deposit generator, source: https://gist.github.com/lightclient/54abb2af2465d6969fa6d1920b9ad9d7
Code: common.Hex2Bytes("6080604052366103aa575f603067ffffffffffffffff811115610025576100246103ae565b5b6040519080825280601f01601f1916602001820160405280156100575781602001600182028036833780820191505090505b5090505f8054906101000a900460ff1660f81b815f8151811061007d5761007c6103db565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053505f602067ffffffffffffffff8111156100c7576100c66103ae565b5b6040519080825280601f01601f1916602001820160405280156100f95781602001600182028036833780820191505090505b5090505f8054906101000a900460ff1660f81b815f8151811061011f5761011e6103db565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053505f600867ffffffffffffffff811115610169576101686103ae565b5b6040519080825280601f01601f19166020018201604052801561019b5781602001600182028036833780820191505090505b5090505f8054906101000a900460ff1660f81b815f815181106101c1576101c06103db565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053505f606067ffffffffffffffff81111561020b5761020a6103ae565b5b6040519080825280601f01601f19166020018201604052801561023d5781602001600182028036833780820191505090505b5090505f8054906101000a900460ff1660f81b815f81518110610263576102626103db565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053505f600867ffffffffffffffff8111156102ad576102ac6103ae565b5b6040519080825280601f01601f1916602001820160405280156102df5781602001600182028036833780820191505090505b5090505f8054906101000a900460ff1660f81b815f81518110610305576103046103db565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053505f8081819054906101000a900460ff168092919061035090610441565b91906101000a81548160ff021916908360ff160217905550507f649bbc62d0e31342afea4e5cd82d4049e7e1ee912fc0889aa790803be39038c585858585856040516103a09594939291906104d9565b60405180910390a1005b5f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f60ff82169050919050565b5f61044b82610435565b915060ff820361045e5761045d610408565b5b600182019050919050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f6104ab82610469565b6104b58185610473565b93506104c5818560208601610483565b6104ce81610491565b840191505092915050565b5f60a0820190508181035f8301526104f181886104a1565b9050818103602083015261050581876104a1565b9050818103604083015261051981866104a1565b9050818103606083015261052d81856104a1565b9050818103608083015261054181846104a1565b9050969550505050505056fea26469706673582212208569967e58690162d7d6fe3513d07b393b4c15e70f41505cbbfd08f53eba739364736f6c63430008190033"),
Nonce: 0,
Balance: big.NewInt(0),
},
}, },
ExtraData: []byte("test genesis"), ExtraData: []byte("test genesis"),
Timestamp: 9000, Timestamp: 9000,
@ -483,10 +489,10 @@ func TestFullAPI(t *testing.T) {
ethservice.TxPool().Add([]*types.Transaction{tx}, true, false) ethservice.TxPool().Add([]*types.Transaction{tx}, true, false)
} }
setupBlocks(t, ethservice, 10, parent, callback, nil) setupBlocks(t, ethservice, 10, parent, callback, nil, nil)
} }
func setupBlocks(t *testing.T, ethservice *eth.Ethereum, n int, parent *types.Header, callback func(parent *types.Header), withdrawals [][]*types.Withdrawal) []*types.Header { func setupBlocks(t *testing.T, ethservice *eth.Ethereum, n int, parent *types.Header, callback func(parent *types.Header), withdrawals [][]*types.Withdrawal, beaconRoots []common.Hash) []*types.Header {
api := NewConsensusAPI(ethservice) api := NewConsensusAPI(ethservice)
var blocks []*types.Header var blocks []*types.Header
for i := 0; i < n; i++ { for i := 0; i < n; i++ {
@ -495,14 +501,18 @@ func setupBlocks(t *testing.T, ethservice *eth.Ethereum, n int, parent *types.He
if withdrawals != nil { if withdrawals != nil {
w = withdrawals[i] w = withdrawals[i]
} }
var h *common.Hash
if beaconRoots != nil {
h = &beaconRoots[i]
}
payload := getNewPayload(t, api, parent, w) payload := getNewPayload(t, api, parent, w, h)
execResp, err := api.NewPayloadV2(*payload) execResp, err := api.newPayload(*payload, []common.Hash{}, h)
if err != nil { if err != nil {
t.Fatalf("can't execute payload: %v", err) t.Fatalf("can't execute payload: %v", err)
} }
if execResp.Status != engine.VALID { if execResp.Status != engine.VALID {
t.Fatalf("invalid status: %v", execResp.Status) t.Fatalf("invalid status: %v %s", execResp.Status, *execResp.ValidationError)
} }
fcState := engine.ForkchoiceStateV1{ fcState := engine.ForkchoiceStateV1{
HeadBlockHash: payload.BlockHash, HeadBlockHash: payload.BlockHash,
@ -690,10 +700,10 @@ func TestEmptyBlocks(t *testing.T) {
api := NewConsensusAPI(ethservice) api := NewConsensusAPI(ethservice)
// Setup 10 blocks on the canonical chain // Setup 10 blocks on the canonical chain
setupBlocks(t, ethservice, 10, commonAncestor, func(parent *types.Header) {}, nil) setupBlocks(t, ethservice, 10, commonAncestor, func(parent *types.Header) {}, nil, nil)
// (1) check LatestValidHash by sending a normal payload (P1'') // (1) check LatestValidHash by sending a normal payload (P1'')
payload := getNewPayload(t, api, commonAncestor, nil) payload := getNewPayload(t, api, commonAncestor, nil, nil)
status, err := api.NewPayloadV1(*payload) status, err := api.NewPayloadV1(*payload)
if err != nil { if err != nil {
@ -707,7 +717,7 @@ func TestEmptyBlocks(t *testing.T) {
} }
// (2) Now send P1' which is invalid // (2) Now send P1' which is invalid
payload = getNewPayload(t, api, commonAncestor, nil) payload = getNewPayload(t, api, commonAncestor, nil, nil)
payload.GasUsed += 1 payload.GasUsed += 1
payload = setBlockhash(payload) payload = setBlockhash(payload)
// Now latestValidHash should be the common ancestor // Now latestValidHash should be the common ancestor
@ -725,7 +735,7 @@ func TestEmptyBlocks(t *testing.T) {
} }
// (3) Now send a payload with unknown parent // (3) Now send a payload with unknown parent
payload = getNewPayload(t, api, commonAncestor, nil) payload = getNewPayload(t, api, commonAncestor, nil, nil)
payload.ParentHash = common.Hash{1} payload.ParentHash = common.Hash{1}
payload = setBlockhash(payload) payload = setBlockhash(payload)
// Now latestValidHash should be the common ancestor // Now latestValidHash should be the common ancestor
@ -741,12 +751,13 @@ func TestEmptyBlocks(t *testing.T) {
} }
} }
func getNewPayload(t *testing.T, api *ConsensusAPI, parent *types.Header, withdrawals []*types.Withdrawal) *engine.ExecutableData { func getNewPayload(t *testing.T, api *ConsensusAPI, parent *types.Header, withdrawals []*types.Withdrawal, beaconRoot *common.Hash) *engine.ExecutableData {
params := engine.PayloadAttributes{ params := engine.PayloadAttributes{
Timestamp: parent.Time + 1, Timestamp: parent.Time + 1,
Random: crypto.Keccak256Hash([]byte{byte(1)}), Random: crypto.Keccak256Hash([]byte{byte(1)}),
SuggestedFeeRecipient: parent.Coinbase, SuggestedFeeRecipient: parent.Coinbase,
Withdrawals: withdrawals, Withdrawals: withdrawals,
BeaconRoot: beaconRoot,
} }
payload, err := assembleBlock(api, parent.Hash(), &params) payload, err := assembleBlock(api, parent.Hash(), &params)
@ -814,7 +825,7 @@ func TestTrickRemoteBlockCache(t *testing.T) {
commonAncestor := ethserviceA.BlockChain().CurrentBlock() commonAncestor := ethserviceA.BlockChain().CurrentBlock()
// Setup 10 blocks on the canonical chain // Setup 10 blocks on the canonical chain
setupBlocks(t, ethserviceA, 10, commonAncestor, func(parent *types.Header) {}, nil) setupBlocks(t, ethserviceA, 10, commonAncestor, func(parent *types.Header) {}, nil, nil)
commonAncestor = ethserviceA.BlockChain().CurrentBlock() commonAncestor = ethserviceA.BlockChain().CurrentBlock()
var invalidChain []*engine.ExecutableData var invalidChain []*engine.ExecutableData
@ -823,7 +834,7 @@ func TestTrickRemoteBlockCache(t *testing.T) {
//invalidChain = append(invalidChain, payload1) //invalidChain = append(invalidChain, payload1)
// create an invalid payload2 (P2) // create an invalid payload2 (P2)
payload2 := getNewPayload(t, apiA, commonAncestor, nil) payload2 := getNewPayload(t, apiA, commonAncestor, nil, nil)
//payload2.ParentHash = payload1.BlockHash //payload2.ParentHash = payload1.BlockHash
payload2.GasUsed += 1 payload2.GasUsed += 1
payload2 = setBlockhash(payload2) payload2 = setBlockhash(payload2)
@ -832,7 +843,7 @@ func TestTrickRemoteBlockCache(t *testing.T) {
head := payload2 head := payload2
// create some valid payloads on top // create some valid payloads on top
for i := 0; i < 10; i++ { for i := 0; i < 10; i++ {
payload := getNewPayload(t, apiA, commonAncestor, nil) payload := getNewPayload(t, apiA, commonAncestor, nil, nil)
payload.ParentHash = head.BlockHash payload.ParentHash = head.BlockHash
payload = setBlockhash(payload) payload = setBlockhash(payload)
invalidChain = append(invalidChain, payload) invalidChain = append(invalidChain, payload)
@ -869,10 +880,10 @@ func TestInvalidBloom(t *testing.T) {
api := NewConsensusAPI(ethservice) api := NewConsensusAPI(ethservice)
// Setup 10 blocks on the canonical chain // Setup 10 blocks on the canonical chain
setupBlocks(t, ethservice, 10, commonAncestor, func(parent *types.Header) {}, nil) setupBlocks(t, ethservice, 10, commonAncestor, func(parent *types.Header) {}, nil, nil)
// (1) check LatestValidHash by sending a normal payload (P1'') // (1) check LatestValidHash by sending a normal payload (P1'')
payload := getNewPayload(t, api, commonAncestor, nil) payload := getNewPayload(t, api, commonAncestor, nil, nil)
payload.LogsBloom = append(payload.LogsBloom, byte(1)) payload.LogsBloom = append(payload.LogsBloom, byte(1))
status, err := api.NewPayloadV1(*payload) status, err := api.NewPayloadV1(*payload)
if err != nil { if err != nil {
@ -1285,24 +1296,35 @@ func TestNilWithdrawals(t *testing.T) {
func setupBodies(t *testing.T) (*node.Node, *eth.Ethereum, []*types.Block) { func setupBodies(t *testing.T) (*node.Node, *eth.Ethereum, []*types.Block) {
genesis, blocks := generateMergeChain(10, true) genesis, blocks := generateMergeChain(10, true)
// enable shanghai on the last block
// Enable next forks on the last block.
time := blocks[len(blocks)-1].Header().Time + 1 time := blocks[len(blocks)-1].Header().Time + 1
genesis.Config.ShanghaiTime = &time genesis.Config.ShanghaiTime = &time
genesis.Config.CancunTime = &time
genesis.Config.PragueTime = &time
n, ethservice := startEthService(t, genesis, blocks) n, ethservice := startEthService(t, genesis, blocks)
var ( var (
parent = ethservice.BlockChain().CurrentBlock()
// This EVM code generates a log when the contract is created. // This EVM code generates a log when the contract is created.
logCode = common.Hex2Bytes("60606040525b7f24ec1d3ff24c2f6ff210738839dbc339cd45a5294d85c79361016243157aae7b60405180905060405180910390a15b600a8060416000396000f360606040526008565b00") logCode = common.Hex2Bytes("60606040525b7f24ec1d3ff24c2f6ff210738839dbc339cd45a5294d85c79361016243157aae7b60405180905060405180910390a15b600a8060416000396000f360606040526008565b00")
parent = ethservice.BlockChain().CurrentBlock()
) )
// Each block, this callback will include two txs that generate body values like logs and requests.
callback := func(parent *types.Header) { callback := func(parent *types.Header) {
statedb, _ := ethservice.BlockChain().StateAt(parent.Root) var (
nonce := statedb.GetNonce(testAddr) statedb, _ = ethservice.BlockChain().StateAt(parent.Root)
tx, _ := types.SignTx(types.NewContractCreation(nonce, new(big.Int), 1000000, big.NewInt(2*params.InitialBaseFee), logCode), types.LatestSigner(ethservice.BlockChain().Config()), testKey) // Create tx to trigger log generator.
ethservice.TxPool().Add([]*types.Transaction{tx}, false, false) tx1, _ = types.SignTx(types.NewContractCreation(statedb.GetNonce(testAddr), new(big.Int), 1000000, big.NewInt(2*params.InitialBaseFee), logCode), types.LatestSigner(ethservice.BlockChain().Config()), testKey)
// Create tx to trigger deposit generator.
tx2, _ = types.SignTx(types.NewTransaction(statedb.GetNonce(testAddr)+1, ethservice.APIBackend.ChainConfig().DepositContractAddress, new(big.Int), 500000, big.NewInt(2*params.InitialBaseFee), nil), types.LatestSigner(ethservice.BlockChain().Config()), testKey)
)
ethservice.TxPool().Add([]*types.Transaction{tx1}, false, false)
ethservice.TxPool().Add([]*types.Transaction{tx2}, false, false)
} }
// Make some withdrawals to include.
withdrawals := make([][]*types.Withdrawal, 10) withdrawals := make([][]*types.Withdrawal, 10)
withdrawals[0] = nil // should be filtered out by miner withdrawals[0] = nil // should be filtered out by miner
withdrawals[1] = make([]*types.Withdrawal, 0) withdrawals[1] = make([]*types.Withdrawal, 0)
@ -1314,12 +1336,20 @@ func setupBodies(t *testing.T) (*node.Node, *eth.Ethereum, []*types.Block) {
} }
} }
postShanghaiHeaders := setupBlocks(t, ethservice, 10, parent, callback, withdrawals) // Make beacon root update for each block.
postShanghaiBlocks := make([]*types.Block, len(postShanghaiHeaders)) beaconRoots := make([]common.Hash, 10)
for i, header := range postShanghaiHeaders { for i := 0; i < 10; i++ {
postShanghaiBlocks[i] = ethservice.BlockChain().GetBlock(header.Hash(), header.Number.Uint64()) beaconRoots[i] = common.Hash{byte(i)}
} }
return n, ethservice, append(blocks, postShanghaiBlocks...)
// Create the blocks.
newHeaders := setupBlocks(t, ethservice, 10, parent, callback, withdrawals, beaconRoots)
newBlocks := make([]*types.Block, len(newHeaders))
for i, header := range newHeaders {
newBlocks[i] = ethservice.BlockChain().GetBlock(header.Hash(), header.Number.Uint64())
}
return n, ethservice, append(blocks, newBlocks...)
} }
func allHashes(blocks []*types.Block) []common.Hash { func allHashes(blocks []*types.Block) []common.Hash {
@ -1384,7 +1414,7 @@ func TestGetBlockBodiesByHash(t *testing.T) {
} }
for k, test := range tests { for k, test := range tests {
result := api.GetPayloadBodiesByHashV1(test.hashes) result := api.GetPayloadBodiesByHashV2(test.hashes)
for i, r := range result { for i, r := range result {
if !equalBody(test.results[i], r) { if !equalBody(test.results[i], r) {
t.Fatalf("test %v: invalid response: expected %+v got %+v", k, test.results[i], r) t.Fatalf("test %v: invalid response: expected %+v got %+v", k, test.results[i], r)
@ -1458,7 +1488,7 @@ func TestGetBlockBodiesByRange(t *testing.T) {
} }
for k, test := range tests { for k, test := range tests {
result, err := api.GetPayloadBodiesByRangeV1(test.start, test.count) result, err := api.GetPayloadBodiesByRangeV2(test.start, test.count)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -1509,7 +1539,7 @@ func TestGetBlockBodiesByRangeInvalidParams(t *testing.T) {
}, },
} }
for i, tc := range tests { for i, tc := range tests {
result, err := api.GetPayloadBodiesByRangeV1(tc.start, tc.count) result, err := api.GetPayloadBodiesByRangeV2(tc.start, tc.count)
if err == nil { if err == nil {
t.Fatalf("test %d: expected error, got %v", i, result) t.Fatalf("test %d: expected error, got %v", i, result)
} }
@ -1519,7 +1549,7 @@ func TestGetBlockBodiesByRangeInvalidParams(t *testing.T) {
} }
} }
func equalBody(a *types.Body, b *engine.ExecutionPayloadBodyV1) bool { func equalBody(a *types.Body, b *engine.ExecutionPayloadBody) bool {
if a == nil && b == nil { if a == nil && b == nil {
return true return true
} else if a == nil || b == nil { } else if a == nil || b == nil {
@ -1534,7 +1564,23 @@ func equalBody(a *types.Body, b *engine.ExecutionPayloadBodyV1) bool {
return false return false
} }
} }
return reflect.DeepEqual(a.Withdrawals, b.Withdrawals)
if !reflect.DeepEqual(a.Withdrawals, b.Withdrawals) {
return false
}
var deposits types.Deposits
if a.Requests != nil {
// If requests is non-nil, it means deposits are available in block and we
// should return an empty slice instead of nil if there are no deposits.
deposits = make(types.Deposits, 0)
}
for _, r := range a.Requests {
if d, ok := r.Inner().(*types.Deposit); ok {
deposits = append(deposits, d)
}
}
return reflect.DeepEqual(deposits, b.Deposits)
} }
func TestBlockToPayloadWithBlobs(t *testing.T) { func TestBlockToPayloadWithBlobs(t *testing.T) {

View file

@ -109,7 +109,7 @@ func NewSimulatedBeacon(period uint64, eth *eth.Ethereum) (*SimulatedBeacon, err
// if genesis block, send forkchoiceUpdated to trigger transition to PoS // if genesis block, send forkchoiceUpdated to trigger transition to PoS
if block.Number.Sign() == 0 { if block.Number.Sign() == 0 {
if _, err := engineAPI.ForkchoiceUpdatedV2(current, nil); err != nil { if _, err := engineAPI.ForkchoiceUpdatedV3(current, nil); err != nil {
return nil, err return nil, err
} }
} }
@ -226,7 +226,7 @@ func (c *SimulatedBeacon) sealBlock(withdrawals []*types.Withdrawal, timestamp u
c.setCurrentState(payload.BlockHash, finalizedHash) c.setCurrentState(payload.BlockHash, finalizedHash)
// Mark the block containing the payload as canonical // Mark the block containing the payload as canonical
if _, err = c.engineAPI.ForkchoiceUpdatedV2(c.curForkchoiceState, nil); err != nil { if _, err = c.engineAPI.ForkchoiceUpdatedV3(c.curForkchoiceState, nil); err != nil {
return err return err
} }
c.lastBlockTime = payload.Timestamp c.lastBlockTime = payload.Timestamp

View file

@ -68,7 +68,7 @@ func newTesterWithNotification(t *testing.T, success func()) *downloadTester {
Alloc: types.GenesisAlloc{testAddress: {Balance: big.NewInt(1000000000000000)}}, Alloc: types.GenesisAlloc{testAddress: {Balance: big.NewInt(1000000000000000)}},
BaseFee: big.NewInt(params.InitialBaseFee), BaseFee: big.NewInt(params.InitialBaseFee),
} }
chain, err := core.NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) chain, err := core.NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil)
if err != nil { if err != nil {
panic(err) panic(err)
} }
@ -230,6 +230,7 @@ func (dlp *downloadTesterPeer) RequestBodies(hashes []common.Hash, sink chan *et
txsHashes = make([]common.Hash, len(bodies)) txsHashes = make([]common.Hash, len(bodies))
uncleHashes = make([]common.Hash, len(bodies)) uncleHashes = make([]common.Hash, len(bodies))
withdrawalHashes = make([]common.Hash, len(bodies)) withdrawalHashes = make([]common.Hash, len(bodies))
requestsHashes = make([]common.Hash, len(bodies))
) )
hasher := trie.NewStackTrie(nil) hasher := trie.NewStackTrie(nil)
for i, body := range bodies { for i, body := range bodies {
@ -248,7 +249,7 @@ func (dlp *downloadTesterPeer) RequestBodies(hashes []common.Hash, sink chan *et
res := &eth.Response{ res := &eth.Response{
Req: req, Req: req,
Res: (*eth.BlockBodiesResponse)(&bodies), Res: (*eth.BlockBodiesResponse)(&bodies),
Meta: [][]common.Hash{txsHashes, uncleHashes, withdrawalHashes}, Meta: [][]common.Hash{txsHashes, uncleHashes, withdrawalHashes, requestsHashes},
Time: 1, Time: 1,
Done: make(chan error, 1), // Ignore the returned status Done: make(chan error, 1), // Ignore the returned status
} }

View file

@ -88,10 +88,10 @@ func (q *bodyQueue) request(peer *peerConnection, req *fetchRequest, resCh chan
// deliver is responsible for taking a generic response packet from the concurrent // deliver is responsible for taking a generic response packet from the concurrent
// fetcher, unpacking the body data and delivering it to the downloader's queue. // fetcher, unpacking the body data and delivering it to the downloader's queue.
func (q *bodyQueue) deliver(peer *peerConnection, packet *eth.Response) (int, error) { func (q *bodyQueue) deliver(peer *peerConnection, packet *eth.Response) (int, error) {
txs, uncles, withdrawals := packet.Res.(*eth.BlockBodiesResponse).Unpack() txs, uncles, withdrawals, requests := packet.Res.(*eth.BlockBodiesResponse).Unpack()
hashsets := packet.Meta.([][]common.Hash) // {txs hashes, uncle hashes, withdrawal hashes} hashsets := packet.Meta.([][]common.Hash) // {txs hashes, uncle hashes, withdrawal hashes, requests hashes}
accepted, err := q.queue.DeliverBodies(peer.id, txs, hashsets[0], uncles, hashsets[1], withdrawals, hashsets[2]) accepted, err := q.queue.DeliverBodies(peer.id, txs, hashsets[0], uncles, hashsets[1], withdrawals, hashsets[2], requests, hashsets[3])
switch { switch {
case err == nil && len(txs) == 0: case err == nil && len(txs) == 0:
peer.log.Trace("Requested bodies delivered") peer.log.Trace("Requested bodies delivered")

View file

@ -784,7 +784,8 @@ func (q *queue) DeliverHeaders(id string, headers []*types.Header, hashes []comm
// also wakes any threads waiting for data delivery. // also wakes any threads waiting for data delivery.
func (q *queue) DeliverBodies(id string, txLists [][]*types.Transaction, txListHashes []common.Hash, func (q *queue) DeliverBodies(id string, txLists [][]*types.Transaction, txListHashes []common.Hash,
uncleLists [][]*types.Header, uncleListHashes []common.Hash, uncleLists [][]*types.Header, uncleListHashes []common.Hash,
withdrawalLists [][]*types.Withdrawal, withdrawalListHashes []common.Hash) (int, error) { withdrawalLists [][]*types.Withdrawal, withdrawalListHashes []common.Hash,
requestsLists [][]*types.Request, requestsListHashes []common.Hash) (int, error) {
q.lock.Lock() q.lock.Lock()
defer q.lock.Unlock() defer q.lock.Unlock()
@ -808,6 +809,19 @@ func (q *queue) DeliverBodies(id string, txLists [][]*types.Transaction, txListH
return errInvalidBody return errInvalidBody
} }
} }
if header.RequestsHash == nil {
// nil hash means that requests should not be present in body
if requestsLists[index] != nil {
return errInvalidBody
}
} else { // non-nil hash: body must have requests
if requestsLists[index] == nil {
return errInvalidBody
}
if requestsListHashes[index] != *header.RequestsHash {
return errInvalidBody
}
}
// Blocks must have a number of blobs corresponding to the header gas usage, // Blocks must have a number of blobs corresponding to the header gas usage,
// and zero before the Cancun hardfork. // and zero before the Cancun hardfork.
var blobs int var blobs int

View file

@ -341,7 +341,7 @@ func XTestDelivery(t *testing.T) {
uncleHashes[i] = types.CalcUncleHash(uncles) uncleHashes[i] = types.CalcUncleHash(uncles)
} }
time.Sleep(100 * time.Millisecond) time.Sleep(100 * time.Millisecond)
_, err := q.DeliverBodies(peer.id, txset, txsHashes, uncleset, uncleHashes, nil, nil) _, err := q.DeliverBodies(peer.id, txset, txsHashes, uncleset, uncleHashes, nil, nil, nil, nil)
if err != nil { if err != nil {
fmt.Printf("delivered %d bodies %v\n", len(txset), err) fmt.Printf("delivered %d bodies %v\n", len(txset), err)
} }

View file

@ -217,7 +217,7 @@ func newTestBlockchain(blocks []*types.Block) *core.BlockChain {
if pregenerated { if pregenerated {
panic("Requested chain generation outside of init") panic("Requested chain generation outside of init")
} }
chain, err := core.NewBlockChain(rawdb.NewMemoryDatabase(), nil, testGspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) chain, err := core.NewBlockChain(rawdb.NewMemoryDatabase(), nil, testGspec, nil, ethash.NewFaker(), vm.Config{}, nil)
if err != nil { if err != nil {
panic(err) panic(err)
} }

View file

@ -250,7 +250,7 @@ func TestFilters(t *testing.T) {
} }
}) })
var l uint64 var l uint64
bc, err := core.NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, &l) bc, err := core.NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, &l)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }

View file

@ -210,7 +210,7 @@ func newTestBackend(t *testing.T, londonBlock *big.Int, cancunBlock *big.Int, pe
}) })
// Construct testing chain // Construct testing chain
gspec.Config.TerminalTotalDifficulty = new(big.Int).SetUint64(td) gspec.Config.TerminalTotalDifficulty = new(big.Int).SetUint64(td)
chain, err := core.NewBlockChain(db, &core.CacheConfig{TrieCleanNoPrefetch: true}, gspec, nil, engine, vm.Config{}, nil, nil) chain, err := core.NewBlockChain(db, &core.CacheConfig{TrieCleanNoPrefetch: true}, gspec, nil, engine, vm.Config{}, nil)
if err != nil { if err != nil {
t.Fatalf("Failed to create local chain, %v", err) t.Fatalf("Failed to create local chain, %v", err)
} }

View file

@ -98,8 +98,8 @@ func testForkIDSplit(t *testing.T, protocol uint) {
gspecNoFork = &core.Genesis{Config: configNoFork} gspecNoFork = &core.Genesis{Config: configNoFork}
gspecProFork = &core.Genesis{Config: configProFork} gspecProFork = &core.Genesis{Config: configProFork}
chainNoFork, _ = core.NewBlockChain(dbNoFork, nil, gspecNoFork, nil, engine, vm.Config{}, nil, nil) chainNoFork, _ = core.NewBlockChain(dbNoFork, nil, gspecNoFork, nil, engine, vm.Config{}, nil)
chainProFork, _ = core.NewBlockChain(dbProFork, nil, gspecProFork, nil, engine, vm.Config{}, nil, nil) chainProFork, _ = core.NewBlockChain(dbProFork, nil, gspecProFork, nil, engine, vm.Config{}, nil)
_, blocksNoFork, _ = core.GenerateChainWithGenesis(gspecNoFork, engine, 2, nil) _, blocksNoFork, _ = core.GenerateChainWithGenesis(gspecNoFork, engine, 2, nil)
_, blocksProFork, _ = core.GenerateChainWithGenesis(gspecProFork, engine, 2, nil) _, blocksProFork, _ = core.GenerateChainWithGenesis(gspecProFork, engine, 2, nil)

View file

@ -151,7 +151,7 @@ func newTestHandlerWithBlocks(blocks int) *testHandler {
Config: params.TestChainConfig, Config: params.TestChainConfig,
Alloc: types.GenesisAlloc{testAddr: {Balance: big.NewInt(1000000)}}, Alloc: types.GenesisAlloc{testAddr: {Balance: big.NewInt(1000000)}},
} }
chain, _ := core.NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) chain, _ := core.NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil)
_, bs, _ := core.GenerateChainWithGenesis(gspec, ethash.NewFaker(), blocks, nil) _, bs, _ := core.GenerateChainWithGenesis(gspec, ethash.NewFaker(), blocks, nil)
if _, err := chain.InsertChain(bs); err != nil { if _, err := chain.InsertChain(bs); err != nil {

View file

@ -104,7 +104,7 @@ func newTestBackendWithGenerator(blocks int, shanghai bool, generator func(int,
Config: config, Config: config,
Alloc: types.GenesisAlloc{testAddr: {Balance: big.NewInt(100_000_000_000_000_000)}}, Alloc: types.GenesisAlloc{testAddr: {Balance: big.NewInt(100_000_000_000_000_000)}},
} }
chain, _ := core.NewBlockChain(db, nil, gspec, nil, engine, vm.Config{}, nil, nil) chain, _ := core.NewBlockChain(db, nil, gspec, nil, engine, vm.Config{}, nil)
_, bs, _ := core.GenerateChainWithGenesis(gspec, engine, blocks, generator) _, bs, _ := core.GenerateChainWithGenesis(gspec, engine, blocks, generator)
if _, err := chain.InsertChain(bs); err != nil { if _, err := chain.InsertChain(bs); err != nil {

View file

@ -316,6 +316,7 @@ func handleBlockBodies(backend Backend, msg Decoder, peer *Peer) error {
txsHashes = make([]common.Hash, len(res.BlockBodiesResponse)) txsHashes = make([]common.Hash, len(res.BlockBodiesResponse))
uncleHashes = make([]common.Hash, len(res.BlockBodiesResponse)) uncleHashes = make([]common.Hash, len(res.BlockBodiesResponse))
withdrawalHashes = make([]common.Hash, len(res.BlockBodiesResponse)) withdrawalHashes = make([]common.Hash, len(res.BlockBodiesResponse))
requestsHashes = make([]common.Hash, len(res.BlockBodiesResponse))
) )
hasher := trie.NewStackTrie(nil) hasher := trie.NewStackTrie(nil)
for i, body := range res.BlockBodiesResponse { for i, body := range res.BlockBodiesResponse {
@ -324,8 +325,11 @@ func handleBlockBodies(backend Backend, msg Decoder, peer *Peer) error {
if body.Withdrawals != nil { if body.Withdrawals != nil {
withdrawalHashes[i] = types.DeriveSha(types.Withdrawals(body.Withdrawals), hasher) withdrawalHashes[i] = types.DeriveSha(types.Withdrawals(body.Withdrawals), hasher)
} }
if body.Requests != nil {
requestsHashes[i] = types.DeriveSha(types.Requests(body.Requests), hasher)
} }
return [][]common.Hash{txsHashes, uncleHashes, withdrawalHashes} }
return [][]common.Hash{txsHashes, uncleHashes, withdrawalHashes, requestsHashes}
} }
return peer.dispatchResponse(&Response{ return peer.dispatchResponse(&Response{
id: res.RequestId, id: res.RequestId,

View file

@ -224,21 +224,22 @@ type BlockBody struct {
Transactions []*types.Transaction // Transactions contained within a block Transactions []*types.Transaction // Transactions contained within a block
Uncles []*types.Header // Uncles contained within a block Uncles []*types.Header // Uncles contained within a block
Withdrawals []*types.Withdrawal `rlp:"optional"` // Withdrawals contained within a block Withdrawals []*types.Withdrawal `rlp:"optional"` // Withdrawals contained within a block
Requests []*types.Request `rlp:"optional"` // Requests contained within a block
} }
// Unpack retrieves the transactions and uncles from the range packet and returns // Unpack retrieves the transactions and uncles from the range packet and returns
// them in a split flat format that's more consistent with the internal data structures. // them in a split flat format that's more consistent with the internal data structures.
func (p *BlockBodiesResponse) Unpack() ([][]*types.Transaction, [][]*types.Header, [][]*types.Withdrawal) { func (p *BlockBodiesResponse) Unpack() ([][]*types.Transaction, [][]*types.Header, [][]*types.Withdrawal, [][]*types.Request) {
// TODO(matt): add support for withdrawals to fetchers
var ( var (
txset = make([][]*types.Transaction, len(*p)) txset = make([][]*types.Transaction, len(*p))
uncleset = make([][]*types.Header, len(*p)) uncleset = make([][]*types.Header, len(*p))
withdrawalset = make([][]*types.Withdrawal, len(*p)) withdrawalset = make([][]*types.Withdrawal, len(*p))
requestset = make([][]*types.Request, len(*p))
) )
for i, body := range *p { for i, body := range *p {
txset[i], uncleset[i], withdrawalset[i] = body.Transactions, body.Uncles, body.Withdrawals txset[i], uncleset[i], withdrawalset[i], requestset[i] = body.Transactions, body.Uncles, body.Withdrawals, body.Requests
} }
return txset, uncleset, withdrawalset return txset, uncleset, withdrawalset, requestset
} }
// GetReceiptsRequest represents a block receipts query. // GetReceiptsRequest represents a block receipts query.

View file

@ -126,7 +126,7 @@ func getChain() *core.BlockChain {
SnapshotWait: true, SnapshotWait: true,
} }
trieRoot = blocks[len(blocks)-1].Root() trieRoot = blocks[len(blocks)-1].Root()
bc, _ := core.NewBlockChain(rawdb.NewMemoryDatabase(), cacheConf, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) bc, _ := core.NewBlockChain(rawdb.NewMemoryDatabase(), cacheConf, gspec, nil, ethash.NewFaker(), vm.Config{}, nil)
if _, err := bc.InsertChain(blocks); err != nil { if _, err := bc.InsertChain(blocks); err != nil {
panic(err) panic(err)
} }

View file

@ -146,7 +146,7 @@ func (eth *Ethereum) hashState(ctx context.Context, block *types.Block, reexec u
if current = eth.blockchain.GetBlockByNumber(next); current == nil { if current = eth.blockchain.GetBlockByNumber(next); current == nil {
return nil, nil, fmt.Errorf("block #%d not found", next) return nil, nil, fmt.Errorf("block #%d not found", next)
} }
_, _, _, err := eth.blockchain.Processor().Process(current, statedb, vm.Config{}) _, err := eth.blockchain.Processor().Process(current, statedb, vm.Config{})
if err != nil { if err != nil {
return nil, nil, fmt.Errorf("processing block %d failed: %v", current.NumberU64(), err) return nil, nil, fmt.Errorf("processing block %d failed: %v", current.NumberU64(), err)
} }

View file

@ -81,7 +81,7 @@ func newTestBackend(t *testing.T, n int, gspec *core.Genesis, generator func(i i
SnapshotLimit: 0, SnapshotLimit: 0,
TrieDirtyDisabled: true, // Archive mode TrieDirtyDisabled: true, // Archive mode
} }
chain, err := core.NewBlockChain(backend.chaindb, cacheConfig, gspec, nil, backend.engine, vm.Config{}, nil, nil) chain, err := core.NewBlockChain(backend.chaindb, cacheConfig, gspec, nil, backend.engine, vm.Config{}, nil)
if err != nil { if err != nil {
t.Fatalf("failed to create tester chain: %v", err) t.Fatalf("failed to create tester chain: %v", err)
} }
@ -1014,7 +1014,7 @@ func newTestMergedBackend(t *testing.T, n int, gspec *core.Genesis, generator fu
SnapshotLimit: 0, SnapshotLimit: 0,
TrieDirtyDisabled: true, // Archive mode TrieDirtyDisabled: true, // Archive mode
} }
chain, err := core.NewBlockChain(backend.chaindb, cacheConfig, gspec, nil, backend.engine, vm.Config{}, nil, nil) chain, err := core.NewBlockChain(backend.chaindb, cacheConfig, gspec, nil, backend.engine, vm.Config{}, nil)
if err != nil { if err != nil {
t.Fatalf("failed to create tester chain: %v", err) t.Fatalf("failed to create tester chain: %v", err)
} }

View file

@ -557,7 +557,7 @@ func testSupplyTracer(t *testing.T, genesis *core.Genesis, gen func(*core.BlockG
return nil, nil, fmt.Errorf("failed to create call tracer: %v", err) return nil, nil, fmt.Errorf("failed to create call tracer: %v", err)
} }
chain, err := core.NewBlockChain(rawdb.NewMemoryDatabase(), core.DefaultCacheConfigWithScheme(rawdb.PathScheme), genesis, nil, engine, vm.Config{Tracer: tracer}, nil, nil) chain, err := core.NewBlockChain(rawdb.NewMemoryDatabase(), core.DefaultCacheConfigWithScheme(rawdb.PathScheme), genesis, nil, engine, vm.Config{Tracer: tracer}, nil)
if err != nil { if err != nil {
return nil, nil, fmt.Errorf("failed to create tester chain: %v", err) return nil, nil, fmt.Errorf("failed to create tester chain: %v", err)
} }

View file

@ -390,7 +390,7 @@ func (t *mdLogger) OnExit(depth int, output []byte, gasUsed uint64, err error, r
// OnOpcode also tracks SLOAD/SSTORE ops to track storage change. // OnOpcode also tracks SLOAD/SSTORE ops to track storage change.
func (t *mdLogger) OnOpcode(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { func (t *mdLogger) OnOpcode(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) {
stack := scope.StackData() stack := scope.StackData()
fmt.Fprintf(t.out, "| %4d | %10v | %3d |", pc, op, cost) fmt.Fprintf(t.out, "| %4d | %10v | %3d |", pc, vm.OpCode(op).String(), cost)
if !t.cfg.DisableStack { if !t.cfg.DisableStack {
// format stack // format stack

View file

@ -123,6 +123,7 @@ type rpcBlock struct {
Transactions []rpcTransaction `json:"transactions"` Transactions []rpcTransaction `json:"transactions"`
UncleHashes []common.Hash `json:"uncles"` UncleHashes []common.Hash `json:"uncles"`
Withdrawals []*types.Withdrawal `json:"withdrawals,omitempty"` Withdrawals []*types.Withdrawal `json:"withdrawals,omitempty"`
Requests []*types.Request `json:"requests,omitempty"`
} }
func (ec *Client) getBlock(ctx context.Context, method string, args ...interface{}) (*types.Block, error) { func (ec *Client) getBlock(ctx context.Context, method string, args ...interface{}) (*types.Block, error) {
@ -196,6 +197,7 @@ func (ec *Client) getBlock(ctx context.Context, method string, args ...interface
Transactions: txs, Transactions: txs,
Uncles: uncles, Uncles: uncles,
Withdrawals: body.Withdrawals, Withdrawals: body.Withdrawals,
Requests: body.Requests,
}), nil }), nil
} }

View file

@ -1,5 +0,0 @@
{
"opRetro": {
"projectId": "0x79c2ae8858a5a3bd7f2e0da9509d727833ffa01f358b5969355f38ff32b20122"
}
}

View file

@ -1388,6 +1388,9 @@ func RPCMarshalHeader(head *types.Header) map[string]interface{} {
if head.ParentBeaconRoot != nil { if head.ParentBeaconRoot != nil {
result["parentBeaconBlockRoot"] = head.ParentBeaconRoot result["parentBeaconBlockRoot"] = head.ParentBeaconRoot
} }
if head.RequestsHash != nil {
result["requestsRoot"] = head.RequestsHash
}
return result return result
} }
@ -1423,6 +1426,9 @@ func RPCMarshalBlock(block *types.Block, inclTx bool, fullTx bool, config *param
if block.Header().WithdrawalsHash != nil { if block.Header().WithdrawalsHash != nil {
fields["withdrawals"] = block.Withdrawals() fields["withdrawals"] = block.Withdrawals()
} }
if block.Header().RequestsHash != nil {
fields["requests"] = block.Requests()
}
return fields return fields
} }

View file

@ -451,7 +451,7 @@ func newTestBackend(t *testing.T, n int, gspec *core.Genesis, engine consensus.E
// Generate blocks for testing // Generate blocks for testing
db, blocks, _ := core.GenerateChainWithGenesis(gspec, engine, n, generator) db, blocks, _ := core.GenerateChainWithGenesis(gspec, engine, n, generator)
txlookupLimit := uint64(0) txlookupLimit := uint64(0)
chain, err := core.NewBlockChain(db, cacheConfig, gspec, nil, engine, vm.Config{}, nil, &txlookupLimit) chain, err := core.NewBlockChain(db, cacheConfig, gspec, nil, engine, vm.Config{}, &txlookupLimit)
if err != nil { if err != nil {
t.Fatalf("failed to create tester chain: %v", err) t.Fatalf("failed to create tester chain: %v", err)
} }

View file

@ -152,7 +152,7 @@ func createMiner(t *testing.T) *Miner {
// Create consensus engine // Create consensus engine
engine := clique.New(chainConfig.Clique, chainDB) engine := clique.New(chainConfig.Clique, chainDB)
// Create Ethereum backend // Create Ethereum backend
bc, err := core.NewBlockChain(chainDB, nil, genesis, nil, engine, vm.Config{}, nil, nil) bc, err := core.NewBlockChain(chainDB, nil, genesis, nil, engine, vm.Config{}, nil)
if err != nil { if err != nil {
t.Fatalf("can't create new chain %v", err) t.Fatalf("can't create new chain %v", err)
} }

View file

@ -121,7 +121,7 @@ func newTestWorkerBackend(t *testing.T, chainConfig *params.ChainConfig, engine
default: default:
t.Fatalf("unexpected consensus engine type: %T", engine) t.Fatalf("unexpected consensus engine type: %T", engine)
} }
chain, err := core.NewBlockChain(db, &core.CacheConfig{TrieDirtyDisabled: true}, gspec, nil, engine, vm.Config{}, nil, nil) chain, err := core.NewBlockChain(db, &core.CacheConfig{TrieDirtyDisabled: true}, gspec, nil, engine, vm.Config{}, nil)
if err != nil { if err != nil {
t.Fatalf("core.NewBlockChain failed: %v", err) t.Fatalf("core.NewBlockChain failed: %v", err)
} }

View file

@ -105,7 +105,20 @@ func (miner *Miner) generateWork(params *generateParams) *newPayloadResult {
log.Warn("Block building is interrupted", "allowance", common.PrettyDuration(miner.config.Recommit)) log.Warn("Block building is interrupted", "allowance", common.PrettyDuration(miner.config.Recommit))
} }
} }
body := types.Body{Transactions: work.txs, Withdrawals: params.withdrawals} body := types.Body{Transactions: work.txs, Withdrawals: params.withdrawals}
allLogs := make([]*types.Log, 0)
for _, r := range work.receipts {
allLogs = append(allLogs, r.Logs...)
}
// Read requests if Prague is enabled.
if miner.chainConfig.IsPrague(work.header.Number, work.header.Time) {
requests, err := core.ParseDepositLogs(allLogs, miner.chainConfig)
if err != nil {
return &newPayloadResult{err: err}
}
body.Requests = requests
}
block, err := miner.engine.FinalizeAndAssemble(miner.chain, work.header, work.state, &body, work.receipts) block, err := miner.engine.FinalizeAndAssemble(miner.chain, work.header, work.state, &body, work.receipts)
if err != nil { if err != nil {
return &newPayloadResult{err: err} return &newPayloadResult{err: err}

View file

@ -383,7 +383,7 @@ func TestJWT(t *testing.T) {
expFail := []func() string{ expFail := []func() string{
// future // future
func() string { func() string {
return fmt.Sprintf("Bearer %v", issueToken(secret, nil, testClaim{"iat": time.Now().Unix() + int64(jwtExpiryTimeout.Seconds()) + 1})) return fmt.Sprintf("Bearer %v", issueToken(secret, nil, testClaim{"iat": time.Now().Unix() + int64(jwtExpiryTimeout.Seconds()) + 60}))
}, },
// stale // stale
func() string { func() string {

View file

@ -58,6 +58,7 @@ var (
TerminalTotalDifficultyPassed: true, TerminalTotalDifficultyPassed: true,
ShanghaiTime: newUint64(1681338455), ShanghaiTime: newUint64(1681338455),
CancunTime: newUint64(1710338135), CancunTime: newUint64(1710338135),
DepositContractAddress: common.HexToAddress("0x00000000219ab540356cbb839cbe05303d7705fa"),
Ethash: new(EthashConfig), Ethash: new(EthashConfig),
} }
// HoleskyChainConfig contains the chain parameters to run a node on the Holesky test network. // HoleskyChainConfig contains the chain parameters to run a node on the Holesky test network.
@ -337,6 +338,8 @@ type ChainConfig struct {
// TODO(karalabe): Drop this field eventually (always assuming PoS mode) // TODO(karalabe): Drop this field eventually (always assuming PoS mode)
TerminalTotalDifficultyPassed bool `json:"terminalTotalDifficultyPassed,omitempty"` TerminalTotalDifficultyPassed bool `json:"terminalTotalDifficultyPassed,omitempty"`
DepositContractAddress common.Address `json:"depositContractAddress,omitempty"`
// Various consensus engines // Various consensus engines
Ethash *EthashConfig `json:"ethash,omitempty"` Ethash *EthashConfig `json:"ethash,omitempty"`
Clique *CliqueConfig `json:"clique,omitempty"` Clique *CliqueConfig `json:"clique,omitempty"`

View file

@ -49,6 +49,17 @@ func TestBlockchain(t *testing.T) {
// using 4.6 TGas // using 4.6 TGas
bt.skipLoad(`.*randomStatetest94.json.*`) bt.skipLoad(`.*randomStatetest94.json.*`)
// After the merge we would accept side chains as canonical even if they have lower td
bt.skipLoad(`.*bcMultiChainTest/ChainAtoChainB_difficultyB.json`)
bt.skipLoad(`.*bcMultiChainTest/CallContractFromNotBestBlock.json`)
bt.skipLoad(`.*bcTotalDifficultyTest/uncleBlockAtBlock3afterBlock4.json`)
bt.skipLoad(`.*bcTotalDifficultyTest/lotsOfBranchesOverrideAtTheMiddle.json`)
bt.skipLoad(`.*bcTotalDifficultyTest/sideChainWithMoreTransactions.json`)
bt.skipLoad(`.*bcForkStressTest/ForkStressTest.json`)
bt.skipLoad(`.*bcMultiChainTest/lotsOfLeafs.json`)
bt.skipLoad(`.*bcFrontierToHomestead/blockChainFrontierWithLargerTDvsHomesteadBlockchain.json`)
bt.skipLoad(`.*bcFrontierToHomestead/blockChainFrontierWithLargerTDvsHomesteadBlockchain2.json`)
bt.walk(t, blockTestDir, func(t *testing.T, name string, test *BlockTest) { bt.walk(t, blockTestDir, func(t *testing.T, name string, test *BlockTest) {
execBlockTest(t, bt, test) execBlockTest(t, bt, test)
}) })

View file

@ -153,7 +153,7 @@ func (t *BlockTest) Run(snapshotter bool, scheme string, witness bool, tracer *t
chain, err := core.NewBlockChain(db, cache, gspec, nil, engine, vm.Config{ chain, err := core.NewBlockChain(db, cache, gspec, nil, engine, vm.Config{
Tracer: tracer, Tracer: tracer,
EnableWitnessCollection: witness, EnableWitnessCollection: witness,
}, nil, nil) }, nil)
if err != nil { if err != nil {
return err return err
} }

View file

@ -373,6 +373,7 @@ var Forks = map[string]*params.ChainConfig{
ShanghaiTime: u64(0), ShanghaiTime: u64(0),
CancunTime: u64(0), CancunTime: u64(0),
PragueTime: u64(0), PragueTime: u64(0),
DepositContractAddress: params.MainnetChainConfig.DepositContractAddress,
}, },
"CancunToPragueAtTime15k": { "CancunToPragueAtTime15k": {
ChainID: big.NewInt(1), ChainID: big.NewInt(1),
@ -393,6 +394,7 @@ var Forks = map[string]*params.ChainConfig{
ShanghaiTime: u64(0), ShanghaiTime: u64(0),
CancunTime: u64(0), CancunTime: u64(0),
PragueTime: u64(15_000), PragueTime: u64(15_000),
DepositContractAddress: params.MainnetChainConfig.DepositContractAddress,
}, },
} }