From 695083e5627c4ef63143575d6a8fb3632d94b3f9 Mon Sep 17 00:00:00 2001 From: Mister-EA Date: Fri, 7 Apr 2023 12:21:30 +0200 Subject: [PATCH 1/8] core, params, consensus: enable london hard fork features with basefee=0 --- consensus/misc/eip1559.go | 67 ++++++++++++++++++---------------- consensus/misc/eip1559_test.go | 4 +- consensus/parlia/parlia.go | 60 +++++++++++++++++++++--------- core/state_processor_test.go | 4 +- core/state_transition.go | 11 +++--- core/types/block_test.go | 5 ++- params/protocol_params.go | 6 +-- 7 files changed, 93 insertions(+), 64 deletions(-) diff --git a/consensus/misc/eip1559.go b/consensus/misc/eip1559.go index 8fca0fdc70..52a199f4f9 100644 --- a/consensus/misc/eip1559.go +++ b/consensus/misc/eip1559.go @@ -20,8 +20,6 @@ import ( "fmt" "math/big" - "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/params" ) @@ -42,6 +40,10 @@ func VerifyEip1559Header(config *params.ChainConfig, parent, header *types.Heade if header.BaseFee == nil { return fmt.Errorf("header is missing baseFee") } + + if header.BaseFee.Cmp(big.NewInt(params.InitialBaseFee)) != 0 { + return fmt.Errorf("header has a non-zero baseFee of %v", header.BaseFee) + } // Verify the baseFee is correct based on the parent header. expectedBaseFee := CalcBaseFee(config, parent) if header.BaseFee.Cmp(expectedBaseFee) != 0 { @@ -57,37 +59,38 @@ func CalcBaseFee(config *params.ChainConfig, parent *types.Header) *big.Int { if !config.IsLondon(parent.Number) { return new(big.Int).SetUint64(params.InitialBaseFee) } + return new(big.Int).SetUint64(params.InitialBaseFee) - var ( - parentGasTarget = parent.GasLimit / params.ElasticityMultiplier - parentGasTargetBig = new(big.Int).SetUint64(parentGasTarget) - baseFeeChangeDenominator = new(big.Int).SetUint64(params.BaseFeeChangeDenominator) - ) - // If the parent gasUsed is the same as the target, the baseFee remains unchanged. - if parent.GasUsed == parentGasTarget { - return new(big.Int).Set(parent.BaseFee) - } - if parent.GasUsed > parentGasTarget { - // If the parent block used more gas than its target, the baseFee should increase. - gasUsedDelta := new(big.Int).SetUint64(parent.GasUsed - parentGasTarget) - x := new(big.Int).Mul(parent.BaseFee, gasUsedDelta) - y := x.Div(x, parentGasTargetBig) - baseFeeDelta := math.BigMax( - x.Div(y, baseFeeChangeDenominator), - common.Big1, - ) + // var ( + // parentGasTarget = parent.GasLimit / params.ElasticityMultiplier + // parentGasTargetBig = new(big.Int).SetUint64(parentGasTarget) + // baseFeeChangeDenominator = new(big.Int).SetUint64(params.BaseFeeChangeDenominator) + // ) + // // If the parent gasUsed is the same as the target, the baseFee remains unchanged. + // if parent.GasUsed == parentGasTarget { + // return new(big.Int).Set(parent.BaseFee) + // } + // if parent.GasUsed > parentGasTarget { + // // If the parent block used more gas than its target, the baseFee should increase. + // gasUsedDelta := new(big.Int).SetUint64(parent.GasUsed - parentGasTarget) + // x := new(big.Int).Mul(parent.BaseFee, gasUsedDelta) + // y := x.Div(x, parentGasTargetBig) + // baseFeeDelta := math.BigMax( + // x.Div(y, baseFeeChangeDenominator), + // common.Big1, + // ) - return x.Add(parent.BaseFee, baseFeeDelta) - } else { - // Otherwise if the parent block used less gas than its target, the baseFee should decrease. - gasUsedDelta := new(big.Int).SetUint64(parentGasTarget - parent.GasUsed) - x := new(big.Int).Mul(parent.BaseFee, gasUsedDelta) - y := x.Div(x, parentGasTargetBig) - baseFeeDelta := x.Div(y, baseFeeChangeDenominator) + // return x.Add(parent.BaseFee, baseFeeDelta) + // } else { + // // Otherwise if the parent block used less gas than its target, the baseFee should decrease. + // gasUsedDelta := new(big.Int).SetUint64(parentGasTarget - parent.GasUsed) + // x := new(big.Int).Mul(parent.BaseFee, gasUsedDelta) + // y := x.Div(x, parentGasTargetBig) + // baseFeeDelta := x.Div(y, baseFeeChangeDenominator) - return math.BigMax( - x.Sub(parent.BaseFee, baseFeeDelta), - common.Big0, - ) - } + // return math.BigMax( + // x.Sub(parent.BaseFee, baseFeeDelta), + // common.Big0, + // ) + // } } diff --git a/consensus/misc/eip1559_test.go b/consensus/misc/eip1559_test.go index aaa09da9b9..da532e1957 100644 --- a/consensus/misc/eip1559_test.go +++ b/consensus/misc/eip1559_test.go @@ -115,8 +115,8 @@ func TestCalcBaseFee(t *testing.T) { expectedBaseFee int64 }{ {params.InitialBaseFee, 20000000, 10000000, params.InitialBaseFee}, // usage == target - {params.InitialBaseFee, 20000000, 9000000, 987500000}, // usage below target - {params.InitialBaseFee, 20000000, 11000000, 1012500000}, // usage above target + {params.InitialBaseFee, 20000000, 9000000, params.InitialBaseFee}, // usage below target + {params.InitialBaseFee, 20000000, 11000000, params.InitialBaseFee}, // usage above target } for i, test := range tests { parent := &types.Header{ diff --git a/consensus/parlia/parlia.go b/consensus/parlia/parlia.go index b660217c17..46cade8dc6 100644 --- a/consensus/parlia/parlia.go +++ b/consensus/parlia/parlia.go @@ -394,6 +394,22 @@ func getVoteAttestationFromHeader(header *types.Header, chainConfig *params.Chai return &attestation, nil } +func (p *Parlia) getParent(chain consensus.ChainHeaderReader, header *types.Header, parents []*types.Header) (*types.Header, error) { + var parent *types.Header + number := header.Number.Uint64() + if len(parents) > 0 { + parent = parents[len(parents)-1] + } else { + parent = chain.GetHeader(header.ParentHash, number-1) + } + + if parent == nil || parent.Number.Uint64() != number-1 || parent.Hash() != header.ParentHash { + return nil, consensus.ErrUnknownAncestor + } else { + return parent, nil + } +} + // verifyVoteAttestation checks whether the vote attestation in the header is valid. func (p *Parlia) verifyVoteAttestation(chain consensus.ChainHeaderReader, header *types.Header, parents []*types.Header) error { attestation, err := getVoteAttestationFromHeader(header, p.chainConfig, p.config) @@ -411,15 +427,9 @@ func (p *Parlia) verifyVoteAttestation(chain consensus.ChainHeaderReader, header } // Get parent block - number := header.Number.Uint64() - var parent *types.Header - if len(parents) > 0 { - parent = parents[len(parents)-1] - } else { - parent = chain.GetHeader(header.ParentHash, number-1) - } - if parent == nil || parent.Hash() != header.ParentHash { - return consensus.ErrUnknownAncestor + parent, err := p.getParent(chain, header, parents) + if err != nil { + return err } // The target block should be direct parent. @@ -541,6 +551,26 @@ func (p *Parlia) verifyHeader(chain consensus.ChainHeaderReader, header *types.H if err := misc.VerifyForkHashes(chain.Config(), header, false); err != nil { return err } + + parent, err := p.getParent(chain, header, parents) + if err != nil { + return err + } + + // Verify the block's gas usage and (if applicable) verify the base fee. + if !chain.Config().IsLondon(header.Number) { + // Verify BaseFee not present before EIP-1559 fork. + if header.BaseFee != nil { + return fmt.Errorf("invalid baseFee before fork: have %d, expected 'nil'", header.BaseFee) + } + if err := misc.VerifyGaslimit(parent.GasLimit, header.GasLimit); err != nil { + return err + } + } else if err := misc.VerifyEip1559Header(chain.Config(), parent, header); err != nil { + // Verify the header's EIP-1559 attributes. + return err + } + // All basic checks passed, verify cascading fields return p.verifyCascadingFields(chain, header, parents) } @@ -556,15 +586,9 @@ func (p *Parlia) verifyCascadingFields(chain consensus.ChainHeaderReader, header return nil } - var parent *types.Header - if len(parents) > 0 { - parent = parents[len(parents)-1] - } else { - parent = chain.GetHeader(header.ParentHash, number-1) - } - - if parent == nil || parent.Number.Uint64() != number-1 || parent.Hash() != header.ParentHash { - return consensus.ErrUnknownAncestor + parent, err := p.getParent(chain, header, parents) + if err != nil { + return err } snap, err := p.snapshot(chain, number-1, header.ParentHash, parents) diff --git a/core/state_processor_test.go b/core/state_processor_test.go index 964c08947c..d1dd278308 100644 --- a/core/state_processor_test.go +++ b/core/state_processor_test.go @@ -160,11 +160,11 @@ func TestStateProcessorErrors(t *testing.T) { }, want: "could not apply tx 0 [0xbd49d8dadfd47fb846986695f7d4da3f7b2c48c8da82dbc211a26eb124883de9]: gas limit reached", }, - { // ErrFeeCapTooLow + { // ErrFeeCapTooLow does not apply because default BaseFee is 0 txs: []*types.Transaction{ mkDynamicTx(0, common.Address{}, params.TxGas, big.NewInt(0), big.NewInt(0)), }, - want: "could not apply tx 0 [0xc4ab868fef0c82ae0387b742aee87907f2d0fc528fc6ea0a021459fb0fc4a4a8]: max fee per gas less than block base fee: address 0x71562b71999873DB5b286dF957af199Ec94617F7, maxFeePerGas: 0 baseFee: 875000000", + want: "invalid gas used (remote: 0 local: 21000)", }, { // ErrTipVeryHigh txs: []*types.Transaction{ diff --git a/core/state_transition.go b/core/state_transition.go index 8083a4ea61..f4f38b6e29 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -353,14 +353,15 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { st.refundGas(params.RefundQuotientEIP3529) } + effectiveTip := st.gasPrice + if rules.IsLondon { + effectiveTip = cmath.BigMin(st.gasTipCap, new(big.Int).Sub(st.gasFeeCap, st.evm.Context.BaseFee)) + } + // consensus engine is parlia if st.evm.ChainConfig().Parlia != nil { - st.state.AddBalance(consensus.SystemAddress, new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), st.gasPrice)) + st.state.AddBalance(consensus.SystemAddress, new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), effectiveTip)) } else { - effectiveTip := st.gasPrice - if rules.IsLondon { - effectiveTip = cmath.BigMin(st.gasTipCap, new(big.Int).Sub(st.gasFeeCap, st.evm.Context.BaseFee)) - } st.state.AddBalance(st.evm.Context.Coinbase, new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), effectiveTip)) } diff --git a/core/types/block_test.go b/core/types/block_test.go index aa1db2f4fa..01ad95312a 100644 --- a/core/types/block_test.go +++ b/core/types/block_test.go @@ -69,7 +69,7 @@ func TestBlockEncoding(t *testing.T) { } func TestEIP1559BlockEncoding(t *testing.T) { - blockEnc := common.FromHex("f9030bf901fea083cafc574e1f51ba9dc0568fc617a08ea2429fb384059c972f13b19fa1c8dd55a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0ef1552a40b7165c3cd773806b9e0c165b75356e0314bf0706f279c729f51e017a05fe50b260da6308036625b850b5d6ced6d0a9f814c0688bc91ffb7b7a3a54b67a0bc37d79753ad738a6dac4921e57392f145d8887476de3f783dfa7edae9283e52b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000001832fefd8825208845506eb0780a0bd4472abb6659ebe3ee06ee4d7b72a00a9f4d001caca51342001075469aff49888a13a5a8c8f2bb1c4843b9aca00f90106f85f800a82c35094095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba09bea4c4daac7c7c52e093e6a4c35dbbcf8856f1af7b059ba20253e70848d094fa08a8fae537ce25ed8cb5af9adac3f141af69bd515bd2ba031522df09b97dd72b1b8a302f8a0018080843b9aca008301e24194095e7baea6a6c7c4c2dfeb977efac326af552d878080f838f7940000000000000000000000000000000000000001e1a0000000000000000000000000000000000000000000000000000000000000000080a0fe38ca4e44a30002ac54af7cf922a6ac2ba11b7d22f548e8ecb3f51f41cb31b0a06de6a5cbae13c0c856e33acf021b51819636cfc009d39eafb9f606d546e305a8c0") + blockEnc := common.FromHex("f90303f901faa083cafc574e1f51ba9dc0568fc617a08ea2429fb384059c972f13b19fa1c8dd55a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0ef1552a40b7165c3cd773806b9e0c165b75356e0314bf0706f279c729f51e017a05fe50b260da6308036625b850b5d6ced6d0a9f814c0688bc91ffb7b7a3a54b67a0bc37d79753ad738a6dac4921e57392f145d8887476de3f783dfa7edae9283e52b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000001832fefd8825208845506eb0780a0bd4472abb6659ebe3ee06ee4d7b72a00a9f4d001caca51342001075469aff49888a13a5a8c8f2bb1c480f90102f85f800a82c35094095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba09bea4c4daac7c7c52e093e6a4c35dbbcf8856f1af7b059ba20253e70848d094fa08a8fae537ce25ed8cb5af9adac3f141af69bd515bd2ba031522df09b97dd72b1b89f02f89c018080808301e24194095e7baea6a6c7c4c2dfeb977efac326af552d878080f838f7940000000000000000000000000000000000000001e1a0000000000000000000000000000000000000000000000000000000000000000080a0fe38ca4e44a30002ac54af7cf922a6ac2ba11b7d22f548e8ecb3f51f41cb31b0a06de6a5cbae13c0c856e33acf021b51819636cfc009d39eafb9f606d546e305a8c0") var block Block if err := rlp.DecodeBytes(blockEnc, &block); err != nil { t.Fatal("decode error: ", err) @@ -87,7 +87,7 @@ func TestEIP1559BlockEncoding(t *testing.T) { check("Coinbase", block.Coinbase(), common.HexToAddress("8888f1f195afa192cfee860698584c030f4c9db1")) check("MixDigest", block.MixDigest(), common.HexToHash("bd4472abb6659ebe3ee06ee4d7b72a00a9f4d001caca51342001075469aff498")) check("Root", block.Root(), common.HexToHash("ef1552a40b7165c3cd773806b9e0c165b75356e0314bf0706f279c729f51e017")) - check("Hash", block.Hash(), common.HexToHash("c7252048cd273fe0dac09650027d07f0e3da4ee0675ebbb26627cea92729c372")) + check("Hash", block.Hash(), common.HexToHash("0xae9d971d16de73f69f940f1bd4ce5961158781176e73abea92a2b8781403885e")) check("Nonce", block.Nonce(), uint64(0xa13a5a8c8f2bb1c4)) check("Time", block.Time(), uint64(1426516743)) check("Size", block.Size(), common.StorageSize(len(blockEnc))) @@ -122,6 +122,7 @@ func TestEIP1559BlockEncoding(t *testing.T) { check("len(Transactions)", len(block.Transactions()), 2) check("Transactions[0].Hash", block.Transactions()[0].Hash(), tx1.Hash()) + check("Transactions[1].inner", block.Transactions()[1].inner, tx2.inner) check("Transactions[1].Hash", block.Transactions()[1].Hash(), tx2.Hash()) check("Transactions[1].Type", block.Transactions()[1].Type(), tx2.Type()) ourBlockEnc, err := rlp.EncodeToBytes(&block) diff --git a/params/protocol_params.go b/params/protocol_params.go index 527c6dc166..2a6b07ac23 100644 --- a/params/protocol_params.go +++ b/params/protocol_params.go @@ -121,9 +121,9 @@ const ( // Introduced in Tangerine Whistle (Eip 150) CreateBySelfdestructGas uint64 = 25000 - BaseFeeChangeDenominator = 8 // Bounds the amount the base fee can change between blocks. - ElasticityMultiplier = 2 // Bounds the maximum gas limit an EIP-1559 block may have. - InitialBaseFee = 1000000000 // Initial base fee for EIP-1559 blocks. + BaseFeeChangeDenominator = 8 // Bounds the amount the base fee can change between blocks. + ElasticityMultiplier = 2 // Bounds the maximum gas limit an EIP-1559 block may have. + InitialBaseFee = 0 // Initial base fee for EIP-1559 blocks. MaxCodeSize = 24576 // Maximum bytecode to permit for a contract From 9f4b58d3cdb95a52ee98fda814e50f0f3a2e0d19 Mon Sep 17 00:00:00 2001 From: Mister-EA Date: Fri, 7 Apr 2023 13:41:04 +0200 Subject: [PATCH 2/8] ethclient, graphql: update test cases --- ethclient/ethclient_test.go | 19 +++++++++++++++---- graphql/graphql_test.go | 2 +- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/ethclient/ethclient_test.go b/ethclient/ethclient_test.go index 355905d950..3b133fc889 100644 --- a/ethclient/ethclient_test.go +++ b/ethclient/ethclient_test.go @@ -39,6 +39,7 @@ import ( "github.com/ethereum/go-ethereum/internal/ethapi" "github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rpc" ) @@ -419,10 +420,20 @@ func testHeader(t *testing.T, chain []*types.Block, client *rpc.Client) { if !errors.Is(err, tt.wantErr) { t.Fatalf("HeaderByNumber(%v) error = %q, want %q", tt.block, err, tt.wantErr) } - if got != nil && got.Number != nil && got.Number.Sign() == 0 { - got.Number = big.NewInt(0) // hack to make DeepEqual work + + gotBytes, err := rlp.EncodeToBytes(got) + if err != nil { + t.Fatalf("Error serializing received block header.") + } + wantBytes, _ := rlp.EncodeToBytes(tt.want) + if err != nil { + t.Fatalf("Error serializing wanted block header.") } - if !reflect.DeepEqual(got, tt.want) { + + // Instead of comparing the Header's compare the serialized bytes, + // because reflect.DeepEqual(*types.Header, *types.Header) sometimes + // returns false even though the underlying field values are exactly the same. + if !reflect.DeepEqual(gotBytes, wantBytes) { t.Fatalf("HeaderByNumber(%v)\n = %v\nwant %v", tt.block, got, tt.want) } }) @@ -583,7 +594,7 @@ func testStatusFunctions(t *testing.T, client *rpc.Client) { if err != nil { t.Fatalf("unexpected error: %v", err) } - if gasPrice.Cmp(big.NewInt(1000000042)) != 0 { + if gasPrice.Cmp(big.NewInt(1000000000)) != 0 { t.Fatalf("unexpected gas price: %v", gasPrice) } diff --git a/graphql/graphql_test.go b/graphql/graphql_test.go index a0b7979069..4d709d50d2 100644 --- a/graphql/graphql_test.go +++ b/graphql/graphql_test.go @@ -177,7 +177,7 @@ func TestGraphQLBlockSerializationEIP2718(t *testing.T) { }{ { body: `{"query": "{block {number transactions { from { address } to { address } value hash type accessList { address storageKeys } index}}}"}`, - want: `{"data":{"block":{"number":1,"transactions":[{"from":{"address":"0x71562b71999873db5b286df957af199ec94617f7"},"to":{"address":"0x0000000000000000000000000000000000000dad"},"value":"0x64","hash":"0xd864c9d7d37fade6b70164740540c06dd58bb9c3f6b46101908d6339db6a6a7b","type":0,"accessList":[],"index":0},{"from":{"address":"0x71562b71999873db5b286df957af199ec94617f7"},"to":{"address":"0x0000000000000000000000000000000000000dad"},"value":"0x32","hash":"0x19b35f8187b4e15fb59a9af469dca5dfa3cd363c11d372058c12f6482477b474","type":1,"accessList":[{"address":"0x0000000000000000000000000000000000000dad","storageKeys":["0x0000000000000000000000000000000000000000000000000000000000000000"]}],"index":1}]}}}`, + want: `{"data":{"block":{"number":1,"transactions":[{"from":{"address":"0x71562b71999873db5b286df957af199ec94617f7"},"to":{"address":"0x0000000000000000000000000000000000000dad"},"value":"0x64","hash":"0xe7418d03e2ece5fcd277c49bf9d8b7b9d43a9e27731d56a6496eb9e54d504202","type":0,"accessList":[],"index":0},{"from":{"address":"0x71562b71999873db5b286df957af199ec94617f7"},"to":{"address":"0x0000000000000000000000000000000000000dad"},"value":"0x32","hash":"0x0f32fec26e145116d7927ce74dfa64334682747459481246cde86e68d3091679","type":1,"accessList":[{"address":"0x0000000000000000000000000000000000000dad","storageKeys":["0x0000000000000000000000000000000000000000000000000000000000000000"]}],"index":1}]}}}`, code: 200, }, } { From c69b538340b38d4b9edb8e45f2579459976226e2 Mon Sep 17 00:00:00 2001 From: Mister-EA Date: Tue, 11 Apr 2023 18:50:37 +0200 Subject: [PATCH 3/8] core: add eip3529 tests --- core/blockchain_eip3529_test.go | 165 ++++++++++++++++++++++++++++++++ 1 file changed, 165 insertions(+) create mode 100644 core/blockchain_eip3529_test.go diff --git a/core/blockchain_eip3529_test.go b/core/blockchain_eip3529_test.go new file mode 100644 index 0000000000..25e91469a0 --- /dev/null +++ b/core/blockchain_eip3529_test.go @@ -0,0 +1,165 @@ +package core + +import ( + "math/big" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/consensus" + "github.com/ethereum/go-ethereum/consensus/ethash" + "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" +) + +func postLondonConfig() *params.ChainConfig { + config := *params.TestChainConfig + config.LondonBlock = big.NewInt(0) + return &config +} + +func preLondonConfig() *params.ChainConfig { + config := *params.TestChainConfig + config.LondonBlock = nil + return &config +} + +func TestSelfDestructGasPreEIP3529(t *testing.T) { + bytecode := []byte{ + byte(vm.PC), + byte(vm.SELFDESTRUCT), + } + + // Expected gas is (intrinsic + pc + cold load (due to legacy tx) + selfdestruct cost ) / 2 + // The refund of 24000 gas (i.e. params.SelfdestructRefundGas) is not applied since refunds pre-EIP3529 are + // capped to half of the transaction's gas. + expectedGasUsed := (params.TxGas + vm.GasQuickStep + params.ColdAccountAccessCostEIP2929 + params.SelfdestructGasEIP150) / 2 + testGasUsage(t, preLondonConfig(), ethash.NewFaker(), bytecode, nil, 60_000, expectedGasUsed) +} + +func TestSstoreGasPreEIP3529(t *testing.T) { + bytecode := []byte{ + byte(vm.PUSH1), 0x3, // value + byte(vm.PUSH1), 0x3, // location + byte(vm.SSTORE), // Set slot[3] = 3 + } + // // Expected gas is intrinsic + 2*pushGas + cold load (due to legacy tx) + SstoreGas + expectedGasUsed := params.TxGas + 2*vm.GasFastestStep + params.ColdSloadCostEIP2929 + params.SstoreSetGasEIP2200 + testGasUsage(t, preLondonConfig(), ethash.NewFaker(), bytecode, nil, 60_000, expectedGasUsed) +} + +func TestSelfDestructGasPostEIP3529(t *testing.T) { + bytecode := []byte{ + byte(vm.PC), + byte(vm.SELFDESTRUCT), + } + // Expected gas is intrinsic + pc + cold load (due to legacy tx) + SelfDestructGas + expectedGasUsed := params.TxGas + vm.GasQuickStep + params.ColdAccountAccessCostEIP2929 + params.SelfdestructGasEIP150 + testGasUsage(t, postLondonConfig(), ethash.NewFaker(), bytecode, nil, 60_000, expectedGasUsed) +} + +func TestSstoreGasPostEIP3529(t *testing.T) { + bytecode := []byte{ + byte(vm.PUSH1), 0x3, // value + byte(vm.PUSH1), 0x3, // location + byte(vm.SSTORE), // Set slot[3] = 3 + } + // Expected gas is intrinsic + 2*pushGas + cold load (due to legacy tx) + SstoreGas + expectedGasUsed := params.TxGas + 2*vm.GasFastestStep + params.ColdSloadCostEIP2929 + params.SstoreSetGasEIP2200 + testGasUsage(t, postLondonConfig(), ethash.NewFaker(), bytecode, nil, 60_000, expectedGasUsed) +} + +func TestSstoreModifyGasPostEIP3529(t *testing.T) { + bytecode := []byte{ + byte(vm.PUSH1), 0x3, // value + byte(vm.PUSH1), 0x1, // location + byte(vm.SSTORE), // Set slot[1] = 3 + } + // initialize contract storage + initialStorage := make(map[common.Hash]common.Hash) + // Populate two slots + initialStorage[common.HexToHash("01")] = common.HexToHash("01") + initialStorage[common.HexToHash("02")] = common.HexToHash("02") + // Expected gas is intrinsic + 2*pushGas + cold load (due to legacy tx) + SstoreReset (a->b such that a!=0) + expectedGasUsed := params.TxGas + 2*vm.GasFastestStep + params.ColdSloadCostEIP2929 + (params.SstoreResetGasEIP2200 - params.ColdSloadCostEIP2929) + testGasUsage(t, postLondonConfig(), ethash.NewFaker(), bytecode, initialStorage, 60_000, expectedGasUsed) +} + +func TestSstoreClearGasPostEIP3529(t *testing.T) { + bytecode := []byte{ + byte(vm.PUSH1), 0x0, // value + byte(vm.PUSH1), 0x1, // location + byte(vm.SSTORE), // Set slot[1] = 0 + } + // initialize contract storage + initialStorage := make(map[common.Hash]common.Hash) + // Populate two slots + initialStorage[common.HexToHash("01")] = common.HexToHash("01") + initialStorage[common.HexToHash("02")] = common.HexToHash("02") + + // Expected gas is intrinsic + 2*pushGas + cold load (due to legacy tx) + SstoreReset (a->b such that a!=0) - sstoreClearGasRefund + expectedGasUsage := params.TxGas + 2*vm.GasFastestStep + params.ColdSloadCostEIP2929 + (params.SstoreResetGasEIP2200 - params.ColdSloadCostEIP2929) - params.SstoreClearsScheduleRefundEIP3529 + testGasUsage(t, postLondonConfig(), ethash.NewFaker(), bytecode, initialStorage, 60_000, expectedGasUsage) +} + +// Test the gas used by running a transaction sent to a smart contract with given bytecode and storage. +func testGasUsage(t *testing.T, config *params.ChainConfig, engine consensus.Engine, bytecode []byte, initialStorage map[common.Hash]common.Hash, initialGas, expectedGasUsed uint64) { + var ( + aa = common.HexToAddress("0x000000000000000000000000000000000000aaaa") + + // Generate a canonical chain to act as the main dataset + db = rawdb.NewMemoryDatabase() + + // A sender who makes transactions, has some funds + key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + address = crypto.PubkeyToAddress(key.PublicKey) + balanceBefore = big.NewInt(1000000000000000) + gspec = &Genesis{ + Config: config, + Alloc: GenesisAlloc{ + address: {Balance: balanceBefore}, + aa: { + Code: bytecode, + Storage: initialStorage, + Nonce: 0, + Balance: big.NewInt(0), + }, + }, + } + genesis = gspec.MustCommit(db) + ) + + blocks, _ := GenerateChain(gspec.Config, genesis, engine, db, 1, func(i int, b *BlockGen) { + b.SetCoinbase(common.Address{1}) + + // One transaction to 0xAAAA + signer := types.LatestSigner(gspec.Config) + tx, _ := types.SignNewTx(key, signer, &types.LegacyTx{ + Nonce: 0, + To: &aa, + Gas: initialGas, + GasPrice: newGwei(5), + }) + b.AddTx(tx) + }) + + // Import the canonical chain + diskdb := rawdb.NewMemoryDatabase() + gspec.MustCommit(diskdb) + + chain, err := NewBlockChain(diskdb, nil, gspec.Config, engine, vm.Config{}, nil, nil) + if err != nil { + t.Fatalf("failed to create tester chain: %v", err) + } + 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 block.GasUsed() != expectedGasUsed { + t.Fatalf("incorrect amount of gas spent: expected %d, got %d", expectedGasUsed, block.GasUsed()) + } +} From 506c36c14d87bf76d07582af641c6b3176f886e9 Mon Sep 17 00:00:00 2001 From: Mister-EA Date: Wed, 12 Apr 2023 12:21:48 +0200 Subject: [PATCH 4/8] consensus: remove commented out code --- consensus/misc/eip1559.go | 33 --------------------------------- 1 file changed, 33 deletions(-) diff --git a/consensus/misc/eip1559.go b/consensus/misc/eip1559.go index 52a199f4f9..5f229e9add 100644 --- a/consensus/misc/eip1559.go +++ b/consensus/misc/eip1559.go @@ -60,37 +60,4 @@ func CalcBaseFee(config *params.ChainConfig, parent *types.Header) *big.Int { return new(big.Int).SetUint64(params.InitialBaseFee) } return new(big.Int).SetUint64(params.InitialBaseFee) - - // var ( - // parentGasTarget = parent.GasLimit / params.ElasticityMultiplier - // parentGasTargetBig = new(big.Int).SetUint64(parentGasTarget) - // baseFeeChangeDenominator = new(big.Int).SetUint64(params.BaseFeeChangeDenominator) - // ) - // // If the parent gasUsed is the same as the target, the baseFee remains unchanged. - // if parent.GasUsed == parentGasTarget { - // return new(big.Int).Set(parent.BaseFee) - // } - // if parent.GasUsed > parentGasTarget { - // // If the parent block used more gas than its target, the baseFee should increase. - // gasUsedDelta := new(big.Int).SetUint64(parent.GasUsed - parentGasTarget) - // x := new(big.Int).Mul(parent.BaseFee, gasUsedDelta) - // y := x.Div(x, parentGasTargetBig) - // baseFeeDelta := math.BigMax( - // x.Div(y, baseFeeChangeDenominator), - // common.Big1, - // ) - - // return x.Add(parent.BaseFee, baseFeeDelta) - // } else { - // // Otherwise if the parent block used less gas than its target, the baseFee should decrease. - // gasUsedDelta := new(big.Int).SetUint64(parentGasTarget - parent.GasUsed) - // x := new(big.Int).Mul(parent.BaseFee, gasUsedDelta) - // y := x.Div(x, parentGasTargetBig) - // baseFeeDelta := x.Div(y, baseFeeChangeDenominator) - - // return math.BigMax( - // x.Sub(parent.BaseFee, baseFeeDelta), - // common.Big0, - // ) - // } } From 95e948a34bdaaf77daffb2e6e1afdee07647d5a3 Mon Sep 17 00:00:00 2001 From: Mister-EA Date: Wed, 12 Apr 2023 13:47:03 +0200 Subject: [PATCH 5/8] consensus: remove unnecessary if --- consensus/misc/eip1559.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/consensus/misc/eip1559.go b/consensus/misc/eip1559.go index 5f229e9add..4e69720ca3 100644 --- a/consensus/misc/eip1559.go +++ b/consensus/misc/eip1559.go @@ -55,9 +55,5 @@ func VerifyEip1559Header(config *params.ChainConfig, parent, header *types.Heade // CalcBaseFee calculates the basefee of the header. func CalcBaseFee(config *params.ChainConfig, parent *types.Header) *big.Int { - // If the current block is the first EIP-1559 block, return the InitialBaseFee. - if !config.IsLondon(parent.Number) { - return new(big.Int).SetUint64(params.InitialBaseFee) - } return new(big.Int).SetUint64(params.InitialBaseFee) } From f5c018b5710f7606a798820df1a2dc6b769b4af0 Mon Sep 17 00:00:00 2001 From: Mister-EA Date: Thu, 13 Apr 2023 10:55:01 +0200 Subject: [PATCH 6/8] consensus: add docstring for getParent --- consensus/parlia/parlia.go | 1 + 1 file changed, 1 insertion(+) diff --git a/consensus/parlia/parlia.go b/consensus/parlia/parlia.go index 46cade8dc6..b507addcf7 100644 --- a/consensus/parlia/parlia.go +++ b/consensus/parlia/parlia.go @@ -394,6 +394,7 @@ func getVoteAttestationFromHeader(header *types.Header, chainConfig *params.Chai return &attestation, nil } +// getParent returns the parent of a given block. func (p *Parlia) getParent(chain consensus.ChainHeaderReader, header *types.Header, parents []*types.Header) (*types.Header, error) { var parent *types.Header number := header.Number.Uint64() From 8fc96d6471c961590ab4918111777b526202fdf1 Mon Sep 17 00:00:00 2001 From: Mister-EA Date: Wed, 19 Apr 2023 12:03:11 +0200 Subject: [PATCH 7/8] consensus, misc: remove unnecessary parent gas limit check --- consensus/misc/eip1559.go | 12 +----------- consensus/parlia/parlia.go | 3 --- 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/consensus/misc/eip1559.go b/consensus/misc/eip1559.go index 4e69720ca3..41566ebdc3 100644 --- a/consensus/misc/eip1559.go +++ b/consensus/misc/eip1559.go @@ -28,22 +28,12 @@ import ( // - gas limit check // - basefee check func VerifyEip1559Header(config *params.ChainConfig, parent, header *types.Header) error { - // Verify that the gas limit remains within allowed bounds - parentGasLimit := parent.GasLimit - if !config.IsLondon(parent.Number) { - parentGasLimit = parent.GasLimit * params.ElasticityMultiplier - } - if err := VerifyGaslimit(parentGasLimit, header.GasLimit); err != nil { - return err - } + // Verify the header is not malformed if header.BaseFee == nil { return fmt.Errorf("header is missing baseFee") } - if header.BaseFee.Cmp(big.NewInt(params.InitialBaseFee)) != 0 { - return fmt.Errorf("header has a non-zero baseFee of %v", header.BaseFee) - } // Verify the baseFee is correct based on the parent header. expectedBaseFee := CalcBaseFee(config, parent) if header.BaseFee.Cmp(expectedBaseFee) != 0 { diff --git a/consensus/parlia/parlia.go b/consensus/parlia/parlia.go index b507addcf7..160d3f0729 100644 --- a/consensus/parlia/parlia.go +++ b/consensus/parlia/parlia.go @@ -564,9 +564,6 @@ func (p *Parlia) verifyHeader(chain consensus.ChainHeaderReader, header *types.H if header.BaseFee != nil { return fmt.Errorf("invalid baseFee before fork: have %d, expected 'nil'", header.BaseFee) } - if err := misc.VerifyGaslimit(parent.GasLimit, header.GasLimit); err != nil { - return err - } } else if err := misc.VerifyEip1559Header(chain.Config(), parent, header); err != nil { // Verify the header's EIP-1559 attributes. return err From 94a8f7c83f67c11774f4ec4c538eccf963147408 Mon Sep 17 00:00:00 2001 From: Mister-EA Date: Wed, 24 May 2023 13:18:54 +0200 Subject: [PATCH 8/8] consensus, ethclient, params: add LondonBlock to config --- consensus/parlia/parlia.go | 3 +-- ethclient/ethclient_test.go | 2 +- params/config.go | 9 ++++++--- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/consensus/parlia/parlia.go b/consensus/parlia/parlia.go index 160d3f0729..9f13d5731f 100644 --- a/consensus/parlia/parlia.go +++ b/consensus/parlia/parlia.go @@ -406,9 +406,8 @@ func (p *Parlia) getParent(chain consensus.ChainHeaderReader, header *types.Head if parent == nil || parent.Number.Uint64() != number-1 || parent.Hash() != header.ParentHash { return nil, consensus.ErrUnknownAncestor - } else { - return parent, nil } + return parent, nil } // verifyVoteAttestation checks whether the vote attestation in the header is valid. diff --git a/ethclient/ethclient_test.go b/ethclient/ethclient_test.go index 3b133fc889..1f81b3b256 100644 --- a/ethclient/ethclient_test.go +++ b/ethclient/ethclient_test.go @@ -425,7 +425,7 @@ func testHeader(t *testing.T, chain []*types.Block, client *rpc.Client) { if err != nil { t.Fatalf("Error serializing received block header.") } - wantBytes, _ := rlp.EncodeToBytes(tt.want) + wantBytes, err := rlp.EncodeToBytes(tt.want) if err != nil { t.Fatalf("Error serializing wanted block header.") } diff --git a/params/config.go b/params/config.go index 5cd772c8d0..0371cb5a68 100644 --- a/params/config.go +++ b/params/config.go @@ -194,8 +194,9 @@ var ( // TODO Caution !!! it should be very careful !!! LubanBlock: nil, PlatoBlock: nil, - // TODO modify blockNumber, make sure the Hertz block number is equal to BerlinBlock for enabling Berlin EIPs + // TODO modify blockNumber, make sure HertzBlock=BerlinBlock=LondonBlock to enable Berlin and London EIPs BerlinBlock: nil, + LondonBlock: nil, HertzBlock: nil, Parlia: &ParliaConfig{ @@ -227,9 +228,11 @@ var ( // TODO modify blockNumber, make sure the blockNumber is not an integer multiple of 200 (epoch number) // TODO Caution !!! it should be very careful !!! - LubanBlock: big.NewInt(29295050), - PlatoBlock: big.NewInt(29861024), + LubanBlock: big.NewInt(29295050), + PlatoBlock: big.NewInt(29861024), + // TODO modify blockNumber, make sure HertzBlock=BerlinBlock=LondonBlock to enable Berlin and London EIPs BerlinBlock: nil, + LondonBlock: nil, HertzBlock: nil, Parlia: &ParliaConfig{