Skip to content

Commit

Permalink
eth: Make transaction replacement compatible with Arbitrum
Browse files Browse the repository at this point in the history
  • Loading branch information
leszko committed Feb 9, 2022
1 parent c0f194a commit 71388bb
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 18 deletions.
46 changes: 32 additions & 14 deletions eth/transactionManager.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down
41 changes: 37 additions & 4 deletions eth/transactionManager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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{
Expand Down

0 comments on commit 71388bb

Please sign in to comment.