Skip to content

Commit 7004182

Browse files
committed
core/txpool/blobpool: add test to check internal shuffling
1 parent 9274f28 commit 7004182

File tree

1 file changed

+81
-32
lines changed

1 file changed

+81
-32
lines changed

core/txpool/blobpool/blobpool_test.go

Lines changed: 81 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ import (
2727
"path/filepath"
2828
"sync"
2929
"testing"
30-
"time"
3130

3231
"github.com/ethereum/go-ethereum/common"
3332
"github.com/ethereum/go-ethereum/consensus/misc/eip1559"
@@ -53,33 +52,22 @@ var (
5352
emptyBlobVHash = kzg4844.CalcBlobHashV1(sha256.New(), &emptyBlobCommit)
5453
)
5554

56-
// Chain configuration with Cancun enabled.
57-
//
58-
// TODO(karalabe): replace with params.MainnetChainConfig after Cancun.
59-
var testChainConfig *params.ChainConfig
60-
61-
func init() {
62-
testChainConfig = new(params.ChainConfig)
63-
*testChainConfig = *params.MainnetChainConfig
64-
65-
testChainConfig.CancunTime = new(uint64)
66-
*testChainConfig.CancunTime = uint64(time.Now().Unix())
67-
}
68-
6955
// testBlockChain is a mock of the live chain for testing the pool.
7056
type testBlockChain struct {
7157
config *params.ChainConfig
7258
basefee *uint256.Int
7359
blobfee *uint256.Int
7460
statedb *state.StateDB
61+
62+
blocks map[uint64]*types.Block
7563
}
7664

7765
func (bc *testBlockChain) Config() *params.ChainConfig {
7866
return bc.config
7967
}
8068

8169
func (bc *testBlockChain) CurrentBlock() *types.Header {
82-
// Yolo, life is too short to invert mist.CalcBaseFee and misc.CalcBlobFee,
70+
// Yolo, life is too short to invert misc.CalcBaseFee and misc.CalcBlobFee,
8371
// just binary search it them.
8472

8573
// The base fee at 5714 ETH translates into the 21000 base gas higher than
@@ -142,7 +130,14 @@ func (bc *testBlockChain) CurrentFinalBlock() *types.Header {
142130
}
143131

144132
func (bc *testBlockChain) GetBlock(hash common.Hash, number uint64) *types.Block {
145-
return nil
133+
// This is very yolo for the tests. If the number is the origin block we use
134+
// to init the pool, return an empty block with the correct starting header.
135+
//
136+
// If it is something else, return some baked in mock data.
137+
if number == bc.config.LondonBlock.Uint64()+1 {
138+
return types.NewBlockWithHeader(bc.CurrentBlock())
139+
}
140+
return bc.blocks[number]
146141
}
147142

148143
func (bc *testBlockChain) StateAt(common.Hash) (*state.StateDB, error) {
@@ -181,14 +176,14 @@ func makeAddressReserver() txpool.AddressReserver {
181176
// the blob pool.
182177
func makeTx(nonce uint64, gasTipCap uint64, gasFeeCap uint64, blobFeeCap uint64, key *ecdsa.PrivateKey) *types.Transaction {
183178
blobtx := makeUnsignedTx(nonce, gasTipCap, gasFeeCap, blobFeeCap)
184-
return types.MustSignNewTx(key, types.LatestSigner(testChainConfig), blobtx)
179+
return types.MustSignNewTx(key, types.LatestSigner(params.MainnetChainConfig), blobtx)
185180
}
186181

187182
// makeUnsignedTx is a utility method to construct a random blob transaction
188183
// without signing it.
189184
func makeUnsignedTx(nonce uint64, gasTipCap uint64, gasFeeCap uint64, blobFeeCap uint64) *types.BlobTx {
190185
return &types.BlobTx{
191-
ChainID: uint256.MustFromBig(testChainConfig.ChainID),
186+
ChainID: uint256.MustFromBig(params.MainnetChainConfig.ChainID),
192187
Nonce: nonce,
193188
GasTipCap: uint256.NewInt(gasTipCap),
194189
GasFeeCap: uint256.NewInt(gasFeeCap),
@@ -229,13 +224,17 @@ func verifyPoolInternals(t *testing.T, pool *BlobPool) {
229224
for hash := range seen {
230225
t.Errorf("indexed transaction hash #%x missing from lookup table", hash)
231226
}
232-
// Verify that transactions are sorted per account and contain no nonce gaps
227+
// Verify that transactions are sorted per account and contain no nonce gaps,
228+
// and that the first nonce is the next expected one based on the state.
233229
for addr, txs := range pool.index {
234230
for i := 1; i < len(txs); i++ {
235231
if txs[i].nonce != txs[i-1].nonce+1 {
236232
t.Errorf("addr %v, tx %d nonce mismatch: have %d, want %d", addr, i, txs[i].nonce, txs[i-1].nonce+1)
237233
}
238234
}
235+
if txs[0].nonce != pool.state.GetNonce(addr) {
236+
t.Errorf("addr %v, first tx nonce mismatch: have %d, want %d", addr, txs[0].nonce, pool.state.GetNonce(addr))
237+
}
239238
}
240239
// Verify that calculated evacuation thresholds are correct
241240
for addr, txs := range pool.index {
@@ -331,7 +330,7 @@ func TestOpenDrops(t *testing.T) {
331330
// Insert a transaction with a bad signature to verify that stale junk after
332331
// potential hard-forks can get evicted (case 2)
333332
tx := types.NewTx(&types.BlobTx{
334-
ChainID: uint256.MustFromBig(testChainConfig.ChainID),
333+
ChainID: uint256.MustFromBig(params.MainnetChainConfig.ChainID),
335334
GasTipCap: new(uint256.Int),
336335
GasFeeCap: new(uint256.Int),
337336
Gas: 0,
@@ -560,7 +559,7 @@ func TestOpenDrops(t *testing.T) {
560559
statedb.Commit(0, true)
561560

562561
chain := &testBlockChain{
563-
config: testChainConfig,
562+
config: params.MainnetChainConfig,
564563
basefee: uint256.NewInt(params.InitialBaseFee),
565564
blobfee: uint256.NewInt(params.BlobTxMinBlobGasprice),
566565
statedb: statedb,
@@ -679,7 +678,7 @@ func TestOpenIndex(t *testing.T) {
679678
statedb.Commit(0, true)
680679

681680
chain := &testBlockChain{
682-
config: testChainConfig,
681+
config: params.MainnetChainConfig,
683682
basefee: uint256.NewInt(params.InitialBaseFee),
684683
blobfee: uint256.NewInt(params.BlobTxMinBlobGasprice),
685684
statedb: statedb,
@@ -781,7 +780,7 @@ func TestOpenHeap(t *testing.T) {
781780
statedb.Commit(0, true)
782781

783782
chain := &testBlockChain{
784-
config: testChainConfig,
783+
config: params.MainnetChainConfig,
785784
basefee: uint256.NewInt(1050),
786785
blobfee: uint256.NewInt(105),
787786
statedb: statedb,
@@ -861,7 +860,7 @@ func TestOpenCap(t *testing.T) {
861860
statedb.Commit(0, true)
862861

863862
chain := &testBlockChain{
864-
config: testChainConfig,
863+
config: params.MainnetChainConfig,
865864
basefee: uint256.NewInt(1050),
866865
blobfee: uint256.NewInt(105),
867866
statedb: statedb,
@@ -908,23 +907,28 @@ func TestOpenCap(t *testing.T) {
908907
func TestAdd(t *testing.T) {
909908
log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelTrace, true)))
910909

911-
// seed is a helper tumpe to seed an initial state db and pool
910+
// seed is a helper tuple to seed an initial state db and pool
912911
type seed struct {
913912
balance uint64
914913
nonce uint64
915914
txs []*types.BlobTx
916915
}
917-
918916
// addtx is a helper sender/tx tuple to represent a new tx addition
919917
type addtx struct {
920918
from string
921919
tx *types.BlobTx
922920
err error
923921
}
922+
// newhead ius a helper tumple to represent a chain head event
923+
type newhead struct {
924+
header *types.Header
925+
txs []*types.BlobTx
926+
}
924927

925928
tests := []struct {
926929
seeds map[string]seed
927930
adds []addtx
931+
block []addtx
928932
}{
929933
// Transactions from new accounts should be accepted if their initial
930934
// nonce matches the expected one from the statedb. Higher or lower must
@@ -1250,6 +1254,25 @@ func TestAdd(t *testing.T) {
12501254
},
12511255
},
12521256
},
1257+
// Tests issue #30518 where a refactor broke internal state invariants,
1258+
// causing included transactions not to be properly accounted and thus
1259+
// account states going our of sync with the chain.
1260+
{
1261+
seeds: map[string]seed{
1262+
"alice": {
1263+
balance: 1000000,
1264+
txs: []*types.BlobTx{
1265+
makeUnsignedTx(0, 1, 1, 1),
1266+
},
1267+
},
1268+
},
1269+
block: []addtx{
1270+
{
1271+
from: "alice",
1272+
tx: makeUnsignedTx(0, 1, 1, 1),
1273+
},
1274+
},
1275+
},
12531276
}
12541277
for i, tt := range tests {
12551278
// Create a temporary folder for the persistent backend
@@ -1276,7 +1299,7 @@ func TestAdd(t *testing.T) {
12761299

12771300
// Sign the seed transactions and store them in the data store
12781301
for _, tx := range seed.txs {
1279-
signed := types.MustSignNewTx(keys[acc], types.LatestSigner(testChainConfig), tx)
1302+
signed := types.MustSignNewTx(keys[acc], types.LatestSigner(params.MainnetChainConfig), tx)
12801303
blob, _ := rlp.EncodeToBytes(signed)
12811304
store.Put(blob)
12821305
}
@@ -1286,7 +1309,7 @@ func TestAdd(t *testing.T) {
12861309

12871310
// Create a blob pool out of the pre-seeded dats
12881311
chain := &testBlockChain{
1289-
config: testChainConfig,
1312+
config: params.MainnetChainConfig,
12901313
basefee: uint256.NewInt(1050),
12911314
blobfee: uint256.NewInt(105),
12921315
statedb: statedb,
@@ -1299,14 +1322,40 @@ func TestAdd(t *testing.T) {
12991322

13001323
// Add each transaction one by one, verifying the pool internals in between
13011324
for j, add := range tt.adds {
1302-
signed, _ := types.SignNewTx(keys[add.from], types.LatestSigner(testChainConfig), add.tx)
1325+
signed, _ := types.SignNewTx(keys[add.from], types.LatestSigner(params.MainnetChainConfig), add.tx)
13031326
if err := pool.add(signed); !errors.Is(err, add.err) {
13041327
t.Errorf("test %d, tx %d: adding transaction error mismatch: have %v, want %v", i, j, err, add.err)
13051328
}
13061329
verifyPoolInternals(t, pool)
13071330
}
1308-
// Verify the pool internals and close down the test
13091331
verifyPoolInternals(t, pool)
1332+
1333+
// If the test contains a chain head event, run that and gain verify the internals
1334+
if tt.block != nil {
1335+
// Fake a header for the new set of transactions
1336+
header := &types.Header{
1337+
Number: big.NewInt(int64(chain.CurrentBlock().Number.Uint64() + 1)),
1338+
BaseFee: chain.CurrentBlock().BaseFee, // invalid, but nothing checks it, yolo
1339+
}
1340+
// Inject the fake block into the chain
1341+
txs := make([]*types.Transaction, len(tt.block))
1342+
for j, inc := range tt.block {
1343+
txs[j] = types.MustSignNewTx(keys[inc.from], types.LatestSigner(params.MainnetChainConfig), inc.tx)
1344+
}
1345+
chain.blocks = map[uint64]*types.Block{
1346+
header.Number.Uint64(): types.NewBlockWithHeader(header).WithBody(types.Body{
1347+
Transactions: txs,
1348+
}),
1349+
}
1350+
// Apply the nonce updates to the state db
1351+
for _, tx := range txs {
1352+
sender, _ := types.Sender(types.LatestSigner(params.MainnetChainConfig), tx)
1353+
chain.statedb.SetNonce(sender, tx.Nonce()+1)
1354+
}
1355+
pool.Reset(chain.CurrentBlock(), header)
1356+
verifyPoolInternals(t, pool)
1357+
}
1358+
// Close down the test
13101359
pool.Close()
13111360
}
13121361
}
@@ -1325,10 +1374,10 @@ func benchmarkPoolPending(b *testing.B, datacap uint64) {
13251374
var (
13261375
basefee = uint64(1050)
13271376
blobfee = uint64(105)
1328-
signer = types.LatestSigner(testChainConfig)
1377+
signer = types.LatestSigner(params.MainnetChainConfig)
13291378
statedb, _ = state.New(types.EmptyRootHash, state.NewDatabaseForTesting())
13301379
chain = &testBlockChain{
1331-
config: testChainConfig,
1380+
config: params.MainnetChainConfig,
13321381
basefee: uint256.NewInt(basefee),
13331382
blobfee: uint256.NewInt(blobfee),
13341383
statedb: statedb,

0 commit comments

Comments
 (0)