From 5bcedac5e04f9bf09d5696c1182250fbaa9b6afc Mon Sep 17 00:00:00 2001 From: Rachit Sonthalia Date: Thu, 24 Aug 2023 22:44:01 +0530 Subject: [PATCH 01/20] corrected upfront gas deduction for type-2 transactions --- state/executor.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/state/executor.go b/state/executor.go index 4d31ff5ed1..57d1cf5da7 100644 --- a/state/executor.go +++ b/state/executor.go @@ -450,7 +450,7 @@ func (t *Transition) subGasLimitPrice(msg *types.Transaction) error { factor := new(big.Int) if msg.GasFeeCap != nil && msg.GasFeeCap.BitLen() > 0 { // Apply EIP-1559 tx cost calculation factor - factor = factor.Set(msg.GasFeeCap) + factor = factor.Set(msg.GetGasPrice(t.ctx.BaseFee.Uint64())) } else { // Apply legacy tx cost calculation factor factor = factor.Set(msg.GasPrice) From d37eace010555c0befd6380aae9cfd663e2edd81 Mon Sep 17 00:00:00 2001 From: Rachit Sonthalia Date: Fri, 25 Aug 2023 01:28:43 +0530 Subject: [PATCH 02/20] solve the bug reported in EVM-804 --- state/executor.go | 16 +++++++++++----- txpool/txpool.go | 6 ++++++ 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/state/executor.go b/state/executor.go index 57d1cf5da7..1d939fc386 100644 --- a/state/executor.go +++ b/state/executor.go @@ -634,11 +634,17 @@ func (t *Transition) apply(msg *types.Transaction) (*runtime.ExecutionResult, er // We use EIP-1559 fields of the tx if the london hardfork is enabled. // Effective tip became to be either gas tip cap or (gas fee cap - current base fee) effectiveTip := new(big.Int).Set(gasPrice) - if t.config.London && msg.Type == types.DynamicFeeTx { - effectiveTip = common.BigMin( - new(big.Int).Sub(msg.GasFeeCap, t.ctx.BaseFee), - new(big.Int).Set(msg.GasTipCap), - ) + + if t.config.London { + if msg.Type == types.DynamicFeeTx { + effectiveTip = common.BigMin( + new(big.Int).Sub(msg.GasFeeCap, t.ctx.BaseFee), + new(big.Int).Set(msg.GasTipCap), + ) + } else { + // legacy tx + effectiveTip.Sub(gasPrice, t.ctx.BaseFee) + } } // Pay the coinbase fee as a miner reward using the calculated effective tip. diff --git a/txpool/txpool.go b/txpool/txpool.go index 03461dea92..9b856db6bb 100644 --- a/txpool/txpool.go +++ b/txpool/txpool.go @@ -661,6 +661,12 @@ func (p *TxPool) validateTx(tx *types.Transaction) error { } } else { // Legacy approach to check if the given tx is not underpriced + if forks.London && tx.GasPrice.Cmp(new(big.Int).SetUint64(baseFee)) < 0 { + metrics.IncrCounter([]string{txPoolMetrics, "underpriced_tx"}, 1) + + return ErrUnderpriced + } + if tx.GetGasPrice(baseFee).Cmp(big.NewInt(0).SetUint64(p.priceLimit)) < 0 { metrics.IncrCounter([]string{txPoolMetrics, "underpriced_tx"}, 1) From 779ccbdba81b24a812369cfa61b1dc333846c6c0 Mon Sep 17 00:00:00 2001 From: Rachit Sonthalia Date: Fri, 25 Aug 2023 21:57:12 +0530 Subject: [PATCH 03/20] code optimization --- state/executor.go | 25 ++----------------------- txpool/txpool.go | 6 +----- 2 files changed, 3 insertions(+), 28 deletions(-) diff --git a/state/executor.go b/state/executor.go index 1d939fc386..5d6fbe79db 100644 --- a/state/executor.go +++ b/state/executor.go @@ -11,7 +11,6 @@ import ( "github.com/0xPolygon/polygon-edge/chain" "github.com/0xPolygon/polygon-edge/contracts" "github.com/0xPolygon/polygon-edge/crypto" - "github.com/0xPolygon/polygon-edge/helper/common" "github.com/0xPolygon/polygon-edge/state/runtime" "github.com/0xPolygon/polygon-edge/state/runtime/addresslist" "github.com/0xPolygon/polygon-edge/state/runtime/evm" @@ -445,18 +444,7 @@ func (t *Transition) ContextPtr() *runtime.TxContext { } func (t *Transition) subGasLimitPrice(msg *types.Transaction) error { - upfrontGasCost := new(big.Int).SetUint64(msg.Gas) - - factor := new(big.Int) - if msg.GasFeeCap != nil && msg.GasFeeCap.BitLen() > 0 { - // Apply EIP-1559 tx cost calculation factor - factor = factor.Set(msg.GetGasPrice(t.ctx.BaseFee.Uint64())) - } else { - // Apply legacy tx cost calculation factor - factor = factor.Set(msg.GasPrice) - } - - upfrontGasCost = upfrontGasCost.Mul(upfrontGasCost, factor) + upfrontGasCost := new(big.Int).Mul(new(big.Int).SetUint64(msg.Gas), msg.GetGasPrice(t.ctx.BaseFee.Uint64())) if err := t.state.SubBalance(msg.From, upfrontGasCost); err != nil { if errors.Is(err, runtime.ErrNotEnoughFunds) { @@ -634,17 +622,8 @@ func (t *Transition) apply(msg *types.Transaction) (*runtime.ExecutionResult, er // We use EIP-1559 fields of the tx if the london hardfork is enabled. // Effective tip became to be either gas tip cap or (gas fee cap - current base fee) effectiveTip := new(big.Int).Set(gasPrice) - if t.config.London { - if msg.Type == types.DynamicFeeTx { - effectiveTip = common.BigMin( - new(big.Int).Sub(msg.GasFeeCap, t.ctx.BaseFee), - new(big.Int).Set(msg.GasTipCap), - ) - } else { - // legacy tx - effectiveTip.Sub(gasPrice, t.ctx.BaseFee) - } + effectiveTip = msg.EffectiveGasTip(t.ctx.BaseFee) } // Pay the coinbase fee as a miner reward using the calculated effective tip. diff --git a/txpool/txpool.go b/txpool/txpool.go index 069a8b9b8d..90c96e6f6c 100644 --- a/txpool/txpool.go +++ b/txpool/txpool.go @@ -660,16 +660,12 @@ func (p *TxPool) validateTx(tx *types.Transaction) error { return ErrUnderpriced } } else { - // Legacy approach to check if the given tx is not underpriced + // Legacy approach to check if the given tx is not underpriced when london hardfork is enabled if forks.London && tx.GasPrice.Cmp(new(big.Int).SetUint64(baseFee)) < 0 { metrics.IncrCounter([]string{txPoolMetrics, "underpriced_tx"}, 1) return ErrUnderpriced } - - if tx.GetGasPrice(baseFee).Cmp(big.NewInt(0).SetUint64(p.priceLimit)) < 0 { - metrics.IncrCounter([]string{txPoolMetrics, "underpriced_tx"}, 1) - } } // Check if the given tx is not underpriced From 727e27764bf21d056aac76829ca93c4fe53d7173 Mon Sep 17 00:00:00 2001 From: Rachit Sonthalia Date: Fri, 25 Aug 2023 23:12:37 +0530 Subject: [PATCH 04/20] testCase fix --- state/transition_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/state/transition_test.go b/state/transition_test.go index de94c84cb0..d8e507c8be 100644 --- a/state/transition_test.go +++ b/state/transition_test.go @@ -18,6 +18,7 @@ func newTestTransition(preState map[types.Address]*PreState) *Transition { return &Transition{ logger: hclog.NewNullLogger(), state: newTestTxn(preState), + ctx: runtime.TxContext{BaseFee: big.NewInt(0)}, } } From e353402b6dec04dcaa71a5cfee71620b6fd98bf6 Mon Sep 17 00:00:00 2001 From: Rachit Sonthalia Date: Sat, 26 Aug 2023 00:52:40 +0530 Subject: [PATCH 05/20] added logic --- txpool/txpool.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/txpool/txpool.go b/txpool/txpool.go index 839d999950..1585674664 100644 --- a/txpool/txpool.go +++ b/txpool/txpool.go @@ -337,8 +337,15 @@ func (p *TxPool) Prepare() { // fetch primary from each account primaries := p.accounts.getPrimaries() + var eligiblePrimaries []*types.Transaction + for _, tx := range primaries { + if tx.GetGasFeeCap().Cmp(new(big.Int).SetUint64(p.GetBaseFee())) >= 0 { + eligiblePrimaries = append(eligiblePrimaries, tx) + } + } + // create new executables queue with base fee and initial transactions (primaries) - p.executables = newPricesQueue(p.GetBaseFee(), primaries) + p.executables = newPricesQueue(p.GetBaseFee(), eligiblePrimaries) } // Peek returns the best-price selected From ee0ef97c29aaf43f47d3ae8ebed1fc0ffca24a8c Mon Sep 17 00:00:00 2001 From: Rachit Sonthalia Date: Tue, 29 Aug 2023 13:14:33 +0530 Subject: [PATCH 06/20] fix linting error --- txpool/txpool.go | 1 + 1 file changed, 1 insertion(+) diff --git a/txpool/txpool.go b/txpool/txpool.go index 1585674664..8db3883c95 100644 --- a/txpool/txpool.go +++ b/txpool/txpool.go @@ -338,6 +338,7 @@ func (p *TxPool) Prepare() { primaries := p.accounts.getPrimaries() var eligiblePrimaries []*types.Transaction + for _, tx := range primaries { if tx.GetGasFeeCap().Cmp(new(big.Int).SetUint64(p.GetBaseFee())) >= 0 { eligiblePrimaries = append(eligiblePrimaries, tx) From 024131531fa00e68c62c1652ef977a55e82a5043 Mon Sep 17 00:00:00 2001 From: Rachit Sonthalia Date: Tue, 29 Aug 2023 23:38:06 +0530 Subject: [PATCH 07/20] refactored code --- txpool/account.go | 5 +++-- txpool/txpool.go | 14 +++----------- 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/txpool/account.go b/txpool/account.go index 6610a1dcd5..44116ebba2 100644 --- a/txpool/account.go +++ b/txpool/account.go @@ -1,6 +1,7 @@ package txpool import ( + "math/big" "sync" "sync/atomic" @@ -44,7 +45,7 @@ func (m *accountsMap) exists(addr types.Address) bool { // getPrimaries collects the heads (first-in-line transaction) // from each of the promoted queues. -func (m *accountsMap) getPrimaries() (primaries []*types.Transaction) { +func (m *accountsMap) getPrimaries(baseFee uint64) (primaries []*types.Transaction) { m.Range(func(key, value interface{}) bool { addressKey, ok := key.(types.Address) if !ok { @@ -57,7 +58,7 @@ func (m *accountsMap) getPrimaries() (primaries []*types.Transaction) { defer account.promoted.unlock() // add head of the queue - if tx := account.promoted.peek(); tx != nil { + if tx := account.promoted.peek(); tx != nil && tx.GetGasFeeCap().Cmp(new(big.Int).SetUint64(baseFee)) >= 0 { primaries = append(primaries, tx) } diff --git a/txpool/txpool.go b/txpool/txpool.go index 8db3883c95..9a6c6dc7fd 100644 --- a/txpool/txpool.go +++ b/txpool/txpool.go @@ -335,18 +335,10 @@ func (p *TxPool) AddTx(tx *types.Transaction) error { // ready for execution. (primaries) func (p *TxPool) Prepare() { // fetch primary from each account - primaries := p.accounts.getPrimaries() - - var eligiblePrimaries []*types.Transaction - - for _, tx := range primaries { - if tx.GetGasFeeCap().Cmp(new(big.Int).SetUint64(p.GetBaseFee())) >= 0 { - eligiblePrimaries = append(eligiblePrimaries, tx) - } - } + primaries := p.accounts.getPrimaries(p.GetBaseFee()) // create new executables queue with base fee and initial transactions (primaries) - p.executables = newPricesQueue(p.GetBaseFee(), eligiblePrimaries) + p.executables = newPricesQueue(p.GetBaseFee(), primaries) } // Peek returns the best-price selected @@ -393,7 +385,7 @@ func (p *TxPool) Pop(tx *types.Transaction) { p.updatePending(-1) // update executables - if tx := account.promoted.peek(); tx != nil { + if tx := account.promoted.peek(); tx != nil && tx.GetGasFeeCap().Cmp(new(big.Int).SetUint64(p.GetBaseFee())) >= 0 { p.executables.push(tx) } } From a923db91cc0fd1ca7b027fbd28b1f41eea38e702 Mon Sep 17 00:00:00 2001 From: Rachit Sonthalia Date: Thu, 31 Aug 2023 15:21:37 +0530 Subject: [PATCH 08/20] consensus should also have baseFee and gasPrice/gasFeeCap check for legacy and dynamic tx respecitively --- state/executor.go | 45 +++++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/state/executor.go b/state/executor.go index 13d7be53c9..ab2d85f65b 100644 --- a/state/executor.go +++ b/state/executor.go @@ -489,34 +489,33 @@ func (t *Transition) nonceCheck(msg *types.Transaction) error { } // checkDynamicFees checks correctness of the EIP-1559 feature-related fields. -// Basically, makes sure gas tip cap and gas fee cap are good. +// Basically, makes sure gas tip cap and gas fee cap are good for dynamic and legacy transactions func (t *Transition) checkDynamicFees(msg *types.Transaction) error { - if msg.Type != types.DynamicFeeTx { - return nil - } + if msg.Type == types.DynamicFeeTx { - if msg.GasFeeCap.BitLen() == 0 && msg.GasTipCap.BitLen() == 0 { - return nil - } + if msg.GasFeeCap.BitLen() == 0 && msg.GasTipCap.BitLen() == 0 { + return nil + } - if l := msg.GasFeeCap.BitLen(); l > 256 { - return fmt.Errorf("%w: address %v, GasFeeCap bit length: %d", ErrFeeCapVeryHigh, - msg.From.String(), l) - } + if l := msg.GasFeeCap.BitLen(); l > 256 { + return fmt.Errorf("%w: address %v, GasFeeCap bit length: %d", ErrFeeCapVeryHigh, + msg.From.String(), l) + } - if l := msg.GasTipCap.BitLen(); l > 256 { - return fmt.Errorf("%w: address %v, GasTipCap bit length: %d", ErrTipVeryHigh, - msg.From.String(), l) - } + if l := msg.GasTipCap.BitLen(); l > 256 { + return fmt.Errorf("%w: address %v, GasTipCap bit length: %d", ErrTipVeryHigh, + msg.From.String(), l) + } - if msg.GasFeeCap.Cmp(msg.GasTipCap) < 0 { - return fmt.Errorf("%w: address %v, GasTipCap: %s, GasFeeCap: %s", ErrTipAboveFeeCap, - msg.From.String(), msg.GasTipCap, msg.GasFeeCap) + if msg.GasFeeCap.Cmp(msg.GasTipCap) < 0 { + return fmt.Errorf("%w: address %v, GasTipCap: %s, GasFeeCap: %s", ErrTipAboveFeeCap, + msg.From.String(), msg.GasTipCap, msg.GasFeeCap) + } } // This will panic if baseFee is nil, but basefee presence is verified // as part of header validation. - if msg.GasFeeCap.Cmp(t.ctx.BaseFee) < 0 { + if msg.GetGasFeeCap().Cmp(t.ctx.BaseFee) < 0 { return fmt.Errorf("%w: address %v, GasFeeCap: %s, BaseFee: %s", ErrFeeCapTooLow, msg.From.String(), msg.GasFeeCap, t.ctx.BaseFee) } @@ -1156,9 +1155,11 @@ func checkAndProcessTx(msg *types.Transaction, t *Transition) error { return NewTransitionApplicationError(err, true) } - // 2. check dynamic fees of the transaction - if err := t.checkDynamicFees(msg); err != nil { - return NewTransitionApplicationError(err, true) + // 2. check dynamic fees of the transaction when london fork is enabled + if t.config.London { + if err := t.checkDynamicFees(msg); err != nil { + return NewTransitionApplicationError(err, true) + } } // 3. caller has enough balance to cover transaction From 955036ba695c640d7c6fef93107c06ffec03514f Mon Sep 17 00:00:00 2001 From: Rachit Sonthalia Date: Thu, 31 Aug 2023 15:23:49 +0530 Subject: [PATCH 09/20] linter fix --- state/executor.go | 1 - 1 file changed, 1 deletion(-) diff --git a/state/executor.go b/state/executor.go index ab2d85f65b..4db939efb0 100644 --- a/state/executor.go +++ b/state/executor.go @@ -492,7 +492,6 @@ func (t *Transition) nonceCheck(msg *types.Transaction) error { // Basically, makes sure gas tip cap and gas fee cap are good for dynamic and legacy transactions func (t *Transition) checkDynamicFees(msg *types.Transaction) error { if msg.Type == types.DynamicFeeTx { - if msg.GasFeeCap.BitLen() == 0 && msg.GasTipCap.BitLen() == 0 { return nil } From a15f055641ed6f5407e2e6302f6973e5311d24f7 Mon Sep 17 00:00:00 2001 From: Rachit Sonthalia Date: Fri, 1 Sep 2023 00:21:06 +0530 Subject: [PATCH 10/20] cr fix --- txpool/txpool.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/txpool/txpool.go b/txpool/txpool.go index 9a6c6dc7fd..6979c689e4 100644 --- a/txpool/txpool.go +++ b/txpool/txpool.go @@ -334,11 +334,12 @@ func (p *TxPool) AddTx(tx *types.Transaction) error { // Prepare generates all the transactions // ready for execution. (primaries) func (p *TxPool) Prepare() { + baseFee := p.GetBaseFee() // fetch primary from each account - primaries := p.accounts.getPrimaries(p.GetBaseFee()) + primaries := p.accounts.getPrimaries(baseFee) // create new executables queue with base fee and initial transactions (primaries) - p.executables = newPricesQueue(p.GetBaseFee(), primaries) + p.executables = newPricesQueue(baseFee, primaries) } // Peek returns the best-price selected From 7c10ff0b1f59a8a86fac847489e54e7324f871e9 Mon Sep 17 00:00:00 2001 From: Rachit Sonthalia Date: Fri, 1 Sep 2023 23:15:48 +0530 Subject: [PATCH 11/20] don't build executable heap with baseFee --- txpool/account.go | 5 ++--- txpool/txpool.go | 7 +++---- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/txpool/account.go b/txpool/account.go index 44116ebba2..6610a1dcd5 100644 --- a/txpool/account.go +++ b/txpool/account.go @@ -1,7 +1,6 @@ package txpool import ( - "math/big" "sync" "sync/atomic" @@ -45,7 +44,7 @@ func (m *accountsMap) exists(addr types.Address) bool { // getPrimaries collects the heads (first-in-line transaction) // from each of the promoted queues. -func (m *accountsMap) getPrimaries(baseFee uint64) (primaries []*types.Transaction) { +func (m *accountsMap) getPrimaries() (primaries []*types.Transaction) { m.Range(func(key, value interface{}) bool { addressKey, ok := key.(types.Address) if !ok { @@ -58,7 +57,7 @@ func (m *accountsMap) getPrimaries(baseFee uint64) (primaries []*types.Transacti defer account.promoted.unlock() // add head of the queue - if tx := account.promoted.peek(); tx != nil && tx.GetGasFeeCap().Cmp(new(big.Int).SetUint64(baseFee)) >= 0 { + if tx := account.promoted.peek(); tx != nil { primaries = append(primaries, tx) } diff --git a/txpool/txpool.go b/txpool/txpool.go index 6979c689e4..839d999950 100644 --- a/txpool/txpool.go +++ b/txpool/txpool.go @@ -334,12 +334,11 @@ func (p *TxPool) AddTx(tx *types.Transaction) error { // Prepare generates all the transactions // ready for execution. (primaries) func (p *TxPool) Prepare() { - baseFee := p.GetBaseFee() // fetch primary from each account - primaries := p.accounts.getPrimaries(baseFee) + primaries := p.accounts.getPrimaries() // create new executables queue with base fee and initial transactions (primaries) - p.executables = newPricesQueue(baseFee, primaries) + p.executables = newPricesQueue(p.GetBaseFee(), primaries) } // Peek returns the best-price selected @@ -386,7 +385,7 @@ func (p *TxPool) Pop(tx *types.Transaction) { p.updatePending(-1) // update executables - if tx := account.promoted.peek(); tx != nil && tx.GetGasFeeCap().Cmp(new(big.Int).SetUint64(p.GetBaseFee())) >= 0 { + if tx := account.promoted.peek(); tx != nil { p.executables.push(tx) } } From 9fad4121a7168f208b35c78167a642350e0a5a2e Mon Sep 17 00:00:00 2001 From: Rachit Sonthalia Date: Sat, 2 Sep 2023 03:02:46 +0530 Subject: [PATCH 12/20] fixed txpool e2e tests --- e2e-polybft/e2e/txpool_test.go | 23 +++++------------------ 1 file changed, 5 insertions(+), 18 deletions(-) diff --git a/e2e-polybft/e2e/txpool_test.go b/e2e-polybft/e2e/txpool_test.go index d8b5017cd4..6ae23175e0 100644 --- a/e2e-polybft/e2e/txpool_test.go +++ b/e2e-polybft/e2e/txpool_test.go @@ -68,11 +68,8 @@ func TestE2E_TxPool_Transfer(t *testing.T) { txn.MaxFeePerGas = big.NewInt(1000000000) txn.MaxPriorityFeePerGas = big.NewInt(100000000) } else { - gasPrice, err := client.GasPrice() - require.NoError(t, err) - txn.Type = ethgo.TransactionLegacy - txn.GasPrice = gasPrice + txn.GasPrice = ethgo.Gwei(2).Uint64() } sendTransaction(t, client, sender, txn) @@ -115,10 +112,6 @@ func TestE2E_TxPool_Transfer_Linear(t *testing.T) { client := cluster.Servers[0].JSONRPC().Eth() - // estimate gas price - gasPrice, err := client.GasPrice() - require.NoError(t, err) - waitUntilBalancesChanged := func(acct ethgo.Address) error { err := cluster.WaitUntil(30*time.Second, 2*time.Second, func() bool { balance, err := client.GetBalance(acct, ethgo.Latest) @@ -139,7 +132,7 @@ func TestE2E_TxPool_Transfer_Linear(t *testing.T) { txn.MaxPriorityFeePerGas = big.NewInt(100000000) } else { txn.Type = ethgo.TransactionLegacy - txn.GasPrice = gasPrice + txn.GasPrice = ethgo.Gwei(1).Uint64() } } @@ -177,11 +170,8 @@ func TestE2E_TxPool_Transfer_Linear(t *testing.T) { populateTxFees(txn, i-1) // Add remaining fees to finish the cycle - for j := i; j < num; j++ { - copyTxn := txn.Copy() - populateTxFees(copyTxn, j) - txn.Value = txn.Value.Add(txn.Value, txCost(copyTxn)) - } + gasCostTotal := new(big.Int).Mul(txCost(txn), new(big.Int).SetInt64(int64(num-i-1))) + txn.Value = txn.Value.Add(txn.Value, gasCostTotal) sendTransaction(t, client, receivers[i-1], txn) @@ -274,11 +264,8 @@ func TestE2E_TxPool_BroadcastTransactions(t *testing.T) { txn.MaxFeePerGas = big.NewInt(1000000000) txn.MaxPriorityFeePerGas = big.NewInt(100000000) } else { - gasPrice, err := client.GasPrice() - require.NoError(t, err) - txn.Type = ethgo.TransactionLegacy - txn.GasPrice = gasPrice + txn.GasPrice = ethgo.Gwei(2).Uint64() } sendTransaction(t, client, sender, txn) From a83fb02757e8dfa92fb1d0fe4d357a3b6418c49f Mon Sep 17 00:00:00 2001 From: Rachit Sonthalia Date: Sat, 2 Sep 2023 17:06:21 +0530 Subject: [PATCH 13/20] fixed e2e migration test --- e2e-polybft/e2e/migration_test.go | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/e2e-polybft/e2e/migration_test.go b/e2e-polybft/e2e/migration_test.go index 4b8f29e462..caccb2210f 100644 --- a/e2e-polybft/e2e/migration_test.go +++ b/e2e-polybft/e2e/migration_test.go @@ -60,18 +60,20 @@ func TestE2E_Migration(t *testing.T) { //send transaction to user2 sendAmount := ethgo.Gwei(10000) receipt, err := relayer.SendTransaction(ðgo.Transaction{ - From: userAddr, - To: &userAddr2, - Gas: 1000000, - Value: sendAmount, + From: userAddr, + To: &userAddr2, + Gas: 1000000, + Value: sendAmount, + GasPrice: ethgo.Gwei(2).Uint64(), }, userKey) require.NoError(t, err) require.NotNil(t, receipt) receipt, err = relayer.SendTransaction(ðgo.Transaction{ - From: userAddr, - Gas: 1000000, - Input: contractsapi.TestWriteBlockMetadata.Bytecode, + From: userAddr, + Gas: 1000000, + GasPrice: ethgo.Gwei(2).Uint64(), + Input: contractsapi.TestWriteBlockMetadata.Bytecode, }, userKey) require.NoError(t, err) require.NotNil(t, receipt) From e1c3c3b7e5029e574544b14962dfe298002cbe22 Mon Sep 17 00:00:00 2001 From: Rachit Sonthalia Date: Sun, 3 Sep 2023 18:18:39 +0530 Subject: [PATCH 14/20] logic for fork handler --- chain/params.go | 6 +- server/server.go | 5 ++ state/executor.go | 38 ++----------- state/londonFix_fork.go | 119 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 133 insertions(+), 35 deletions(-) create mode 100644 state/londonFix_fork.go diff --git a/chain/params.go b/chain/params.go index 1c2a7729ce..29c4f3a53a 100644 --- a/chain/params.go +++ b/chain/params.go @@ -90,6 +90,7 @@ const ( EIP155 = "EIP155" QuorumCalcAlignment = "quorumcalcalignment" TxHashWithType = "txHashWithType" + LondonFix = "londonfix" ) // Forks is map which contains all forks and their starting blocks from genesis @@ -125,6 +126,7 @@ func (f *Forks) At(block uint64) ForksInTime { EIP155: f.IsActive(EIP155, block), QuorumCalcAlignment: f.IsActive(QuorumCalcAlignment, block), TxHashWithType: f.IsActive(TxHashWithType, block), + LondonFix: f.IsActive(LondonFix, block), } } @@ -153,7 +155,8 @@ type ForksInTime struct { EIP158, EIP155, QuorumCalcAlignment, - TxHashWithType bool + TxHashWithType, + LondonFix bool } // AllForksEnabled should contain all supported forks by current edge version @@ -169,4 +172,5 @@ var AllForksEnabled = &Forks{ London: NewFork(0), QuorumCalcAlignment: NewFork(0), TxHashWithType: NewFork(0), + LondonFix: NewFork(0), } diff --git a/server/server.go b/server/server.go index 7b4bb42a99..736a337b1a 100644 --- a/server/server.go +++ b/server/server.go @@ -1044,6 +1044,11 @@ func initForkManager(engineName string, config *chain.Chain) error { return err } + // Register Handler for London fork fix + if err := state.RegisterLondonFixFork(chain.LondonFix); err != nil { + return err + } + if factory := forkManagerFactory[ConsensusType(engineName)]; factory != nil { if err := factory(config.Params.Forks); err != nil { return err diff --git a/state/executor.go b/state/executor.go index 4db939efb0..d6d3b240c5 100644 --- a/state/executor.go +++ b/state/executor.go @@ -491,35 +491,7 @@ func (t *Transition) nonceCheck(msg *types.Transaction) error { // checkDynamicFees checks correctness of the EIP-1559 feature-related fields. // Basically, makes sure gas tip cap and gas fee cap are good for dynamic and legacy transactions func (t *Transition) checkDynamicFees(msg *types.Transaction) error { - if msg.Type == types.DynamicFeeTx { - if msg.GasFeeCap.BitLen() == 0 && msg.GasTipCap.BitLen() == 0 { - return nil - } - - if l := msg.GasFeeCap.BitLen(); l > 256 { - return fmt.Errorf("%w: address %v, GasFeeCap bit length: %d", ErrFeeCapVeryHigh, - msg.From.String(), l) - } - - if l := msg.GasTipCap.BitLen(); l > 256 { - return fmt.Errorf("%w: address %v, GasTipCap bit length: %d", ErrTipVeryHigh, - msg.From.String(), l) - } - - if msg.GasFeeCap.Cmp(msg.GasTipCap) < 0 { - return fmt.Errorf("%w: address %v, GasTipCap: %s, GasFeeCap: %s", ErrTipAboveFeeCap, - msg.From.String(), msg.GasTipCap, msg.GasFeeCap) - } - } - - // This will panic if baseFee is nil, but basefee presence is verified - // as part of header validation. - if msg.GetGasFeeCap().Cmp(t.ctx.BaseFee) < 0 { - return fmt.Errorf("%w: address %v, GasFeeCap: %s, BaseFee: %s", ErrFeeCapTooLow, - msg.From.String(), msg.GasFeeCap, t.ctx.BaseFee) - } - - return nil + return GetLondonFixHandler(uint64(t.ctx.Number)).checkDynamicFees(msg, t) } // errors that can originate in the consensus rules checks of the apply method below @@ -1154,11 +1126,9 @@ func checkAndProcessTx(msg *types.Transaction, t *Transition) error { return NewTransitionApplicationError(err, true) } - // 2. check dynamic fees of the transaction when london fork is enabled - if t.config.London { - if err := t.checkDynamicFees(msg); err != nil { - return NewTransitionApplicationError(err, true) - } + // 2. check dynamic fees of the transaction + if err := t.checkDynamicFees(msg); err != nil { + return NewTransitionApplicationError(err, true) } // 3. caller has enough balance to cover transaction diff --git a/state/londonFix_fork.go b/state/londonFix_fork.go new file mode 100644 index 0000000000..448a62e8a9 --- /dev/null +++ b/state/londonFix_fork.go @@ -0,0 +1,119 @@ +package state + +import ( + "fmt" + + "github.com/0xPolygon/polygon-edge/forkmanager" + "github.com/0xPolygon/polygon-edge/types" +) + +const LondonFixHandler forkmanager.HandlerDesc = "LondonFixHandler" + +type LondonFixFork interface { + checkDynamicFees(*types.Transaction, *Transition) error +} + +type LondonFixForkV1 struct{} + +// checkDynamicFees checks correctness of the EIP-1559 feature-related fields. +// Basically, makes sure gas tip cap and gas fee cap are good for dynamic and legacy transactions +// and that GasFeeCap/GasPrice cap is not lower than base fee when London fork is active. +func (l *LondonFixForkV1) checkDynamicFees(msg *types.Transaction, t *Transition) error { + if msg.Type != types.DynamicFeeTx { + return nil + } + + if msg.GasFeeCap.BitLen() == 0 && msg.GasTipCap.BitLen() == 0 { + return nil + } + + if l := msg.GasFeeCap.BitLen(); l > 256 { + return fmt.Errorf("%w: address %v, GasFeeCap bit length: %d", ErrFeeCapVeryHigh, + msg.From.String(), l) + } + + if l := msg.GasTipCap.BitLen(); l > 256 { + return fmt.Errorf("%w: address %v, GasTipCap bit length: %d", ErrTipVeryHigh, + msg.From.String(), l) + } + + if msg.GasFeeCap.Cmp(msg.GasTipCap) < 0 { + return fmt.Errorf("%w: address %v, GasTipCap: %s, GasFeeCap: %s", ErrTipAboveFeeCap, + msg.From.String(), msg.GasTipCap, msg.GasFeeCap) + } + + // This will panic if baseFee is nil, but basefee presence is verified + // as part of header validation. + if msg.GasFeeCap.Cmp(t.ctx.BaseFee) < 0 { + return fmt.Errorf("%w: address %v, GasFeeCap: %s, BaseFee: %s", ErrFeeCapTooLow, + msg.From.String(), msg.GasFeeCap, t.ctx.BaseFee) + } + + return nil + +} + +type LondonFixForkV2 struct{} + +func (l *LondonFixForkV2) checkDynamicFees(msg *types.Transaction, t *Transition) error { + if !t.config.London { + return nil + } + + if msg.Type == types.DynamicFeeTx { + if msg.GasFeeCap.BitLen() == 0 && msg.GasTipCap.BitLen() == 0 { + return nil + } + + if l := msg.GasFeeCap.BitLen(); l > 256 { + return fmt.Errorf("%w: address %v, GasFeeCap bit length: %d", ErrFeeCapVeryHigh, + msg.From.String(), l) + } + + if l := msg.GasTipCap.BitLen(); l > 256 { + return fmt.Errorf("%w: address %v, GasTipCap bit length: %d", ErrTipVeryHigh, + msg.From.String(), l) + } + + if msg.GasFeeCap.Cmp(msg.GasTipCap) < 0 { + return fmt.Errorf("%w: address %v, GasTipCap: %s, GasFeeCap: %s", ErrTipAboveFeeCap, + msg.From.String(), msg.GasTipCap, msg.GasFeeCap) + } + } + + // This will panic if baseFee is nil, but basefee presence is verified + // as part of header validation. + if msg.GetGasFeeCap().Cmp(t.ctx.BaseFee) < 0 { + return fmt.Errorf("%w: address %v, GasFeeCap: %s, BaseFee: %s", ErrFeeCapTooLow, + msg.From.String(), msg.GasFeeCap, t.ctx.BaseFee) + } + + return nil +} + +func RegisterLondonFixFork(londonFixFork string) error { + fh := forkmanager.GetInstance() + + if err := fh.RegisterHandler( + forkmanager.InitialFork, LondonFixHandler, &LondonFixForkV1{}); err != nil { + return err + } + + if fh.IsForkRegistered(londonFixFork) { + if err := fh.RegisterHandler( + londonFixFork, LondonFixHandler, &LondonFixForkV2{}); err != nil { + return err + } + } + + return nil +} + +func GetLondonFixHandler(blockNumber uint64) LondonFixFork { + if h := forkmanager.GetInstance().GetHandler(LondonFixHandler, blockNumber); h != nil { + //nolint:forcetypeassert + return h.(LondonFixFork) + } + + return nil +} From 0f94a42330ec8de8d42d0967cc4e36144b3b02b5 Mon Sep 17 00:00:00 2001 From: Rachit Sonthalia Date: Sun, 3 Sep 2023 18:19:57 +0530 Subject: [PATCH 15/20] fix linting --- state/londonFix_fork.go | 1 - 1 file changed, 1 deletion(-) diff --git a/state/londonFix_fork.go b/state/londonFix_fork.go index 448a62e8a9..63bdd62606 100644 --- a/state/londonFix_fork.go +++ b/state/londonFix_fork.go @@ -50,7 +50,6 @@ func (l *LondonFixForkV1) checkDynamicFees(msg *types.Transaction, t *Transition } return nil - } type LondonFixForkV2 struct{} From 73ff41f723c1be29aee715260111341b043800c6 Mon Sep 17 00:00:00 2001 From: Rachit Sonthalia Date: Sun, 3 Sep 2023 21:09:58 +0530 Subject: [PATCH 16/20] fix unit test --- state/londonFix_fork.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/state/londonFix_fork.go b/state/londonFix_fork.go index 63bdd62606..1f6772d3d3 100644 --- a/state/londonFix_fork.go +++ b/state/londonFix_fork.go @@ -114,5 +114,6 @@ func GetLondonFixHandler(blockNumber uint64) LondonFixFork { return h.(LondonFixFork) } - return nil + // for tests + return &LondonFixForkV1{} } From 8b1d992b259869f5ca95618f32be3b75ae95cf9f Mon Sep 17 00:00:00 2001 From: Rachit Sonthalia Date: Mon, 4 Sep 2023 02:11:07 +0530 Subject: [PATCH 17/20] added hard fork logic for PR #1849 --- state/executor.go | 9 ++++----- state/londonFix_fork.go | 45 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 5 deletions(-) diff --git a/state/executor.go b/state/executor.go index aa2c97af0b..539ee64443 100644 --- a/state/executor.go +++ b/state/executor.go @@ -453,7 +453,7 @@ func (t *Transition) ContextPtr() *runtime.TxContext { } func (t *Transition) subGasLimitPrice(msg *types.Transaction) error { - upfrontGasCost := new(big.Int).Mul(new(big.Int).SetUint64(msg.Gas), msg.GetGasPrice(t.ctx.BaseFee.Uint64())) + upfrontGasCost := GetLondonFixHandler(uint64(t.ctx.Number)).getUpfrontGasCost(msg, t.ctx.BaseFee) if err := t.state.SubBalance(msg.From, upfrontGasCost); err != nil { if errors.Is(err, runtime.ErrNotEnoughFunds) { @@ -600,10 +600,9 @@ func (t *Transition) apply(msg *types.Transaction) (*runtime.ExecutionResult, er // Define effective tip based on tx type. // We use EIP-1559 fields of the tx if the london hardfork is enabled. // Effective tip became to be either gas tip cap or (gas fee cap - current base fee) - effectiveTip := new(big.Int).Set(gasPrice) - if t.config.London { - effectiveTip = msg.EffectiveGasTip(t.ctx.BaseFee) - } + effectiveTip := GetLondonFixHandler(uint64(t.ctx.Number)).getEffectiveTip( + msg, gasPrice, t.ctx.BaseFee, t.config.London, + ) // Pay the coinbase fee as a miner reward using the calculated effective tip. coinbaseFee := new(big.Int).Mul(new(big.Int).SetUint64(result.GasUsed), effectiveTip) diff --git a/state/londonFix_fork.go b/state/londonFix_fork.go index 1f6772d3d3..e896a2fe39 100644 --- a/state/londonFix_fork.go +++ b/state/londonFix_fork.go @@ -2,8 +2,10 @@ package state import ( "fmt" + "math/big" "github.com/0xPolygon/polygon-edge/forkmanager" + "github.com/0xPolygon/polygon-edge/helper/common" "github.com/0xPolygon/polygon-edge/types" ) @@ -11,6 +13,9 @@ const LondonFixHandler forkmanager.HandlerDesc = "LondonFixHandler" type LondonFixFork interface { checkDynamicFees(*types.Transaction, *Transition) error + getUpfrontGasCost(msg *types.Transaction, baseFee *big.Int) *big.Int + getEffectiveTip(msg *types.Transaction, gasPrice *big.Int, + baseFee *big.Int, isLondonForkEnabled bool) *big.Int } type LondonFixForkV1 struct{} @@ -52,6 +57,33 @@ func (l *LondonFixForkV1) checkDynamicFees(msg *types.Transaction, t *Transition return nil } +func (l *LondonFixForkV1) getUpfrontGasCost(msg *types.Transaction, baseFee *big.Int) *big.Int { + upfrontGasCost := new(big.Int).SetUint64(msg.Gas) + + factor := new(big.Int) + if msg.GasFeeCap != nil && msg.GasFeeCap.BitLen() > 0 { + // Apply EIP-1559 tx cost calculation factor + factor = factor.Set(msg.GasFeeCap) + } else { + // Apply legacy tx cost calculation factor + factor = factor.Set(msg.GasPrice) + } + + return upfrontGasCost.Mul(upfrontGasCost, factor) +} + +func (l *LondonFixForkV1) getEffectiveTip(msg *types.Transaction, gasPrice *big.Int, + baseFee *big.Int, isLondonForkEnabled bool) *big.Int { + if isLondonForkEnabled && msg.Type == types.DynamicFeeTx { + return common.BigMin( + new(big.Int).Sub(msg.GasFeeCap, baseFee), + new(big.Int).Set(msg.GasTipCap), + ) + } + + return new(big.Int).Set(gasPrice) +} + type LondonFixForkV2 struct{} func (l *LondonFixForkV2) checkDynamicFees(msg *types.Transaction, t *Transition) error { @@ -90,6 +122,19 @@ func (l *LondonFixForkV2) checkDynamicFees(msg *types.Transaction, t *Transition return nil } +func (l *LondonFixForkV2) getUpfrontGasCost(msg *types.Transaction, baseFee *big.Int) *big.Int { + return new(big.Int).Mul(new(big.Int).SetUint64(msg.Gas), msg.GetGasPrice(baseFee.Uint64())) +} + +func (l *LondonFixForkV2) getEffectiveTip(msg *types.Transaction, gasPrice *big.Int, + baseFee *big.Int, isLondonForkEnabled bool) *big.Int { + if isLondonForkEnabled { + return msg.EffectiveGasTip(baseFee) + } + + return new(big.Int).Set(gasPrice) +} + func RegisterLondonFixFork(londonFixFork string) error { fh := forkmanager.GetInstance() From 975bd6bb868cdcb13859c1b5d2aef4342d01d6be Mon Sep 17 00:00:00 2001 From: Rachit Sonthalia Date: Tue, 5 Sep 2023 12:56:41 +0530 Subject: [PATCH 18/20] fixed TestE2E_TxPool_Transfer_Linear --- e2e-polybft/e2e/txpool_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e-polybft/e2e/txpool_test.go b/e2e-polybft/e2e/txpool_test.go index 6ae23175e0..fba7b5314b 100644 --- a/e2e-polybft/e2e/txpool_test.go +++ b/e2e-polybft/e2e/txpool_test.go @@ -129,7 +129,7 @@ func TestE2E_TxPool_Transfer_Linear(t *testing.T) { if i%2 == 0 { txn.Type = ethgo.TransactionDynamicFee txn.MaxFeePerGas = big.NewInt(1000000000) - txn.MaxPriorityFeePerGas = big.NewInt(100000000) + txn.MaxPriorityFeePerGas = big.NewInt(1000000000) } else { txn.Type = ethgo.TransactionLegacy txn.GasPrice = ethgo.Gwei(1).Uint64() From c64e13fe3ae34031801fbd5c40fe505fd7245bef Mon Sep 17 00:00:00 2001 From: Rachit Sonthalia Date: Tue, 5 Sep 2023 17:59:12 +0530 Subject: [PATCH 19/20] added e2e test case for EIP-1559 spec --- e2e-polybft/e2e/consensus_test.go | 120 ++++++++++++++++++++++++++++++ state/londonFix_fork.go | 2 +- 2 files changed, 121 insertions(+), 1 deletion(-) diff --git a/e2e-polybft/e2e/consensus_test.go b/e2e-polybft/e2e/consensus_test.go index 98863cbc23..cb7a409e0c 100644 --- a/e2e-polybft/e2e/consensus_test.go +++ b/e2e-polybft/e2e/consensus_test.go @@ -8,6 +8,7 @@ import ( "testing" "time" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/umbracle/ethgo" "github.com/umbracle/ethgo/abi" @@ -618,3 +619,122 @@ func TestE2E_Consensus_CustomRewardToken(t *testing.T) { require.NoError(t, err) require.True(t, validatorInfo.WithdrawableRewards.Cmp(big.NewInt(0)) > 0) } + +// TestE2E_Consensus_EIP1559Check sends a legacy and a dynamic tx to the cluster +// and check if balance of sender, receiver, burn contract and miner is updates correctly +// in accordance with EIP-1559 specifications +func TestE2E_Consensus_EIP1559Check(t *testing.T) { + sender1, err := wallet.GenerateKey() + require.NoError(t, err) + + sender2, err := wallet.GenerateKey() + require.NoError(t, err) + + recipientKey, err := wallet.GenerateKey() + require.NoError(t, err) + + recipient := recipientKey.Address() + + // first account should have some matics premined + cluster := framework.NewTestCluster(t, 5, + framework.WithNativeTokenConfig(fmt.Sprintf(nativeTokenMintableTestCfg, sender1.Address())), + framework.WithPremine(types.Address(sender1.Address()), types.Address(sender2.Address())), + framework.WithBurnContract(&polybft.BurnContractInfo{BlockNumber: 0, Address: types.ZeroAddress}), + ) + defer cluster.Stop() + + cluster.WaitForReady(t) + + client := cluster.Servers[0].JSONRPC().Eth() + + waitUntilBalancesChanged := func(acct ethgo.Address, bal *big.Int) error { + err := cluster.WaitUntil(30*time.Second, 2*time.Second, func() bool { + balance, err := client.GetBalance(recipient, ethgo.Latest) + if err != nil { + return true + } + + return balance.Cmp(bal) > 0 + }) + + return err + } + + relayer, err := txrelayer.NewTxRelayer(txrelayer.WithIPAddress(cluster.Servers[0].JSONRPCAddr())) + require.NoError(t, err) + + // create and send tx + sendAmount := ethgo.Gwei(1) + + txn := []*ethgo.Transaction{ + { + Value: sendAmount, + To: &recipient, + Gas: 21000, + Nonce: uint64(0), + GasPrice: ethgo.Gwei(1).Uint64(), + }, + { + Value: sendAmount, + To: &recipient, + Gas: 21000, + Nonce: uint64(0), + Type: ethgo.TransactionDynamicFee, + MaxFeePerGas: ethgo.Gwei(1), + MaxPriorityFeePerGas: ethgo.Gwei(1), + }, + } + + initialMinerBalance := big.NewInt(0) + + var prevMiner ethgo.Address + + for i := 0; i < 2; i++ { + curTxn := txn[i] + + senderInitialBalance, _ := client.GetBalance(sender1.Address(), ethgo.Latest) + receiverInitialBalance, _ := client.GetBalance(recipient, ethgo.Latest) + burnContractInitialBalance, _ := client.GetBalance(ethgo.Address(types.ZeroAddress), ethgo.Latest) + + receipt, err := relayer.SendTransaction(curTxn, sender1) + require.NoError(t, err) + + // wait for balance to get changed + err = waitUntilBalancesChanged(recipient, receiverInitialBalance) + require.NoError(t, err) + + // Retrieve the transaction receipt + txReceipt, err := client.GetTransactionByHash(receipt.TransactionHash) + require.NoError(t, err) + + block, _ := client.GetBlockByHash(txReceipt.BlockHash, true) + finalMinerFinalBalance, _ := client.GetBalance(block.Miner, ethgo.Latest) + + if i == 0 { + prevMiner = block.Miner + } + + senderFinalBalance, _ := client.GetBalance(sender1.Address(), ethgo.Latest) + receiverFinalBalance, _ := client.GetBalance(recipient, ethgo.Latest) + burnContractFinalBalance, _ := client.GetBalance(ethgo.Address(types.ZeroAddress), ethgo.Latest) + + diffReciverBalance := new(big.Int).Sub(receiverFinalBalance, receiverInitialBalance) + assert.Equal(t, sendAmount, diffReciverBalance, "Receiver balance should be increased by send amount") + + if i == 1 && prevMiner != block.Miner { + initialMinerBalance = big.NewInt(0) + } + + diffBurnContractBalance := new(big.Int).Sub(burnContractFinalBalance, burnContractInitialBalance) + diffSenderBalance := new(big.Int).Sub(senderInitialBalance, senderFinalBalance) + diffMinerBalance := new(big.Int).Sub(finalMinerFinalBalance, initialMinerBalance) + + diffSenderBalance.Sub(diffSenderBalance, diffReciverBalance) + diffSenderBalance.Sub(diffSenderBalance, diffBurnContractBalance) + diffSenderBalance.Sub(diffSenderBalance, diffMinerBalance) + + assert.Zero(t, diffSenderBalance.Int64(), "Sender balance should be decreased by send amount + gas") + + initialMinerBalance = finalMinerFinalBalance + } +} diff --git a/state/londonFix_fork.go b/state/londonFix_fork.go index e896a2fe39..9f296a75d0 100644 --- a/state/londonFix_fork.go +++ b/state/londonFix_fork.go @@ -160,5 +160,5 @@ func GetLondonFixHandler(blockNumber uint64) LondonFixFork { } // for tests - return &LondonFixForkV1{} + return &LondonFixForkV2{} } From 3339738f16537e0d84d906b5db9b4339812ec5e2 Mon Sep 17 00:00:00 2001 From: Rachit Sonthalia Date: Tue, 5 Sep 2023 18:34:42 +0530 Subject: [PATCH 20/20] fix Test_Transition_checkDynamicFees --- state/executor_test.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/state/executor_test.go b/state/executor_test.go index 79ae3c96e3..161e29363b 100644 --- a/state/executor_test.go +++ b/state/executor_test.go @@ -147,6 +147,9 @@ func Test_Transition_checkDynamicFees(t *testing.T) { ctx: runtime.TxContext{ BaseFee: tt.baseFee, }, + config: chain.ForksInTime{ + London: true, + }, } err := tr.checkDynamicFees(tt.tx)