diff --git a/consensus/beacon/consensus.go b/consensus/beacon/consensus.go index c716ba4dcc..1db9d81a1d 100644 --- a/consensus/beacon/consensus.go +++ b/consensus/beacon/consensus.go @@ -462,6 +462,10 @@ func (beacon *Beacon) InnerEngine() consensus.Engine { return beacon.ethone } +func (beacon *Beacon) SwapInner(inner consensus.Engine) { + beacon.ethone = inner +} + // SetThreads updates the mining threads. Delegate the call // to the eth1 engine if it's threaded. func (beacon *Beacon) SetThreads(threads int) { @@ -478,13 +482,9 @@ func (beacon *Beacon) SetThreads(threads int) { // If the parentHash is not stored in the database a UnknownAncestor error is returned. func IsTTDReached(chain consensus.ChainHeaderReader, parentHash common.Hash, parentNumber uint64) (bool, error) { if cfg := chain.Config(); cfg.Optimism != nil { - num := parentNumber - if num == ^(uint64(0)) { // caller can (intentionally?!) underflow on parent-of-block 0 case. - num = 0 - } - if cfg.IsBedrock(new(big.Int).SetUint64(num)) { - return true, nil - } + // If OP-Stack then bedrock activation number determines when TTD (eth Merge) has been reached. + // Note: some tests/utils will set parentNumber == max_uint64 as "parent" of the genesis block, this is fine. + return cfg.IsBedrock(new(big.Int).SetUint64(parentNumber + 1)), nil } if chain.Config().TerminalTotalDifficulty == nil { return false, nil diff --git a/consensus/beacon/oplegacy.go b/consensus/beacon/oplegacy.go index 3c30cd24dc..90d7e8678e 100644 --- a/consensus/beacon/oplegacy.go +++ b/consensus/beacon/oplegacy.go @@ -29,8 +29,8 @@ func (o *OpLegacy) VerifyHeader(chain consensus.ChainHeaderReader, header *types func (o *OpLegacy) VerifyHeaders(chain consensus.ChainHeaderReader, headers []*types.Header) (chan<- struct{}, <-chan error) { quit := make(chan struct{}, 1) result := make(chan error, len(headers)) - for range headers { - result <- nil + for _, h := range headers { + result <- o.VerifyHeader(chain, h) } return quit, result } diff --git a/core/chain_makers.go b/core/chain_makers.go index 90b5b1fcee..22c837e84f 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -319,7 +319,7 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse // to a chain, so the difficulty will be left unset (nil). Set it here to the // correct value. if b.header.Difficulty == nil { - if config.TerminalTotalDifficulty == nil { + if config.TerminalTotalDifficulty == nil && !config.IsOptimismBedrock(b.header.Number) { // Clique chain b.header.Difficulty = big.NewInt(2) } else { diff --git a/core/types/receipt.go b/core/types/receipt.go index b85df05a3a..02410c3132 100644 --- a/core/types/receipt.go +++ b/core/types/receipt.go @@ -569,7 +569,7 @@ func (rs Receipts) DeriveFields(config *params.ChainConfig, hash common.Hash, nu logIndex++ } } - if config.Optimism != nil && len(txs) >= 2 { // need at least an info tx and a non-info tx + if config.Optimism != nil && len(txs) >= 2 && config.IsBedrock(new(big.Int).SetUint64(number)) { // need at least an info tx and a non-info tx l1Basefee, costFunc, feeScalar, err := extractL1GasParams(config, time, txs[0].Data()) if err != nil { return err diff --git a/core/types/receipt_test.go b/core/types/receipt_test.go index f6a3598ca9..5c3789b8e1 100644 --- a/core/types/receipt_test.go +++ b/core/types/receipt_test.go @@ -34,8 +34,16 @@ import ( ) var ( + bedrockGenesisTestConfig = func() *params.ChainConfig { + conf := *params.AllCliqueProtocolChanges // copy the config + conf.Clique = nil + conf.TerminalTotalDifficultyPassed = true + conf.BedrockBlock = big.NewInt(0) + conf.Optimism = ¶ms.OptimismConfig{EIP1559Elasticity: 50, EIP1559Denominator: 10} + return &conf + }() ecotoneTestConfig = func() *params.ChainConfig { - conf := *params.OptimismTestConfig // copy the config + conf := *bedrockGenesisTestConfig // copy the config time := uint64(0) conf.EcotoneTime = &time return &conf @@ -774,7 +782,7 @@ func TestDeriveOptimismBedrockTxReceipts(t *testing.T) { // Re-derive receipts. basefee := big.NewInt(1000) derivedReceipts := clearComputedFieldsOnReceipts(receipts) - err := Receipts(derivedReceipts).DeriveFields(params.OptimismTestConfig, blockHash, blockNumber.Uint64(), 0, basefee, nil, txs) + err := Receipts(derivedReceipts).DeriveFields(bedrockGenesisTestConfig, blockHash, blockNumber.Uint64(), 0, basefee, nil, txs) if err != nil { t.Fatalf("DeriveFields(...) = %v, want ", err) } @@ -802,7 +810,7 @@ func TestDeriveOptimismEcotoneTxReceipts(t *testing.T) { basefee := big.NewInt(1000) derivedReceipts := clearComputedFieldsOnReceipts(receipts) // Should error out if we try to process this with a pre-Ecotone config - err := Receipts(derivedReceipts).DeriveFields(params.OptimismTestConfig, blockHash, blockNumber.Uint64(), 0, basefee, nil, txs) + err := Receipts(derivedReceipts).DeriveFields(bedrockGenesisTestConfig, blockHash, blockNumber.Uint64(), 0, basefee, nil, txs) if err == nil { t.Fatalf("expected error from deriving ecotone receipts with pre-ecotone config, got none") } diff --git a/ethclient/ethclient_test.go b/ethclient/ethclient_test.go index c2b8748110..2b6f19f447 100644 --- a/ethclient/ethclient_test.go +++ b/ethclient/ethclient_test.go @@ -29,6 +29,8 @@ import ( "time" "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/consensus" + "github.com/ethereum/go-ethereum/consensus/beacon" "github.com/ethereum/go-ethereum/internal/ethapi" "github.com/ethereum/go-ethereum" @@ -286,8 +288,21 @@ func newMockHistoricalBackend(t *testing.T) string { func newTestBackend(t *testing.T, enableHistoricalState bool) (*node.Node, []*types.Block) { histAddr := newMockHistoricalBackend(t) - // Generate test chain. - blocks := generateTestChain(enableHistoricalState) + var consensusEngine consensus.Engine + var actualGenesis *core.Genesis + var chainLength int + if enableHistoricalState { + actualGenesis = genesisForHistorical + consensusEngine = beacon.New(ethash.NewFaker()) + chainLength = 10 + } else { + actualGenesis = genesis + consensusEngine = ethash.NewFaker() + chainLength = 2 + } + + // Generate test chain + blocks := generateTestChain(consensusEngine, actualGenesis, chainLength) // Create node n, err := node.New(&node.Config{}) @@ -295,12 +310,6 @@ func newTestBackend(t *testing.T, enableHistoricalState bool) (*node.Node, []*ty t.Fatalf("can't create new node: %v", err) } // Create Ethereum Service - var actualGenesis *core.Genesis - if enableHistoricalState { - actualGenesis = genesisForHistorical - } else { - actualGenesis = genesis - } config := ðconfig.Config{Genesis: actualGenesis} if enableHistoricalState { config.RollupHistoricalRPC = histAddr @@ -310,6 +319,9 @@ func newTestBackend(t *testing.T, enableHistoricalState bool) (*node.Node, []*ty if err != nil { t.Fatalf("can't create new ethereum service: %v", err) } + if enableHistoricalState { // swap to the pre-bedrock consensus-engine that we used to generate the historical blocks + ethservice.BlockChain().Engine().(*beacon.Beacon).SwapInner(ethash.NewFaker()) + } // Import the test chain. if err := n.Start(); err != nil { t.Fatalf("can't start test node: %v", err) @@ -317,30 +329,29 @@ func newTestBackend(t *testing.T, enableHistoricalState bool) (*node.Node, []*ty if _, err := ethservice.BlockChain().InsertChain(blocks[1:]); err != nil { t.Fatalf("can't import test blocks: %v", err) } + if enableHistoricalState { + // Now that we have a filled DB, swap the pre-Bedrock consensus to OpLegacy, + // which does not support re-processing of pre-bedrock data. + ethservice.Engine().(*beacon.Beacon).SwapInner(&beacon.OpLegacy{}) + } return n, blocks } -func generateTestChain(enableHistoricalState bool) []*types.Block { +func generateTestChain(consensusEngine consensus.Engine, genesis *core.Genesis, length int) []*types.Block { generate := func(i int, g *core.BlockGen) { g.OffsetTime(5) g.SetExtra([]byte("test")) if i == 1 { // Test transactions are included in block #2. - if enableHistoricalState { + if genesis.Config.Optimism != nil && genesis.Config.IsBedrock(big.NewInt(1)) { g.AddTx(depositTx) } g.AddTx(testTx1) g.AddTx(testTx2) } } - var actualGenesis *core.Genesis - if enableHistoricalState { - actualGenesis = genesisForHistorical - } else { - actualGenesis = genesis - } - _, blocks, _ := core.GenerateChainWithGenesis(actualGenesis, ethash.NewFaker(), 2, generate) - return append([]*types.Block{actualGenesis.ToBlock()}, blocks...) + _, blocks, _ := core.GenerateChainWithGenesis(genesis, consensusEngine, length, generate) + return append([]*types.Block{genesis.ToBlock()}, blocks...) } func TestEthClientHistoricalBackend(t *testing.T) {