Skip to content

Commit 4a78fde

Browse files
susannapaxosblakehhuynh
authored andcommitted
add market gas price to simulate duplicate nonce behavior (paxosglobal#7)
1 parent 7f7e6be commit 4a78fde

File tree

2 files changed

+200
-0
lines changed

2 files changed

+200
-0
lines changed

accounts/abi/bind/backends/simulated.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -726,6 +726,8 @@ func (b *SimulatedBackend) SendTransaction(ctx context.Context, tx *types.Transa
726726
b.stuckTransactions = remainingTxes
727727

728728
b.pendingReceipts = receipts[0]
729+
b.stuckTransactions = remainingTxes
730+
729731
return nil
730732
}
731733

accounts/abi/bind/backends/simulated_test.go

Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1597,3 +1597,201 @@ func TestAdjustTimeAfterFork(t *testing.T) {
15971597
t.Errorf("failed to build block on fork")
15981598
}
15991599
}
1600+
1601+
// TestLowGasTxNotBeingMined checks that the lower gas fee tx with same nonce does not get mined
1602+
// Steps:
1603+
// 1. Send a tx lower than the set market gas price
1604+
// 2. Commit to chain, check nonce stays the same
1605+
// 3. Send a tx meets the market gas price with same nonce.
1606+
// 4. Commit to chain
1607+
// 5. Check tx2 is not in pending state and nonce has increased
1608+
func TestLowGasTxNotBeingMined(t *testing.T) {
1609+
testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
1610+
var gas uint64 = 21000
1611+
1612+
sim := simTestBackend(testAddr)
1613+
defer sim.Close()
1614+
1615+
var testCases = []struct {
1616+
name string
1617+
txType byte
1618+
}{
1619+
{
1620+
name: "LegacyTx",
1621+
txType: types.LegacyTxType,
1622+
},
1623+
{
1624+
name: "dynamicTx",
1625+
txType: types.DynamicFeeTxType,
1626+
},
1627+
}
1628+
for i, test := range testCases {
1629+
t.Run(test.name, func(t *testing.T) {
1630+
bgCtx := context.Background()
1631+
// Create tx and send
1632+
head, _ := sim.HeaderByNumber(context.Background(), nil)
1633+
tip, err := sim.SuggestGasTipCap(bgCtx)
1634+
require.NoError(t, err)
1635+
gasPrice := new(big.Int).Add(head.BaseFee, tip)
1636+
sim.SetMarketGasPrice(int64(gasPrice.Uint64()))
1637+
1638+
lowFeeGas := new(big.Int).Sub(gasPrice, tip)
1639+
txValue := big.NewInt(1)
1640+
1641+
var lowGasFeeTx *types.Transaction
1642+
1643+
if test.txType == types.LegacyTxType {
1644+
lowGasFeeTx = types.NewTx(&types.LegacyTx{
1645+
Nonce: uint64(i),
1646+
To: &testAddr,
1647+
Value: txValue,
1648+
GasPrice: lowFeeGas,
1649+
Gas: gas,
1650+
})
1651+
} else if test.txType == types.DynamicFeeTxType {
1652+
lowGasFeeTx = types.NewTx(&types.DynamicFeeTx{
1653+
Nonce: uint64(i),
1654+
Gas: gas,
1655+
To: &testAddr,
1656+
Value: txValue,
1657+
GasTipCap: lowFeeGas,
1658+
GasFeeCap: lowFeeGas,
1659+
})
1660+
} else {
1661+
t.Fatal("unexpected txType received")
1662+
}
1663+
1664+
signedTx, err := types.SignTx(lowGasFeeTx, types.LatestSigner(sim.config), testKey)
1665+
require.NoError(t, err)
1666+
1667+
// send tx to simulated backend
1668+
err = sim.SendTransaction(bgCtx, signedTx)
1669+
require.NoError(t, err)
1670+
sim.Commit()
1671+
1672+
// expect nonce be the same because low gas fee tx will not be mined
1673+
nonce, err := sim.PendingNonceAt(bgCtx, testAddr)
1674+
require.NoError(t, err)
1675+
assert.Equal(t, uint64(i), nonce)
1676+
1677+
// send tx with higher gas fee
1678+
sufficientGasFeeTx := types.NewTx(&types.LegacyTx{
1679+
Nonce: uint64(i),
1680+
To: &testAddr,
1681+
Value: txValue,
1682+
GasPrice: gasPrice,
1683+
Gas: gas,
1684+
})
1685+
1686+
signedSufficientTx, err := types.SignTx(sufficientGasFeeTx, types.HomesteadSigner{}, testKey)
1687+
require.NoError(t, err)
1688+
1689+
err = sim.SendTransaction(bgCtx, signedSufficientTx)
1690+
require.NoError(t, err)
1691+
sim.Commit()
1692+
1693+
// the higher gas transaction should have been mined
1694+
_, isPending, err := sim.TransactionByHash(bgCtx, signedSufficientTx.Hash())
1695+
require.NoError(t, err)
1696+
assert.False(t, isPending)
1697+
1698+
// expect nonce has increased
1699+
nonce, err = sim.PendingNonceAt(bgCtx, testAddr)
1700+
require.NoError(t, err)
1701+
assert.Equal(t, uint64(i)+1, nonce)
1702+
})
1703+
}
1704+
}
1705+
1706+
// TestLowGasTxGetMinedOnceGasFeeDropped checks that lower gas fee txes still stay in mem pool
1707+
// and get mined once gas fee requirement has been met
1708+
// Steps:
1709+
// 1. Send a tx lower than the set market gas price
1710+
// 2. Commit to chain, tx does not get mined
1711+
// 3. Gas fee drops, commit again
1712+
// 4. Check tx get mined
1713+
func TestLowGasTxGetMinedOnceGasFeeDropped(t *testing.T) {
1714+
var testCases = []struct {
1715+
name string
1716+
txType byte
1717+
}{
1718+
{
1719+
name: "LegacyTx",
1720+
txType: types.LegacyTxType,
1721+
},
1722+
{
1723+
name: "dynamicTx",
1724+
txType: types.DynamicFeeTxType,
1725+
},
1726+
}
1727+
testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
1728+
var gas uint64 = 21000
1729+
1730+
sim := simTestBackend(testAddr)
1731+
defer sim.Close()
1732+
1733+
for i, test := range testCases {
1734+
t.Run(test.name, func(t *testing.T) {
1735+
bgCtx := context.Background()
1736+
// Create tx and send
1737+
head, _ := sim.HeaderByNumber(context.Background(), nil)
1738+
tip, err := sim.SuggestGasTipCap(bgCtx)
1739+
require.NoError(t, err)
1740+
normalGasPrice := new(big.Int).Add(head.BaseFee, tip)
1741+
highGasPrice := new(big.Int).Add(head.BaseFee, big.NewInt(5))
1742+
1743+
sim.SetMarketGasPrice(int64(highGasPrice.Uint64()))
1744+
1745+
var normalGasFeeTx *types.Transaction
1746+
txValue := big.NewInt(1)
1747+
1748+
if test.txType == types.LegacyTxType {
1749+
normalGasFeeTx = types.NewTx(&types.LegacyTx{
1750+
Nonce: uint64(i),
1751+
To: &testAddr,
1752+
Value: txValue,
1753+
GasPrice: normalGasPrice,
1754+
Gas: gas,
1755+
})
1756+
} else if test.txType == types.DynamicFeeTxType {
1757+
normalGasFeeTx = types.NewTx(&types.DynamicFeeTx{
1758+
Nonce: uint64(i),
1759+
Gas: gas,
1760+
To: &testAddr,
1761+
Value: txValue,
1762+
GasTipCap: normalGasPrice,
1763+
GasFeeCap: normalGasPrice,
1764+
})
1765+
} else {
1766+
t.Fatal("unexpected txType received")
1767+
}
1768+
1769+
signedTx, err := types.SignTx(normalGasFeeTx, types.LatestSigner(sim.config), testKey)
1770+
require.NoError(t, err)
1771+
1772+
// send tx to simulated backend
1773+
err = sim.SendTransaction(bgCtx, signedTx)
1774+
require.NoError(t, err)
1775+
sim.Commit()
1776+
1777+
// check that the nonce stays the same because nothing has been mined
1778+
pendingNonce, err := sim.PendingNonceAt(bgCtx, testAddr)
1779+
require.NoError(t, err)
1780+
assert.Equal(t, uint64(i), pendingNonce)
1781+
1782+
// gas fee has dropped
1783+
sim.SetMarketGasPrice(int64(normalGasPrice.Uint64()))
1784+
sim.Commit()
1785+
1786+
// nonce has increased
1787+
pendingNonce, err = sim.PendingNonceAt(bgCtx, testAddr)
1788+
require.NoError(t, err)
1789+
assert.Equal(t, uint64(i)+1, pendingNonce)
1790+
1791+
// the transaction should have been mined
1792+
_, isPending, err := sim.TransactionByHash(bgCtx, signedTx.Hash())
1793+
require.NoError(t, err)
1794+
assert.False(t, isPending)
1795+
})
1796+
}
1797+
}

0 commit comments

Comments
 (0)