From b695a61f85a4c540baff89994e98d94bfdfa2cf6 Mon Sep 17 00:00:00 2001 From: Ian Norden Date: Thu, 12 Dec 2019 22:36:53 -0600 Subject: [PATCH] block_validator_test and fixes --- core/block_validator.go | 23 +- core/block_validator_test.go | 504 +++++++++++++++++++++++++++++++++-- core/chain_makers_test.go | 18 +- 3 files changed, 500 insertions(+), 45 deletions(-) diff --git a/core/block_validator.go b/core/block_validator.go index 177e3285e..af8a77c92 100644 --- a/core/block_validator.go +++ b/core/block_validator.go @@ -21,7 +21,6 @@ import ( "math/big" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" @@ -152,10 +151,6 @@ func CalcGasLimitAndBaseFee(config *params.ChainConfig, parent *types.Block, gas // Start at 50 : 50 and then shift to 0 : 100 // The GasLimit for the legacy pool is (params.MaxGasEIP1559 - EIP1559GasLimit) func calcGasLimitAndBaseFee(config *params.ChainConfig, parent *types.Block) (uint64, *big.Int) { - // Panic if we do not have a block number set for EIP1559 activation - if config.EIP1559Block == nil { - panic("chain config is missing EIP1559Block") - } height := new(big.Int).Add(parent.Number(), common.Big1) // If we are at the block of EIP1559 activation then the BaseFee is set to the initial value @@ -164,12 +159,9 @@ func calcGasLimitAndBaseFee(config *params.ChainConfig, parent *types.Block) (ui return params.MaxGasEIP1559 / 2, new(big.Int).SetUint64(params.EIP1559InitialBaseFee) } - /* - Otherwise, calculate the BaseFee - As a default strategy, miners set BASEFEE as follows. Let delta = block.gas_used - TARGET_GASUSED (possibly negative). - Set BASEFEE = PARENT_BASEFEE + PARENT_BASEFEE * delta // TARGET_GASUSED // BASEFEE_MAX_CHANGE_DENOMINATOR, - clamping this result inside of the allowable bounds if needed (with the parameter setting above clamping will not be required). - */ + // Otherwise, calculate the BaseFee + // As a default strategy, miners set BASEFEE as follows. Let delta = block.gas_used - TARGET_GASUSED (possibly negative). + // Set BASEFEE = PARENT_BASEFEE + PARENT_BASEFEE * delta // TARGET_GASUSED // BASEFEE_MAX_CHANGE_DENOMINATOR, delta := new(big.Int).Sub(new(big.Int).SetUint64(parent.GasUsed()), new(big.Int).SetUint64(params.TargetGasUsed)) mul := new(big.Int).Mul(parent.BaseFee(), delta) @@ -177,18 +169,23 @@ func calcGasLimitAndBaseFee(config *params.ChainConfig, parent *types.Block) (ui div2 := new(big.Int).Div(div, new(big.Int).SetUint64(params.BaseFeeMaxChangeDenominator)) baseFee := new(big.Int).Add(parent.BaseFee(), div2) - // Panic if the BaseFee is not valid // A valid BASEFEE is one such that abs(BASEFEE - PARENT_BASEFEE) <= max(1, PARENT_BASEFEE // BASEFEE_MAX_CHANGE_DENOMINATOR) diff := new(big.Int).Sub(baseFee, parent.BaseFee()) + neg := false if diff.Sign() < 0 { + neg = true diff.Neg(diff) } max := new(big.Int).Div(parent.BaseFee(), new(big.Int).SetUint64(params.BaseFeeMaxChangeDenominator)) if max.Cmp(common.Big1) < 0 { max = common.Big1 } + // If derived BaseFee is not valid, restrict it within the bounds if diff.Cmp(max) > 0 { - panic("invalid BaseFee") + if neg { + max.Neg(max) + } + baseFee.Set(new(big.Int).Add(parent.BaseFee(), max)) } // If EIP1559 is finalized, our limit for the EIP1559 pool is the entire max limit diff --git a/core/block_validator_test.go b/core/block_validator_test.go index f83cd76e2..d80543dcf 100644 --- a/core/block_validator_test.go +++ b/core/block_validator_test.go @@ -17,6 +17,7 @@ package core import ( + "math/big" "runtime" "testing" "time" @@ -25,6 +26,7 @@ import ( "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/params" ) @@ -76,6 +78,172 @@ func TestHeaderVerification(t *testing.T) { } } +func TestHeaderVerificationEIP1559(t *testing.T) { + // Create a simple chain to verify + var ( + key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + key2, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a") + key3, _ = crypto.HexToECDSA("49a7b37aa6f6645917e7b807e9d1c00d4fa71f18343b0d4122a4d2df64dd6fee") + addr1 = crypto.PubkeyToAddress(key1.PublicKey) + addr2 = crypto.PubkeyToAddress(key2.PublicKey) + addr3 = crypto.PubkeyToAddress(key3.PublicKey) + testdb = rawdb.NewMemoryDatabase() + gspec = &Genesis{ + Config: params.EIP1559ChainConfig, + Alloc: GenesisAlloc{addr1: {Balance: big.NewInt(1000000)}}, + BaseFee: new(big.Int).SetUint64(params.EIP1559InitialBaseFee)} + genesis = gspec.MustCommit(testdb) + signer = types.HomesteadSigner{} + blocks, _ = GenerateChain(params.EIP1559ChainConfig, genesis, ethash.NewFaker(), testdb, 5, func(i int, gen *BlockGen) { + switch i { + case 0: + // In block 1, addr1 sends addr2 some ether. + tx, _ := types.SignTx(types.NewTransaction(gen.TxNonce(addr1), addr2, big.NewInt(10000), params.TxGas, new(big.Int), nil, nil, nil), signer, key1) + gen.AddTx(tx) + case 1: + // In block 2, addr1 sends some more ether to addr2. + // addr2 attempts to pass it on to addr3 using a EIP1559 transaction + tx1, _ := types.SignTx(types.NewTransaction(gen.TxNonce(addr1), addr2, big.NewInt(1000), params.TxGas, new(big.Int), nil, nil, nil), signer, key1) + tx2, _ := types.SignTx(types.NewTransaction(gen.TxNonce(addr2), addr3, big.NewInt(1000), params.TxGas, nil, nil, new(big.Int), new(big.Int)), signer, key2) + gen.AddTx(tx1) + gen.AddTx(tx2) + case 2: + // Block 3 is empty but was mined by addr3. + gen.SetCoinbase(addr3) + gen.SetExtra([]byte("yeehaw")) + case 3: + // Block 4 includes blocks 2 and 3 as uncle headers (with modified extra data). + b2 := gen.PrevBlock(1).Header() + b2.Extra = []byte("foo") + gen.AddUncle(b2) + b3 := gen.PrevBlock(2).Header() + b3.Extra = []byte("foo") + gen.AddUncle(b3) + } + }) + ) + headers := make([]*types.Header, len(blocks)) + for i, block := range blocks { + headers[i] = block.Header() + } + // Run the header checker for blocks one-by-one, checking for both valid and invalid nonces + chain, _ := NewBlockChain(testdb, nil, params.EIP1559ChainConfig, ethash.NewFaker(), vm.Config{}, nil) + defer chain.Stop() + + for i := 0; i < len(blocks); i++ { + for j, valid := range []bool{true, false} { + var results <-chan error + + if valid { + engine := ethash.NewFaker() + _, results = engine.VerifyHeaders(chain, []*types.Header{headers[i]}, []bool{true}) + } else { + engine := ethash.NewFakeFailer(headers[i].Number.Uint64()) + _, results = engine.VerifyHeaders(chain, []*types.Header{headers[i]}, []bool{true}) + } + // Wait for the verification result + select { + case result := <-results: + if (result == nil) != valid { + t.Errorf("test %d.%d: validity mismatch: have %v, want %v", i, j, result, valid) + } + case <-time.After(time.Second): + t.Fatalf("test %d.%d: verification timeout", i, j) + } + // Make sure no more data is returned + select { + case result := <-results: + t.Fatalf("test %d.%d: unexpected result returned: %v", i, j, result) + case <-time.After(25 * time.Millisecond): + } + } + chain.InsertChain(blocks[i : i+1]) + } +} + +func TestHeaderVerificationEIP1559Finalized(t *testing.T) { + // Create a simple chain to verify + var ( + key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + key2, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a") + key3, _ = crypto.HexToECDSA("49a7b37aa6f6645917e7b807e9d1c00d4fa71f18343b0d4122a4d2df64dd6fee") + addr1 = crypto.PubkeyToAddress(key1.PublicKey) + addr2 = crypto.PubkeyToAddress(key2.PublicKey) + addr3 = crypto.PubkeyToAddress(key3.PublicKey) + testdb = rawdb.NewMemoryDatabase() + gspec = &Genesis{ + Config: params.EIP1559FinalizedChainConfig, + Alloc: GenesisAlloc{addr1: {Balance: new(big.Int).SetUint64((params.EIP1559InitialBaseFee * params.TxGas) + 1000000)}}, + BaseFee: new(big.Int).SetUint64(params.EIP1559InitialBaseFee)} + genesis = gspec.MustCommit(testdb) + signer = types.HomesteadSigner{} + blocks, _ = GenerateChain(params.EIP1559FinalizedChainConfig, genesis, ethash.NewFaker(), testdb, 5, func(i int, gen *BlockGen) { + switch i { + case 0: + // In block 1, addr1 sends addr2 some ether. + tx, _ := types.SignTx(types.NewTransaction(gen.TxNonce(addr1), addr2, big.NewInt(10000), params.TxGas, nil, nil, new(big.Int), new(big.Int).SetUint64(params.EIP1559InitialBaseFee)), signer, key1) + gen.AddTx(tx) + case 1: + // In block 2, addr1 sends some more ether to addr2. + // addr2 attempts to pass it on to addr3 using a EIP1559 transaction + tx1, _ := types.SignTx(types.NewTransaction(gen.TxNonce(addr1), addr2, big.NewInt(1000), params.TxGas, nil, nil, new(big.Int), new(big.Int)), signer, key1) + tx2, _ := types.SignTx(types.NewTransaction(gen.TxNonce(addr2), addr3, big.NewInt(1000), params.TxGas, nil, nil, new(big.Int), new(big.Int)), signer, key2) + gen.AddTx(tx1) + gen.AddTx(tx2) + case 2: + // Block 3 is empty but was mined by addr3. + gen.SetCoinbase(addr3) + gen.SetExtra([]byte("yeehaw")) + case 3: + // Block 4 includes blocks 2 and 3 as uncle headers (with modified extra data). + b2 := gen.PrevBlock(1).Header() + b2.Extra = []byte("foo") + gen.AddUncle(b2) + b3 := gen.PrevBlock(2).Header() + b3.Extra = []byte("foo") + gen.AddUncle(b3) + } + }) + ) + headers := make([]*types.Header, len(blocks)) + for i, block := range blocks { + headers[i] = block.Header() + } + // Run the header checker for blocks one-by-one, checking for both valid and invalid nonces + chain, _ := NewBlockChain(testdb, nil, params.EIP1559FinalizedChainConfig, ethash.NewFaker(), vm.Config{}, nil) + defer chain.Stop() + + for i := 0; i < len(blocks); i++ { + for j, valid := range []bool{true, false} { + var results <-chan error + + if valid { + engine := ethash.NewFaker() + _, results = engine.VerifyHeaders(chain, []*types.Header{headers[i]}, []bool{true}) + } else { + engine := ethash.NewFakeFailer(headers[i].Number.Uint64()) + _, results = engine.VerifyHeaders(chain, []*types.Header{headers[i]}, []bool{true}) + } + // Wait for the verification result + select { + case result := <-results: + if (result == nil) != valid { + t.Errorf("test %d.%d: validity mismatch: have %v, want %v", i, j, result, valid) + } + case <-time.After(time.Second): + t.Fatalf("test %d.%d: verification timeout", i, j) + } + // Make sure no more data is returned + select { + case result := <-results: + t.Fatalf("test %d.%d: unexpected result returned: %v", i, j, result) + case <-time.After(25 * time.Millisecond): + } + } + chain.InsertChain(blocks[i : i+1]) + } +} + // Tests that concurrent header verification works, for both good and bad blocks. func TestHeaderConcurrentVerification2(t *testing.T) { testHeaderConcurrentVerification(t, 2) } func TestHeaderConcurrentVerification8(t *testing.T) { testHeaderConcurrentVerification(t, 8) } @@ -147,6 +315,158 @@ func testHeaderConcurrentVerification(t *testing.T, threads int) { } } +func TestHeaderConcurrentVerificationEIP15592(t *testing.T) { + testHeaderConcurrentVerificationEIP1559(t, 2) +} +func TestHeaderConcurrentVerificationEIP15598(t *testing.T) { + testHeaderConcurrentVerificationEIP1559(t, 8) +} +func TestHeaderConcurrentVerificationEIP155932(t *testing.T) { + testHeaderConcurrentVerificationEIP1559(t, 32) +} + +func testHeaderConcurrentVerificationEIP1559(t *testing.T, threads int) { + // Create a simple chain to verify + var ( + testdb = rawdb.NewMemoryDatabase() + gspec = &Genesis{Config: params.EIP1559ChainConfig, BaseFee: new(big.Int)} + genesis = gspec.MustCommit(testdb) + blocks, _ = GenerateChain(params.EIP1559ChainConfig, genesis, ethash.NewFaker(), testdb, 8, nil) + ) + headers := make([]*types.Header, len(blocks)) + seals := make([]bool, len(blocks)) + + for i, block := range blocks { + headers[i] = block.Header() + seals[i] = true + } + // Set the number of threads to verify on + old := runtime.GOMAXPROCS(threads) + defer runtime.GOMAXPROCS(old) + + // Run the header checker for the entire block chain at once both for a valid and + // also an invalid chain (enough if one arbitrary block is invalid). + for i, valid := range []bool{true, false} { + var results <-chan error + + if valid { + chain, _ := NewBlockChain(testdb, nil, params.EIP1559ChainConfig, ethash.NewFaker(), vm.Config{}, nil) + _, results = chain.engine.VerifyHeaders(chain, headers, seals) + chain.Stop() + } else { + chain, _ := NewBlockChain(testdb, nil, params.EIP1559ChainConfig, ethash.NewFakeFailer(uint64(len(headers)-1)), vm.Config{}, nil) + _, results = chain.engine.VerifyHeaders(chain, headers, seals) + chain.Stop() + } + // Wait for all the verification results + checks := make(map[int]error) + for j := 0; j < len(blocks); j++ { + select { + case result := <-results: + checks[j] = result + + case <-time.After(time.Second): + t.Fatalf("test %d.%d: verification timeout", i, j) + } + } + // Check nonce check validity + for j := 0; j < len(blocks); j++ { + want := valid || (j < len(blocks)-2) // We chose the last-but-one nonce in the chain to fail + if (checks[j] == nil) != want { + t.Errorf("test %d.%d: validity mismatch: have %v, want %v", i, j, checks[j], want) + } + if !want { + // A few blocks after the first error may pass verification due to concurrent + // workers. We don't care about those in this test, just that the correct block + // errors out. + break + } + } + // Make sure no more data is returned + select { + case result := <-results: + t.Fatalf("test %d: unexpected result returned: %v", i, result) + case <-time.After(25 * time.Millisecond): + } + } +} + +func TestHeaderConcurrentVerificationEIP1559Finalized2(t *testing.T) { + testHeaderConcurrentVerificationEIP1559Finalized(t, 2) +} +func TestHeaderConcurrentVerificationEIP1559Finalized8(t *testing.T) { + testHeaderConcurrentVerificationEIP1559Finalized(t, 8) +} +func TestHeaderConcurrentVerificationEIP1559Finalized32(t *testing.T) { + testHeaderConcurrentVerificationEIP1559Finalized(t, 32) +} + +func testHeaderConcurrentVerificationEIP1559Finalized(t *testing.T, threads int) { + // Create a simple chain to verify + var ( + testdb = rawdb.NewMemoryDatabase() + gspec = &Genesis{Config: params.EIP1559FinalizedChainConfig, BaseFee: new(big.Int)} + genesis = gspec.MustCommit(testdb) + blocks, _ = GenerateChain(params.EIP1559FinalizedChainConfig, genesis, ethash.NewFaker(), testdb, 8, nil) + ) + headers := make([]*types.Header, len(blocks)) + seals := make([]bool, len(blocks)) + + for i, block := range blocks { + headers[i] = block.Header() + seals[i] = true + } + // Set the number of threads to verify on + old := runtime.GOMAXPROCS(threads) + defer runtime.GOMAXPROCS(old) + + // Run the header checker for the entire block chain at once both for a valid and + // also an invalid chain (enough if one arbitrary block is invalid). + for i, valid := range []bool{true, false} { + var results <-chan error + + if valid { + chain, _ := NewBlockChain(testdb, nil, params.EIP1559FinalizedChainConfig, ethash.NewFaker(), vm.Config{}, nil) + _, results = chain.engine.VerifyHeaders(chain, headers, seals) + chain.Stop() + } else { + chain, _ := NewBlockChain(testdb, nil, params.EIP1559FinalizedChainConfig, ethash.NewFakeFailer(uint64(len(headers)-1)), vm.Config{}, nil) + _, results = chain.engine.VerifyHeaders(chain, headers, seals) + chain.Stop() + } + // Wait for all the verification results + checks := make(map[int]error) + for j := 0; j < len(blocks); j++ { + select { + case result := <-results: + checks[j] = result + + case <-time.After(time.Second): + t.Fatalf("test %d.%d: verification timeout", i, j) + } + } + // Check nonce check validity + for j := 0; j < len(blocks); j++ { + want := valid || (j < len(blocks)-2) // We chose the last-but-one nonce in the chain to fail + if (checks[j] == nil) != want { + t.Errorf("test %d.%d: validity mismatch: have %v, want %v", i, j, checks[j], want) + } + if !want { + // A few blocks after the first error may pass verification due to concurrent + // workers. We don't care about those in this test, just that the correct block + // errors out. + break + } + } + // Make sure no more data is returned + select { + case result := <-results: + t.Fatalf("test %d: unexpected result returned: %v", i, result) + case <-time.After(25 * time.Millisecond): + } + } +} + // Tests that aborting a header validation indeed prevents further checks from being // run, as well as checks that no left-over goroutines are leaked. func TestHeaderConcurrentAbortion2(t *testing.T) { testHeaderConcurrentAbortion(t, 2) } @@ -198,27 +518,165 @@ func testHeaderConcurrentAbortion(t *testing.T, threads int) { } } -/* - We need to test: - - 1. That the correct, original, gasLimit is returned in the period before activation and no BaseFee is returned - 2. That both the correct EIP1559 gasLimit and BaseFee are calculated and returned in the period between activation and finalization - 3. That the entire `MaxGasEIP1559` is returned as the EIP1559 gasLimit after finalization and the correct BaseFee is calculated - -*/ - -// TestEIP1559Verification tests that verificaiton works after EIP1559 initialization and finalization -func TestEIP1559Verification(t *testing.T) { - //testEIP1559Verification(t) - //testEIP1559VerificationAfterFinalization(t) -} - -// testEIP1559Verification tests verification during the EIP1559 transition phase -func testEIP1559Verification(t *testing.T) { - panic("implement me") -} - -// testEIP1559VerificationAfterFinalization tests verification after EIP1559 finalization -func testEIP1559VerificationAfterFinalization(t *testing.T) { - panic("implement me") +// TestCalcGasLimitAndBaseFee tests that CalcGasLimitAndBaseFee() returns the correct values +func TestCalcGasLimitAndBaseFee(t *testing.T) { + testConditions := []struct { + // Test inputs + config *params.ChainConfig + eip1559Block *big.Int + eip1559FinalizedBlock *big.Int + parentGasLimit uint64 + parentGasUsed uint64 + parentBaseFee *big.Int + parentBlockNumber *big.Int + // Expected results + gasLimit uint64 + baseFee *big.Int + }{ + { + // Before activation GasLimit is calculated using the legacy function and BaseFee is nil + params.TestChainConfig, + nil, + nil, + 8000000, + 8000000, + nil, + big.NewInt(5), + 8000000, + nil, + }, { + // At the EIP1559 initialization block the GasLimit is split evenly between the two pools and BaseFee is the initial value + params.EIP1559ChainConfig, + new(big.Int).SetUint64(params.EIP1559ForkBlockNumber), + nil, + 8000000, + 8000000, + big.NewInt(1100000000), + new(big.Int).SetUint64(params.EIP1559ForkBlockNumber - 1), + params.MaxGasEIP1559 / 2, + new(big.Int).SetUint64(params.EIP1559InitialBaseFee), + }, + // After initialization the GasLimit and BaseFee are set according to their functions + // Half way between initialization and finalization we should be at a 25 : 75 legacy : eip1559 split + { + params.EIP1559ChainConfig, + new(big.Int).SetUint64(params.EIP1559ForkBlockNumber), + nil, + 8000000, + 8000000, + new(big.Int).SetUint64(params.EIP1559InitialBaseFee), + new(big.Int).SetUint64((params.EIP1559ForkBlockNumber + (params.EIP1559ForkFinalizedBlockNumber-params.EIP1559ForkBlockNumber)/2) - 1), + (params.MaxGasEIP1559 * 3) / 4, + new(big.Int).SetUint64(params.EIP1559InitialBaseFee), + }, + { + params.EIP1559ChainConfig, + new(big.Int).SetUint64(params.EIP1559ForkBlockNumber), + nil, + 8000000, + 7000000, + new(big.Int).SetUint64(params.EIP1559InitialBaseFee), + new(big.Int).SetUint64((params.EIP1559ForkBlockNumber + (params.EIP1559ForkFinalizedBlockNumber-params.EIP1559ForkBlockNumber)/2) - 1), + (params.MaxGasEIP1559 * 3) / 4, + new(big.Int).SetUint64(984375000), + }, + { + params.EIP1559ChainConfig, + new(big.Int).SetUint64(params.EIP1559ForkBlockNumber), + nil, + 8000000, + 8000000, + big.NewInt(1100000000), + new(big.Int).SetUint64((params.EIP1559ForkBlockNumber + (params.EIP1559ForkFinalizedBlockNumber-params.EIP1559ForkBlockNumber)/2) - 1), + (params.MaxGasEIP1559 * 3) / 4, + new(big.Int).SetUint64(1100000000), + }, + { + params.EIP1559ChainConfig, + new(big.Int).SetUint64(params.EIP1559ForkBlockNumber), + nil, + 8000000, + 7000000, + big.NewInt(1100000000), + new(big.Int).SetUint64((params.EIP1559ForkBlockNumber + (params.EIP1559ForkFinalizedBlockNumber-params.EIP1559ForkBlockNumber)/2) - 1), + (params.MaxGasEIP1559 * 3) / 4, + new(big.Int).SetUint64(1082812500), + }, + // At and beyond EIP1559 finalization the GasLimit (for the EIP1559 pool) is the entire MaxGasEIP1559 + { + params.EIP1559FinalizedChainConfig, + new(big.Int).SetUint64(params.EIP1559ForkBlockNumber), + new(big.Int).SetUint64(params.EIP1559ForkFinalizedBlockNumber), + 8000000, + 7000000, + big.NewInt(1082812500), + new(big.Int).SetUint64(params.EIP1559ForkFinalizedBlockNumber - 1), + params.MaxGasEIP1559, + new(big.Int).SetUint64(1065893554), + }, + { + params.EIP1559FinalizedChainConfig, + new(big.Int).SetUint64(params.EIP1559ForkBlockNumber), + new(big.Int).SetUint64(params.EIP1559ForkFinalizedBlockNumber), + 8000000, + 7000000, + big.NewInt(1065893554), + new(big.Int).SetUint64(params.EIP1559ForkFinalizedBlockNumber + 1), + params.MaxGasEIP1559, + new(big.Int).SetUint64(1049238967), + }, + { + params.EIP1559FinalizedChainConfig, + new(big.Int).SetUint64(params.EIP1559ForkBlockNumber), + new(big.Int).SetUint64(params.EIP1559ForkFinalizedBlockNumber), + 8000000, + params.TargetGasUsed + 1000, + big.NewInt(1049238967), + new(big.Int).SetUint64(params.EIP1559ForkFinalizedBlockNumber + 10000), + params.MaxGasEIP1559, + new(big.Int).SetUint64(1049255361), + }, + { + params.EIP1559FinalizedChainConfig, + new(big.Int).SetUint64(params.EIP1559ForkBlockNumber), + new(big.Int).SetUint64(params.EIP1559ForkFinalizedBlockNumber), + 8000000, + params.MaxGasEIP1559, + big.NewInt(1049238967), + new(big.Int).SetUint64(params.EIP1559ForkFinalizedBlockNumber + 10000), + params.MaxGasEIP1559, + new(big.Int).SetUint64(1180393837), + }, + { + params.EIP1559FinalizedChainConfig, + new(big.Int).SetUint64(params.EIP1559ForkBlockNumber), + new(big.Int).SetUint64(params.EIP1559ForkFinalizedBlockNumber), + 8000000, + 0, + big.NewInt(1049238967), + new(big.Int).SetUint64(params.EIP1559ForkFinalizedBlockNumber + 10000), + params.MaxGasEIP1559, + new(big.Int).SetUint64(918084097), + }, + } + for i, test := range testConditions { + config := *test.config + config.EIP1559Block = test.eip1559Block + config.EIP1559FinalizedBlock = test.eip1559FinalizedBlock + parentHeader := &types.Header{} + parentHeader.GasLimit = test.parentGasLimit + parentHeader.GasUsed = test.parentGasUsed + parentHeader.BaseFee = test.parentBaseFee + parentHeader.Number = test.parentBlockNumber + parentBlock := types.NewBlockWithHeader(parentHeader) + gasLimit, baseFee := CalcGasLimitAndBaseFee(&config, parentBlock, parentHeader.GasLimit, parentHeader.GasLimit) + if gasLimit != test.gasLimit { + t.Errorf("test %d expected GasLimit %d got %d", i+1, test.gasLimit, gasLimit) + } + if baseFee == nil && test.baseFee != nil { + t.Errorf("test %d expected BaseFee %d got nil", i+1, test.baseFee) + } else if baseFee != nil && baseFee.Cmp(test.baseFee) != 0 { + t.Errorf("test %d expected BaseFee %d got %d", i+1, test.baseFee.Uint64(), baseFee.Uint64()) + } + } } diff --git a/core/chain_makers_test.go b/core/chain_makers_test.go index e3ef08f55..ec0baf290 100644 --- a/core/chain_makers_test.go +++ b/core/chain_makers_test.go @@ -132,9 +132,8 @@ func generateChainBeforeActivation(t *testing.T) { // Ensure that key1 has some funds in the genesis block. gspec := &Genesis{ - Config: ¶ms.ChainConfig{HomesteadBlock: new(big.Int)}, - Alloc: GenesisAlloc{addr1: {Balance: big.NewInt(1000000)}}, - BaseFee: new(big.Int), + Config: ¶ms.ChainConfig{HomesteadBlock: new(big.Int)}, + Alloc: GenesisAlloc{addr1: {Balance: big.NewInt(1000000)}}, } genesis := gspec.MustCommit(db) @@ -195,7 +194,7 @@ func generateChainDuringTransition(t *testing.T) { gspec := &Genesis{ Config: params.EIP1559ChainConfig, Alloc: GenesisAlloc{addr1: {Balance: big.NewInt(1000000)}}, - BaseFee: new(big.Int), + BaseFee: new(big.Int).SetUint64(params.EIP1559InitialBaseFee), } genesis := gspec.MustCommit(db) @@ -258,6 +257,7 @@ func generateChainDuringTransition(t *testing.T) { // generateChainAfterFinalization demonstrates that we panic if we try to make a chain with legacy transactions after EIP1559 finalization func generateChainAfterFinalization(t *testing.T) { + // We expect a panic due to an ErrTxNotEIP1559 error because of the panic at line 119 in chain_makers.go defer func() { if err := recover().(error); err != nil { if err != ErrTxNotEIP1559 { @@ -279,7 +279,7 @@ func generateChainAfterFinalization(t *testing.T) { gspec := &Genesis{ Config: params.EIP1559FinalizedChainConfig, Alloc: GenesisAlloc{addr1: {Balance: big.NewInt(1000000)}}, - BaseFee: new(big.Int), + BaseFee: new(big.Int).SetUint64(params.EIP1559InitialBaseFee), } genesis := gspec.MustCommit(db) @@ -339,8 +339,8 @@ func generateChainAfterFinalization2(t *testing.T) { // Ensure that key1 has some funds in the genesis block. gspec := &Genesis{ Config: params.EIP1559FinalizedChainConfig, - Alloc: GenesisAlloc{addr1: {Balance: big.NewInt(1000000)}}, - BaseFee: new(big.Int), + Alloc: GenesisAlloc{addr1: {Balance: new(big.Int).SetUint64((params.EIP1559InitialBaseFee * params.TxGas) + 1000000)}}, + BaseFee: new(big.Int).SetUint64(params.EIP1559InitialBaseFee), } genesis := gspec.MustCommit(db) @@ -352,7 +352,7 @@ func generateChainAfterFinalization2(t *testing.T) { switch i { case 0: // In block 1, addr1 sends addr2 some ether. - tx, _ := types.SignTx(types.NewTransaction(gen.TxNonce(addr1), addr2, big.NewInt(10000), params.TxGas, nil, nil, new(big.Int), new(big.Int)), signer, key1) + tx, _ := types.SignTx(types.NewTransaction(gen.TxNonce(addr1), addr2, big.NewInt(10000), params.TxGas, nil, nil, new(big.Int), new(big.Int).SetUint64(params.EIP1559InitialBaseFee)), signer, key1) gen.AddTx(tx) case 1: // In block 2, addr1 sends some more ether to addr2. @@ -388,7 +388,7 @@ func generateChainAfterFinalization2(t *testing.T) { if blockchain.CurrentBlock().Number().Uint64() != 5 { t.Fatalf("expected last block to equal %d got %d", 5, blockchain.CurrentBlock().Number().Uint64()) } - if state.GetBalance(addr1).Uint64() != 989000 { + if state.GetBalance(addr1).Uint64() != 2625000989000 { t.Fatalf("expected balance of addr1 to equal %d got %d", 989000, state.GetBalance(addr1).Uint64()) } if state.GetBalance(addr2).Uint64() != 10000 {