From 71388bb0b065b0de2c5a8fb00d11b19a4c851bac Mon Sep 17 00:00:00 2001 From: Rafal Leszko Date: Tue, 8 Feb 2022 11:21:51 +0100 Subject: [PATCH] eth: Make transaction replacement compatible with Arbitrum --- eth/transactionManager.go | 46 +++++++++++++++++++++++----------- eth/transactionManager_test.go | 41 +++++++++++++++++++++++++++--- 2 files changed, 69 insertions(+), 18 deletions(-) diff --git a/eth/transactionManager.go b/eth/transactionManager.go index 17e30f2293..cf3f3cf9b1 100644 --- a/eth/transactionManager.go +++ b/eth/transactionManager.go @@ -175,9 +175,9 @@ func (tm *TransactionManager) replace(tx *types.Transaction) (*types.Transaction txLog.method = "unknown" } if sendErr != nil { - glog.Infof("\n%vEth Transaction%v\n\nReplacement transaction: \"%v\". Priority Fee: %v Max Fee: %v \nTransaction Failed: %v\n\n%v\n", strings.Repeat("*", 30), strings.Repeat("*", 30), txLog.method, newSignedTx.GasTipCap().String(), newSignedTx.GasFeeCap().String(), sendErr, strings.Repeat("*", 75)) + glog.Infof("\n%vEth Transaction%v\n\nReplacement transaction: \"%v\". \nTransaction Failed: %v\n\n%v\n", strings.Repeat("*", 30), strings.Repeat("*", 30), txLog.method, sendErr, strings.Repeat("*", 75)) } else { - glog.Infof("\n%vEth Transaction%v\n\nReplacement transaction: \"%v\". Hash: \"%v\". Priority Fee: %v Max Fee: %v \n\n%v\n", strings.Repeat("*", 30), strings.Repeat("*", 30), txLog.method, newSignedTx.Hash().String(), newSignedTx.GasTipCap().String(), newSignedTx.GasFeeCap().String(), strings.Repeat("*", 75)) + glog.Infof("\n%vEth Transaction%v\n\nReplacement transaction: \"%v\". Hash: \"%v\". \n\n%v\n", strings.Repeat("*", 30), strings.Repeat("*", 30), txLog.method, newSignedTx.Hash().String(), strings.Repeat("*", 75)) } return newSignedTx, sendErr @@ -243,21 +243,39 @@ func applyPriceBump(val *big.Int, priceBump uint64) *big.Int { // Calculate the gas price as gas tip cap + base fee func calcGasPrice(tx *types.Transaction) *big.Int { - // Assume that the gas fee cap is calculated as gas tip cap + (baseFee * 2) - baseFee := new(big.Int).Div(new(big.Int).Sub(tx.GasFeeCap(), tx.GasTipCap()), big.NewInt(2)) - return new(big.Int).Add(baseFee, tx.GasTipCap()) + if tx.GasFeeCap() == nil { + // legacy tx, not London ready + return tx.GasPrice() + } else { + // Assume that the gas fee cap is calculated as gas tip cap + (baseFee * 2) + baseFee := new(big.Int).Div(new(big.Int).Sub(tx.GasFeeCap(), tx.GasTipCap()), big.NewInt(2)) + return new(big.Int).Add(baseFee, tx.GasTipCap()) + } } func newReplacementTx(tx *types.Transaction) *types.Transaction { - baseTx := &types.DynamicFeeTx{ - Nonce: tx.Nonce(), - // geth requires the price bump to be applied to both the gas tip cap and gas fee cap - GasFeeCap: applyPriceBump(tx.GasFeeCap(), priceBump), - GasTipCap: applyPriceBump(tx.GasTipCap(), priceBump), - Gas: tx.Gas(), - Value: tx.Value(), - Data: tx.Data(), - To: tx.To(), + var baseTx types.TxData + if tx.GasFeeCap() == nil { + // legacy tx, not London ready + baseTx = &types.LegacyTx{ + Nonce: tx.Nonce(), + GasPrice: applyPriceBump(tx.GasPrice(), priceBump), + Gas: tx.Gas(), + To: tx.To(), + Value: tx.Value(), + Data: tx.Data(), + } + } else { + baseTx = &types.DynamicFeeTx{ + Nonce: tx.Nonce(), + // geth requires the price bump to be applied to both the gas tip cap and gas fee cap + GasFeeCap: applyPriceBump(tx.GasFeeCap(), priceBump), + GasTipCap: applyPriceBump(tx.GasTipCap(), priceBump), + Gas: tx.Gas(), + Value: tx.Value(), + Data: tx.Data(), + To: tx.To(), + } } return types.NewTx(baseTx) diff --git a/eth/transactionManager_test.go b/eth/transactionManager_test.go index 1c1a32a71d..b70024844c 100644 --- a/eth/transactionManager_test.go +++ b/eth/transactionManager_test.go @@ -394,16 +394,37 @@ func TestApplyPriceBump(t *testing.T) { func TestCalcGasPrice(t *testing.T) { assert := assert.New(t) + // legacy tx, not London ready + gasPrice := big.NewInt(300) + tx := newStubLegacyTx(gasPrice) + result := calcGasPrice(tx) + assert.Equal(gasPrice, result) + + // dynamic tx baseFee := big.NewInt(1000) gasTipCap := big.NewInt(100) gasFeeCap := new(big.Int).Add(gasTipCap, new(big.Int).Mul(baseFee, big.NewInt(2))) - tx := newStubDynamicFeeTx(gasFeeCap, gasTipCap) + tx = newStubDynamicFeeTx(gasFeeCap, gasTipCap) + result = calcGasPrice(tx) + assert.Equal(new(big.Int).Add(baseFee, gasTipCap), result) +} + +func TestNewReplacementTx_LegacyTx(t *testing.T) { + assert := assert.New(t) - gasPrice := calcGasPrice(tx) - assert.Equal(new(big.Int).Add(baseFee, gasTipCap), gasPrice) + gasPrice := big.NewInt(100) + + tx1 := newStubLegacyTx(gasPrice) + tx2 := newReplacementTx(tx1) + assert.NotEqual(tx1.Hash(), tx2.Hash()) + assert.Equal(applyPriceBump(tx1.GasPrice(), priceBump), tx2.GasPrice()) + assert.Equal(tx1.Nonce(), tx2.Nonce()) + assert.Equal(tx1.Gas(), tx2.Gas()) + assert.Equal(tx1.Value(), tx1.Value()) + assert.Equal(tx1.To(), tx2.To()) } -func TestNewReplacementTx(t *testing.T) { +func TestNewReplacementTx_DynamicFeeTx(t *testing.T) { assert := assert.New(t) gasTipCap := big.NewInt(100) @@ -420,6 +441,18 @@ func TestNewReplacementTx(t *testing.T) { assert.Equal(tx1.To(), tx2.To()) } +func newStubLegacyTx(gasPrice *big.Int) *types.Transaction { + addr := pm.RandAddress() + return types.NewTx(&types.LegacyTx{ + Nonce: 1, + GasPrice: gasPrice, + Gas: 1000000, + Value: big.NewInt(100), + Data: pm.RandBytes(68), + To: &addr, + }) +} + func newStubDynamicFeeTx(gasFeeCap, gasTipCap *big.Int) *types.Transaction { addr := pm.RandAddress() return types.NewTx(&types.DynamicFeeTx{