Skip to content

Commit

Permalink
accounts/abi/bind/backends: return hash of new blocks (ethereum#25163)
Browse files Browse the repository at this point in the history
Co-authored-by: Jens <[email protected]>
  • Loading branch information
2 people authored and blakehhuynh committed Oct 7, 2022
1 parent cbd1ec6 commit adce2ff
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 188 deletions.
9 changes: 6 additions & 3 deletions accounts/abi/bind/backends/simulated.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ func (b *SimulatedBackend) Close() error {

// Commit imports all the pending transactions as a single block and starts a
// fresh new state.
func (b *SimulatedBackend) Commit() {
func (b *SimulatedBackend) Commit() common.Hash {
b.mu.Lock()
defer b.mu.Unlock()

Expand All @@ -130,10 +130,13 @@ func (b *SimulatedBackend) Commit() {
if _, err := b.blockchain.InsertChain([]*types.Block{blocks[0]}); err != nil {
panic(err) // This cannot happen unless the simulator is wrong, fail in that case
}
blockHash := b.pendingBlock.Hash()

// Using the last inserted block here makes it possible to build on a side
// chain after a fork.
b.stuckTransactions = remainingTx
b.rollback(blocks[0])
b.rollback(b.pendingBlock)

return blockHash
}

// Rollback aborts all pending transactions, reverting to the last committed state.
Expand Down
211 changes: 26 additions & 185 deletions accounts/abi/bind/backends/simulated_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1339,200 +1339,41 @@ func TestForkResendTx(t *testing.T) {
}
}

// TestLowGasTxNotBeingMined checks that the lower gas fee tx with same nonce does not get mined
// Steps:
// 1. Send a tx lower than the set market gas price
// 2. Commit to chain, check nonce stays the same
// 3. Send a tx meets the market gas price with same nonce.
// 4. Commit to chain
// 5. Check tx2 is not in pending state and nonce has increased
func TestLowGasTxNotBeingMined(t *testing.T) {
func TestCommitReturnValue(t *testing.T) {
testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
var gas uint64 = 21000

sim := simTestBackend(testAddr)
defer sim.Close()

var testCases = []struct {
name string
txType byte
}{
{
name: "LegacyTx",
txType: types.LegacyTxType,
},
{
name: "dynamicTx",
txType: types.DynamicFeeTxType,
},
}
for i, test := range testCases {
t.Run(test.name, func(t *testing.T) {
bgCtx := context.Background()
// Create tx and send
head, _ := sim.HeaderByNumber(context.Background(), nil)
tip, err := sim.SuggestGasTipCap(bgCtx)
require.NoError(t, err)
gasPrice := new(big.Int).Add(head.BaseFee, tip)
sim.SetMarketGasPrice(int64(gasPrice.Uint64()))

lowFeeGas := new(big.Int).Sub(gasPrice, tip)
txValue := big.NewInt(1)

var lowGasFeeTx *types.Transaction

if test.txType == types.LegacyTxType {
lowGasFeeTx = types.NewTx(&types.LegacyTx{
Nonce: uint64(i),
To: &testAddr,
Value: txValue,
GasPrice: lowFeeGas,
Gas: gas,
})
} else if test.txType == types.DynamicFeeTxType {
lowGasFeeTx = types.NewTx(&types.DynamicFeeTx{
Nonce: uint64(i),
Gas: gas,
To: &testAddr,
Value: txValue,
GasTipCap: lowFeeGas,
GasFeeCap: lowFeeGas,
})
} else {
t.Fatal("unexpected txType received")
}
startBlockHeight := sim.blockchain.CurrentBlock().NumberU64()

signedTx, err := types.SignTx(lowGasFeeTx, types.LatestSigner(sim.config), testKey)
require.NoError(t, err)

// send tx to simulated backend
err = sim.SendTransaction(bgCtx, signedTx)
require.NoError(t, err)
sim.Commit()

// expect nonce be the same because low gas fee tx will not be mined
nonce, err := sim.PendingNonceAt(bgCtx, testAddr)
require.NoError(t, err)
assert.Equal(t, uint64(i), nonce)

// send tx with higher gas fee
sufficientGasFeeTx := types.NewTx(&types.LegacyTx{
Nonce: uint64(i),
To: &testAddr,
Value: txValue,
GasPrice: gasPrice,
Gas: gas,
})

signedSufficientTx, err := types.SignTx(sufficientGasFeeTx, types.HomesteadSigner{}, testKey)
require.NoError(t, err)

err = sim.SendTransaction(bgCtx, signedSufficientTx)
require.NoError(t, err)
sim.Commit()

// the higher gas transaction should have been mined
_, isPending, err := sim.TransactionByHash(bgCtx, signedSufficientTx.Hash())
require.NoError(t, err)
assert.False(t, isPending)

// expect nonce has increased
nonce, err = sim.PendingNonceAt(bgCtx, testAddr)
require.NoError(t, err)
assert.Equal(t, uint64(i) + 1, nonce)
})
// Test if Commit returns the correct block hash
h1 := sim.Commit()
if h1 != sim.blockchain.CurrentBlock().Hash() {
t.Error("Commit did not return the hash of the last block.")
}
}

// TestLowGasTxGetMinedOnceGasFeeDropped checks that lower gas fee txes still stay in mem pool
// and get mined once gas fee requirement has been met
// Steps:
// 1. Send a tx lower than the set market gas price
// 2. Commit to chain, tx does not get mined
// 3. Gas fee drops, commit again
// 4. Check tx get mined
func TestLowGasTxGetMinedOnceGasFeeDropped(t *testing.T) {
var testCases = []struct {
name string
txType byte
}{
{
name: "LegacyTx",
txType: types.LegacyTxType,
},
{
name: "dynamicTx",
txType: types.DynamicFeeTxType,
},
}
testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
var gas uint64 = 21000

sim := simTestBackend(testAddr)
defer sim.Close()

for i, test := range testCases {
t.Run(test.name, func(t *testing.T) {
bgCtx := context.Background()
// Create tx and send
head, _ := sim.HeaderByNumber(context.Background(), nil)
tip, err := sim.SuggestGasTipCap(bgCtx)
require.NoError(t, err)
normalGasPrice := new(big.Int).Add(head.BaseFee, tip)
highGasPrice := new(big.Int).Add(head.BaseFee, big.NewInt(5))

sim.SetMarketGasPrice(int64(highGasPrice.Uint64()))

var normalGasFeeTx *types.Transaction
txValue := big.NewInt(1)

if test.txType == types.LegacyTxType {
normalGasFeeTx = types.NewTx(&types.LegacyTx{
Nonce: uint64(i),
To: &testAddr,
Value: txValue,
GasPrice: normalGasPrice,
Gas: gas,
})
} else if test.txType == types.DynamicFeeTxType {
normalGasFeeTx = types.NewTx(&types.DynamicFeeTx{
Nonce: uint64(i),
Gas: gas,
To: &testAddr,
Value: txValue,
GasTipCap: normalGasPrice,
GasFeeCap: normalGasPrice,
})
} else {
t.Fatal("unexpected txType received")
}

signedTx, err := types.SignTx(normalGasFeeTx, types.LatestSigner(sim.config), testKey)
require.NoError(t, err)

// send tx to simulated backend
err = sim.SendTransaction(bgCtx, signedTx)
require.NoError(t, err)
sim.Commit()

// check that the nonce stays the same because nothing has been mined
pendingNonce, err := sim.PendingNonceAt(bgCtx, testAddr)
require.NoError(t, err)
assert.Equal(t, uint64(i), pendingNonce)
// Create a block in the original chain (containing a transaction to force different block hashes)
head, _ := sim.HeaderByNumber(context.Background(), nil) // Should be child's, good enough
gasPrice := new(big.Int).Add(head.BaseFee, big.NewInt(1))
_tx := types.NewTransaction(0, testAddr, big.NewInt(1000), params.TxGas, gasPrice, nil)
tx, _ := types.SignTx(_tx, types.HomesteadSigner{}, testKey)
sim.SendTransaction(context.Background(), tx)
h2 := sim.Commit()

// gas fee has dropped
sim.SetMarketGasPrice(int64(normalGasPrice.Uint64()))
sim.Commit()
// Create another block in the original chain
sim.Commit()

// nonce has increased
pendingNonce, err = sim.PendingNonceAt(bgCtx, testAddr)
require.NoError(t, err)
assert.Equal(t, uint64(i) + 1, pendingNonce)
// Fork at the first bock
if err := sim.Fork(context.Background(), h1); err != nil {
t.Errorf("forking: %v", err)
}

// the transaction should have been mined
_, isPending, err := sim.TransactionByHash(bgCtx, signedTx.Hash())
require.NoError(t, err)
assert.False(t, isPending)
})
// Test if Commit returns the correct block hash after the reorg
h2fork := sim.Commit()
if h2 == h2fork {
t.Error("The block in the fork and the original block are the same block!")
}
if sim.blockchain.GetHeader(h2fork, startBlockHeight+2) == nil {
t.Error("Could not retrieve the just created block (side-chain)")
}
}

0 comments on commit adce2ff

Please sign in to comment.