github.com/ethereum/go-ethereum@v1.16.1/core/txpool/legacypool/legacypool_test.go (about) 1 // Copyright 2015 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package legacypool 18 19 import ( 20 "crypto/ecdsa" 21 crand "crypto/rand" 22 "errors" 23 "fmt" 24 "math/big" 25 "math/rand" 26 "slices" 27 "sync" 28 "sync/atomic" 29 "testing" 30 "time" 31 32 "github.com/ethereum/go-ethereum/common" 33 "github.com/ethereum/go-ethereum/core" 34 "github.com/ethereum/go-ethereum/core/state" 35 "github.com/ethereum/go-ethereum/core/tracing" 36 "github.com/ethereum/go-ethereum/core/txpool" 37 "github.com/ethereum/go-ethereum/core/types" 38 "github.com/ethereum/go-ethereum/core/vm" 39 "github.com/ethereum/go-ethereum/crypto" 40 "github.com/ethereum/go-ethereum/event" 41 "github.com/ethereum/go-ethereum/params" 42 "github.com/ethereum/go-ethereum/trie" 43 "github.com/holiman/uint256" 44 ) 45 46 var ( 47 // testTxPoolConfig is a transaction pool configuration without stateful disk 48 // sideeffects used during testing. 49 testTxPoolConfig Config 50 51 // eip1559Config is a chain config with EIP-1559 enabled at block 0. 52 eip1559Config *params.ChainConfig 53 ) 54 55 func init() { 56 testTxPoolConfig = DefaultConfig 57 testTxPoolConfig.Journal = "" 58 59 cpy := *params.TestChainConfig 60 eip1559Config = &cpy 61 eip1559Config.BerlinBlock = common.Big0 62 eip1559Config.LondonBlock = common.Big0 63 } 64 65 type testBlockChain struct { 66 config *params.ChainConfig 67 gasLimit atomic.Uint64 68 statedb *state.StateDB 69 chainHeadFeed *event.Feed 70 } 71 72 func newTestBlockChain(config *params.ChainConfig, gasLimit uint64, statedb *state.StateDB, chainHeadFeed *event.Feed) *testBlockChain { 73 bc := testBlockChain{config: config, statedb: statedb, chainHeadFeed: new(event.Feed)} 74 bc.gasLimit.Store(gasLimit) 75 return &bc 76 } 77 78 func (bc *testBlockChain) Config() *params.ChainConfig { 79 return bc.config 80 } 81 82 func (bc *testBlockChain) CurrentBlock() *types.Header { 83 return &types.Header{ 84 Number: new(big.Int), 85 Difficulty: common.Big0, 86 GasLimit: bc.gasLimit.Load(), 87 } 88 } 89 90 func (bc *testBlockChain) GetBlock(hash common.Hash, number uint64) *types.Block { 91 return types.NewBlock(bc.CurrentBlock(), nil, nil, trie.NewStackTrie(nil)) 92 } 93 94 func (bc *testBlockChain) StateAt(common.Hash) (*state.StateDB, error) { 95 return bc.statedb, nil 96 } 97 98 func (bc *testBlockChain) SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription { 99 return bc.chainHeadFeed.Subscribe(ch) 100 } 101 102 func transaction(nonce uint64, gaslimit uint64, key *ecdsa.PrivateKey) *types.Transaction { 103 return pricedTransaction(nonce, gaslimit, big.NewInt(1), key) 104 } 105 106 func pricedTransaction(nonce uint64, gaslimit uint64, gasprice *big.Int, key *ecdsa.PrivateKey) *types.Transaction { 107 tx, _ := types.SignTx(types.NewTransaction(nonce, common.Address{}, big.NewInt(100), gaslimit, gasprice, nil), types.HomesteadSigner{}, key) 108 return tx 109 } 110 111 // pricedDataTransaction generates a signed transaction with fixed-size data, 112 // and ensures that the resulting signature components (r and s) are exactly 32 bytes each, 113 // producing transactions with deterministic size. 114 // 115 // This avoids variability in transaction size caused by leading zeros being omitted in 116 // RLP encoding of r/s. Since r and s are derived from ECDSA, they occasionally have leading 117 // zeros and thus can be shorter than 32 bytes. 118 // 119 // For example: 120 // 121 // r: 0 leading zeros, bytesSize: 32, bytes: [221 ... 101] 122 // s: 1 leading zeros, bytesSize: 31, bytes: [0 75 ... 47] 123 func pricedDataTransaction(nonce uint64, gaslimit uint64, gasprice *big.Int, key *ecdsa.PrivateKey, dataBytes uint64) *types.Transaction { 124 var tx *types.Transaction 125 126 // 10 attempts is statistically sufficient since leading zeros in ECDSA signatures are rare and randomly distributed. 127 var retryTimes = 10 128 for i := 0; i < retryTimes; i++ { 129 data := make([]byte, dataBytes) 130 crand.Read(data) 131 132 tx, _ = types.SignTx(types.NewTransaction(nonce, common.Address{}, big.NewInt(0), gaslimit, gasprice, data), types.HomesteadSigner{}, key) 133 _, r, s := tx.RawSignatureValues() 134 if len(r.Bytes()) == 32 && len(s.Bytes()) == 32 { 135 break 136 } 137 } 138 return tx 139 } 140 141 func dynamicFeeTx(nonce uint64, gaslimit uint64, gasFee *big.Int, tip *big.Int, key *ecdsa.PrivateKey) *types.Transaction { 142 tx, _ := types.SignNewTx(key, types.LatestSignerForChainID(params.TestChainConfig.ChainID), &types.DynamicFeeTx{ 143 ChainID: params.TestChainConfig.ChainID, 144 Nonce: nonce, 145 GasTipCap: tip, 146 GasFeeCap: gasFee, 147 Gas: gaslimit, 148 To: &common.Address{}, 149 Value: big.NewInt(100), 150 Data: nil, 151 AccessList: nil, 152 }) 153 return tx 154 } 155 156 type unsignedAuth struct { 157 nonce uint64 158 key *ecdsa.PrivateKey 159 } 160 161 func setCodeTx(nonce uint64, key *ecdsa.PrivateKey, unsigned []unsignedAuth) *types.Transaction { 162 return pricedSetCodeTx(nonce, 250000, uint256.NewInt(1000), uint256.NewInt(1), key, unsigned) 163 } 164 165 func pricedSetCodeTx(nonce uint64, gaslimit uint64, gasFee, tip *uint256.Int, key *ecdsa.PrivateKey, unsigned []unsignedAuth) *types.Transaction { 166 var authList []types.SetCodeAuthorization 167 for _, u := range unsigned { 168 auth, _ := types.SignSetCode(u.key, types.SetCodeAuthorization{ 169 ChainID: *uint256.MustFromBig(params.TestChainConfig.ChainID), 170 Address: common.Address{0x42}, 171 Nonce: u.nonce, 172 }) 173 authList = append(authList, auth) 174 } 175 return pricedSetCodeTxWithAuth(nonce, gaslimit, gasFee, tip, key, authList) 176 } 177 178 func pricedSetCodeTxWithAuth(nonce uint64, gaslimit uint64, gasFee, tip *uint256.Int, key *ecdsa.PrivateKey, authList []types.SetCodeAuthorization) *types.Transaction { 179 return types.MustSignNewTx(key, types.LatestSignerForChainID(params.TestChainConfig.ChainID), &types.SetCodeTx{ 180 ChainID: uint256.MustFromBig(params.TestChainConfig.ChainID), 181 Nonce: nonce, 182 GasTipCap: tip, 183 GasFeeCap: gasFee, 184 Gas: gaslimit, 185 To: common.Address{}, 186 Value: uint256.NewInt(100), 187 Data: nil, 188 AccessList: nil, 189 AuthList: authList, 190 }) 191 } 192 193 func setupPool() (*LegacyPool, *ecdsa.PrivateKey) { 194 return setupPoolWithConfig(params.TestChainConfig) 195 } 196 197 // reserver is a utility struct to sanity check that accounts are 198 // properly reserved by the blobpool (no duplicate reserves or unreserves). 199 type reserver struct { 200 accounts map[common.Address]struct{} 201 lock sync.RWMutex 202 } 203 204 func newReserver() txpool.Reserver { 205 return &reserver{accounts: make(map[common.Address]struct{})} 206 } 207 208 func (r *reserver) Hold(addr common.Address) error { 209 r.lock.Lock() 210 defer r.lock.Unlock() 211 if _, exists := r.accounts[addr]; exists { 212 panic("already reserved") 213 } 214 r.accounts[addr] = struct{}{} 215 return nil 216 } 217 218 func (r *reserver) Release(addr common.Address) error { 219 r.lock.Lock() 220 defer r.lock.Unlock() 221 if _, exists := r.accounts[addr]; !exists { 222 panic("not reserved") 223 } 224 delete(r.accounts, addr) 225 return nil 226 } 227 228 func (r *reserver) Has(address common.Address) bool { 229 return false // reserver only supports a single pool 230 } 231 232 func setupPoolWithConfig(config *params.ChainConfig) (*LegacyPool, *ecdsa.PrivateKey) { 233 statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) 234 blockchain := newTestBlockChain(config, 10000000, statedb, new(event.Feed)) 235 236 key, _ := crypto.GenerateKey() 237 pool := New(testTxPoolConfig, blockchain) 238 if err := pool.Init(testTxPoolConfig.PriceLimit, blockchain.CurrentBlock(), newReserver()); err != nil { 239 panic(err) 240 } 241 // wait for the pool to initialize 242 <-pool.initDoneCh 243 return pool, key 244 } 245 246 // validatePoolInternals checks various consistency invariants within the pool. 247 func validatePoolInternals(pool *LegacyPool) error { 248 pool.mu.RLock() 249 defer pool.mu.RUnlock() 250 251 // Ensure the total transaction set is consistent with pending + queued 252 pending, queued := pool.stats() 253 if total := pool.all.Count(); total != pending+queued { 254 return fmt.Errorf("total transaction count %d != %d pending + %d queued", total, pending, queued) 255 } 256 pool.priced.Reheap() 257 priced, remote := pool.priced.urgent.Len()+pool.priced.floating.Len(), pool.all.Count() 258 if priced != remote { 259 return fmt.Errorf("total priced transaction count %d != %d", priced, remote) 260 } 261 // Ensure the next nonce to assign is the correct one 262 for addr, txs := range pool.pending { 263 // Find the last transaction 264 var last uint64 265 for nonce := range txs.txs.items { 266 if last < nonce { 267 last = nonce 268 } 269 } 270 if nonce := pool.pendingNonces.get(addr); nonce != last+1 { 271 return fmt.Errorf("pending nonce mismatch: have %v, want %v", nonce, last+1) 272 } 273 } 274 // Ensure all auths in pool are tracked 275 for _, tx := range pool.all.txs { 276 for _, addr := range tx.SetCodeAuthorities() { 277 list := pool.all.auths[addr] 278 if i := slices.Index(list, tx.Hash()); i < 0 { 279 return fmt.Errorf("authority not tracked: addr %s, tx %s", addr, tx.Hash()) 280 } 281 } 282 } 283 // Ensure all auths in pool have an associated tx. 284 for addr, hashes := range pool.all.auths { 285 for _, hash := range hashes { 286 if _, ok := pool.all.txs[hash]; !ok { 287 return fmt.Errorf("dangling authority, missing originating tx: addr %s, hash %s", addr, hash.Hex()) 288 } 289 } 290 } 291 return nil 292 } 293 294 // validateEvents checks that the correct number of transaction addition events 295 // were fired on the pool's event feed. 296 func validateEvents(events chan core.NewTxsEvent, count int) error { 297 var received []*types.Transaction 298 299 for len(received) < count { 300 select { 301 case ev := <-events: 302 received = append(received, ev.Txs...) 303 case <-time.After(time.Second): 304 return fmt.Errorf("event #%d not fired", len(received)) 305 } 306 } 307 if len(received) > count { 308 return fmt.Errorf("more than %d events fired: %v", count, received[count:]) 309 } 310 select { 311 case ev := <-events: 312 return fmt.Errorf("more than %d events fired: %v", count, ev.Txs) 313 314 case <-time.After(50 * time.Millisecond): 315 // This branch should be "default", but it's a data race between goroutines, 316 // reading the event channel and pushing into it, so better wait a bit ensuring 317 // really nothing gets injected. 318 } 319 return nil 320 } 321 322 func deriveSender(tx *types.Transaction) (common.Address, error) { 323 return types.Sender(types.HomesteadSigner{}, tx) 324 } 325 326 type testChain struct { 327 *testBlockChain 328 address common.Address 329 trigger *bool 330 } 331 332 // testChain.State() is used multiple times to reset the pending state. 333 // when simulate is true it will create a state that indicates 334 // that tx0 and tx1 are included in the chain. 335 func (c *testChain) State() (*state.StateDB, error) { 336 // delay "state change" by one. The tx pool fetches the 337 // state multiple times and by delaying it a bit we simulate 338 // a state change between those fetches. 339 stdb := c.statedb 340 if *c.trigger { 341 c.statedb, _ = state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) 342 // simulate that the new head block included tx0 and tx1 343 c.statedb.SetNonce(c.address, 2, tracing.NonceChangeUnspecified) 344 c.statedb.SetBalance(c.address, new(uint256.Int).SetUint64(params.Ether), tracing.BalanceChangeUnspecified) 345 *c.trigger = false 346 } 347 return stdb, nil 348 } 349 350 // This test simulates a scenario where a new block is imported during a 351 // state reset and tests whether the pending state is in sync with the 352 // block head event that initiated the resetState(). 353 func TestStateChangeDuringReset(t *testing.T) { 354 t.Parallel() 355 356 var ( 357 key, _ = crypto.GenerateKey() 358 address = crypto.PubkeyToAddress(key.PublicKey) 359 statedb, _ = state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) 360 trigger = false 361 ) 362 363 // setup pool with 2 transaction in it 364 statedb.SetBalance(address, new(uint256.Int).SetUint64(params.Ether), tracing.BalanceChangeUnspecified) 365 blockchain := &testChain{newTestBlockChain(params.TestChainConfig, 1000000000, statedb, new(event.Feed)), address, &trigger} 366 367 tx0 := transaction(0, 100000, key) 368 tx1 := transaction(1, 100000, key) 369 370 pool := New(testTxPoolConfig, blockchain) 371 pool.Init(testTxPoolConfig.PriceLimit, blockchain.CurrentBlock(), newReserver()) 372 defer pool.Close() 373 374 nonce := pool.Nonce(address) 375 if nonce != 0 { 376 t.Fatalf("Invalid nonce, want 0, got %d", nonce) 377 } 378 379 pool.addRemotesSync([]*types.Transaction{tx0, tx1}) 380 381 nonce = pool.Nonce(address) 382 if nonce != 2 { 383 t.Fatalf("Invalid nonce, want 2, got %d", nonce) 384 } 385 386 // trigger state change in the background 387 trigger = true 388 <-pool.requestReset(nil, nil) 389 390 nonce = pool.Nonce(address) 391 if nonce != 2 { 392 t.Fatalf("Invalid nonce, want 2, got %d", nonce) 393 } 394 } 395 396 func testAddBalance(pool *LegacyPool, addr common.Address, amount *big.Int) { 397 pool.mu.Lock() 398 pool.currentState.AddBalance(addr, uint256.MustFromBig(amount), tracing.BalanceChangeUnspecified) 399 pool.mu.Unlock() 400 } 401 402 func testSetNonce(pool *LegacyPool, addr common.Address, nonce uint64) { 403 pool.mu.Lock() 404 pool.currentState.SetNonce(addr, nonce, tracing.NonceChangeUnspecified) 405 pool.mu.Unlock() 406 } 407 408 func TestInvalidTransactions(t *testing.T) { 409 t.Parallel() 410 411 pool, key := setupPool() 412 defer pool.Close() 413 414 tx := transaction(0, 100, key) 415 from, _ := deriveSender(tx) 416 417 // Intrinsic gas too low 418 testAddBalance(pool, from, big.NewInt(1)) 419 if err, want := pool.addRemote(tx), core.ErrIntrinsicGas; !errors.Is(err, want) { 420 t.Errorf("want %v have %v", want, err) 421 } 422 423 // Insufficient funds 424 tx = transaction(0, 100000, key) 425 if err, want := pool.addRemote(tx), core.ErrInsufficientFunds; !errors.Is(err, want) { 426 t.Errorf("want %v have %v", want, err) 427 } 428 429 testSetNonce(pool, from, 1) 430 testAddBalance(pool, from, big.NewInt(0xffffffffffffff)) 431 tx = transaction(0, 100000, key) 432 if err, want := pool.addRemote(tx), core.ErrNonceTooLow; !errors.Is(err, want) { 433 t.Errorf("want %v have %v", want, err) 434 } 435 436 tx = transaction(1, 100000, key) 437 pool.gasTip.Store(uint256.NewInt(1000)) 438 if err, want := pool.addRemote(tx), txpool.ErrTxGasPriceTooLow; !errors.Is(err, want) { 439 t.Errorf("want %v have %v", want, err) 440 } 441 } 442 443 func TestQueue(t *testing.T) { 444 t.Parallel() 445 446 pool, key := setupPool() 447 defer pool.Close() 448 449 tx := transaction(0, 100, key) 450 from, _ := deriveSender(tx) 451 testAddBalance(pool, from, big.NewInt(1000)) 452 <-pool.requestReset(nil, nil) 453 454 pool.enqueueTx(tx.Hash(), tx, true) 455 <-pool.requestPromoteExecutables(newAccountSet(pool.signer, from)) 456 if len(pool.pending) != 1 { 457 t.Error("expected valid txs to be 1 is", len(pool.pending)) 458 } 459 460 tx = transaction(1, 100, key) 461 from, _ = deriveSender(tx) 462 testSetNonce(pool, from, 2) 463 pool.enqueueTx(tx.Hash(), tx, true) 464 465 <-pool.requestPromoteExecutables(newAccountSet(pool.signer, from)) 466 if _, ok := pool.pending[from].txs.items[tx.Nonce()]; ok { 467 t.Error("expected transaction to be in tx pool") 468 } 469 if len(pool.queue) > 0 { 470 t.Error("expected transaction queue to be empty. is", len(pool.queue)) 471 } 472 } 473 474 func TestQueue2(t *testing.T) { 475 t.Parallel() 476 477 pool, key := setupPool() 478 defer pool.Close() 479 480 tx1 := transaction(0, 100, key) 481 tx2 := transaction(10, 100, key) 482 tx3 := transaction(11, 100, key) 483 from, _ := deriveSender(tx1) 484 testAddBalance(pool, from, big.NewInt(1000)) 485 pool.reset(nil, nil) 486 487 pool.enqueueTx(tx1.Hash(), tx1, true) 488 pool.enqueueTx(tx2.Hash(), tx2, true) 489 pool.enqueueTx(tx3.Hash(), tx3, true) 490 491 pool.promoteExecutables([]common.Address{from}) 492 if len(pool.pending) != 1 { 493 t.Error("expected pending length to be 1, got", len(pool.pending)) 494 } 495 if pool.queue[from].Len() != 2 { 496 t.Error("expected len(queue) == 2, got", pool.queue[from].Len()) 497 } 498 } 499 500 func TestNegativeValue(t *testing.T) { 501 t.Parallel() 502 503 pool, key := setupPool() 504 defer pool.Close() 505 506 tx, _ := types.SignTx(types.NewTransaction(0, common.Address{}, big.NewInt(-1), 100, big.NewInt(1), nil), types.HomesteadSigner{}, key) 507 from, _ := deriveSender(tx) 508 testAddBalance(pool, from, big.NewInt(1)) 509 if err := pool.addRemote(tx); !errors.Is(err, txpool.ErrNegativeValue) { 510 t.Error("expected", txpool.ErrNegativeValue, "got", err) 511 } 512 } 513 514 func TestTipAboveFeeCap(t *testing.T) { 515 t.Parallel() 516 517 pool, key := setupPoolWithConfig(eip1559Config) 518 defer pool.Close() 519 520 tx := dynamicFeeTx(0, 100, big.NewInt(1), big.NewInt(2), key) 521 522 if err := pool.addRemote(tx); !errors.Is(err, core.ErrTipAboveFeeCap) { 523 t.Error("expected", core.ErrTipAboveFeeCap, "got", err) 524 } 525 } 526 527 func TestVeryHighValues(t *testing.T) { 528 t.Parallel() 529 530 pool, key := setupPoolWithConfig(eip1559Config) 531 defer pool.Close() 532 533 veryBigNumber := big.NewInt(1) 534 veryBigNumber.Lsh(veryBigNumber, 300) 535 536 tx := dynamicFeeTx(0, 100, big.NewInt(1), veryBigNumber, key) 537 if err := pool.addRemote(tx); !errors.Is(err, core.ErrTipVeryHigh) { 538 t.Error("expected", core.ErrTipVeryHigh, "got", err) 539 } 540 541 tx2 := dynamicFeeTx(0, 100, veryBigNumber, big.NewInt(1), key) 542 if err := pool.addRemote(tx2); !errors.Is(err, core.ErrFeeCapVeryHigh) { 543 t.Error("expected", core.ErrFeeCapVeryHigh, "got", err) 544 } 545 } 546 547 func TestChainFork(t *testing.T) { 548 t.Parallel() 549 550 pool, key := setupPool() 551 defer pool.Close() 552 553 addr := crypto.PubkeyToAddress(key.PublicKey) 554 resetState := func() { 555 statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) 556 statedb.AddBalance(addr, uint256.NewInt(100000000000000), tracing.BalanceChangeUnspecified) 557 558 pool.chain = newTestBlockChain(pool.chainconfig, 1000000, statedb, new(event.Feed)) 559 <-pool.requestReset(nil, nil) 560 } 561 resetState() 562 563 tx := transaction(0, 100000, key) 564 if _, err := pool.add(tx); err != nil { 565 t.Error("didn't expect error", err) 566 } 567 pool.removeTx(tx.Hash(), true, true) 568 569 // reset the pool's internal state 570 resetState() 571 if _, err := pool.add(tx); err != nil { 572 t.Error("didn't expect error", err) 573 } 574 } 575 576 func TestDoubleNonce(t *testing.T) { 577 t.Parallel() 578 579 pool, key := setupPool() 580 defer pool.Close() 581 582 addr := crypto.PubkeyToAddress(key.PublicKey) 583 resetState := func() { 584 statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) 585 statedb.AddBalance(addr, uint256.NewInt(100000000000000), tracing.BalanceChangeUnspecified) 586 587 pool.chain = newTestBlockChain(pool.chainconfig, 1000000, statedb, new(event.Feed)) 588 <-pool.requestReset(nil, nil) 589 } 590 resetState() 591 592 signer := types.HomesteadSigner{} 593 tx1, _ := types.SignTx(types.NewTransaction(0, common.Address{}, big.NewInt(100), 100000, big.NewInt(1), nil), signer, key) 594 tx2, _ := types.SignTx(types.NewTransaction(0, common.Address{}, big.NewInt(100), 1000000, big.NewInt(2), nil), signer, key) 595 tx3, _ := types.SignTx(types.NewTransaction(0, common.Address{}, big.NewInt(100), 1000000, big.NewInt(1), nil), signer, key) 596 597 // Add the first two transaction, ensure higher priced stays only 598 if replace, err := pool.add(tx1); err != nil || replace { 599 t.Errorf("first transaction insert failed (%v) or reported replacement (%v)", err, replace) 600 } 601 if replace, err := pool.add(tx2); err != nil || !replace { 602 t.Errorf("second transaction insert failed (%v) or not reported replacement (%v)", err, replace) 603 } 604 <-pool.requestPromoteExecutables(newAccountSet(signer, addr)) 605 if pool.pending[addr].Len() != 1 { 606 t.Error("expected 1 pending transactions, got", pool.pending[addr].Len()) 607 } 608 if tx := pool.pending[addr].txs.items[0]; tx.Hash() != tx2.Hash() { 609 t.Errorf("transaction mismatch: have %x, want %x", tx.Hash(), tx2.Hash()) 610 } 611 612 // Add the third transaction and ensure it's not saved (smaller price) 613 pool.add(tx3) 614 <-pool.requestPromoteExecutables(newAccountSet(signer, addr)) 615 if pool.pending[addr].Len() != 1 { 616 t.Error("expected 1 pending transactions, got", pool.pending[addr].Len()) 617 } 618 if tx := pool.pending[addr].txs.items[0]; tx.Hash() != tx2.Hash() { 619 t.Errorf("transaction mismatch: have %x, want %x", tx.Hash(), tx2.Hash()) 620 } 621 // Ensure the total transaction count is correct 622 if pool.all.Count() != 1 { 623 t.Error("expected 1 total transactions, got", pool.all.Count()) 624 } 625 } 626 627 func TestMissingNonce(t *testing.T) { 628 t.Parallel() 629 630 pool, key := setupPool() 631 defer pool.Close() 632 633 addr := crypto.PubkeyToAddress(key.PublicKey) 634 testAddBalance(pool, addr, big.NewInt(100000000000000)) 635 tx := transaction(1, 100000, key) 636 if _, err := pool.add(tx); err != nil { 637 t.Error("didn't expect error", err) 638 } 639 if len(pool.pending) != 0 { 640 t.Error("expected 0 pending transactions, got", len(pool.pending)) 641 } 642 if pool.queue[addr].Len() != 1 { 643 t.Error("expected 1 queued transaction, got", pool.queue[addr].Len()) 644 } 645 if pool.all.Count() != 1 { 646 t.Error("expected 1 total transactions, got", pool.all.Count()) 647 } 648 } 649 650 func TestNonceRecovery(t *testing.T) { 651 t.Parallel() 652 653 const n = 10 654 pool, key := setupPool() 655 defer pool.Close() 656 657 addr := crypto.PubkeyToAddress(key.PublicKey) 658 testSetNonce(pool, addr, n) 659 testAddBalance(pool, addr, big.NewInt(100000000000000)) 660 <-pool.requestReset(nil, nil) 661 662 tx := transaction(n, 100000, key) 663 if err := pool.addRemote(tx); err != nil { 664 t.Error(err) 665 } 666 // simulate some weird re-order of transactions and missing nonce(s) 667 testSetNonce(pool, addr, n-1) 668 <-pool.requestReset(nil, nil) 669 if fn := pool.Nonce(addr); fn != n-1 { 670 t.Errorf("expected nonce to be %d, got %d", n-1, fn) 671 } 672 } 673 674 // Tests that if an account runs out of funds, any pending and queued transactions 675 // are dropped. 676 func TestDropping(t *testing.T) { 677 t.Parallel() 678 679 // Create a test account and fund it 680 pool, key := setupPool() 681 defer pool.Close() 682 683 account := crypto.PubkeyToAddress(key.PublicKey) 684 testAddBalance(pool, account, big.NewInt(1000)) 685 686 // Add some pending and some queued transactions 687 var ( 688 tx0 = transaction(0, 100, key) 689 tx1 = transaction(1, 200, key) 690 tx2 = transaction(2, 300, key) 691 tx10 = transaction(10, 100, key) 692 tx11 = transaction(11, 200, key) 693 tx12 = transaction(12, 300, key) 694 ) 695 pool.all.Add(tx0) 696 pool.priced.Put(tx0) 697 pool.promoteTx(account, tx0.Hash(), tx0) 698 699 pool.all.Add(tx1) 700 pool.priced.Put(tx1) 701 pool.promoteTx(account, tx1.Hash(), tx1) 702 703 pool.all.Add(tx2) 704 pool.priced.Put(tx2) 705 pool.promoteTx(account, tx2.Hash(), tx2) 706 707 pool.enqueueTx(tx10.Hash(), tx10, true) 708 pool.enqueueTx(tx11.Hash(), tx11, true) 709 pool.enqueueTx(tx12.Hash(), tx12, true) 710 711 // Check that pre and post validations leave the pool as is 712 if pool.pending[account].Len() != 3 { 713 t.Errorf("pending transaction mismatch: have %d, want %d", pool.pending[account].Len(), 3) 714 } 715 if pool.queue[account].Len() != 3 { 716 t.Errorf("queued transaction mismatch: have %d, want %d", pool.queue[account].Len(), 3) 717 } 718 if pool.all.Count() != 6 { 719 t.Errorf("total transaction mismatch: have %d, want %d", pool.all.Count(), 6) 720 } 721 <-pool.requestReset(nil, nil) 722 if pool.pending[account].Len() != 3 { 723 t.Errorf("pending transaction mismatch: have %d, want %d", pool.pending[account].Len(), 3) 724 } 725 if pool.queue[account].Len() != 3 { 726 t.Errorf("queued transaction mismatch: have %d, want %d", pool.queue[account].Len(), 3) 727 } 728 if pool.all.Count() != 6 { 729 t.Errorf("total transaction mismatch: have %d, want %d", pool.all.Count(), 6) 730 } 731 // Reduce the balance of the account, and check that invalidated transactions are dropped 732 testAddBalance(pool, account, big.NewInt(-650)) 733 <-pool.requestReset(nil, nil) 734 735 if _, ok := pool.pending[account].txs.items[tx0.Nonce()]; !ok { 736 t.Errorf("funded pending transaction missing: %v", tx0) 737 } 738 if _, ok := pool.pending[account].txs.items[tx1.Nonce()]; !ok { 739 t.Errorf("funded pending transaction missing: %v", tx0) 740 } 741 if _, ok := pool.pending[account].txs.items[tx2.Nonce()]; ok { 742 t.Errorf("out-of-fund pending transaction present: %v", tx1) 743 } 744 if _, ok := pool.queue[account].txs.items[tx10.Nonce()]; !ok { 745 t.Errorf("funded queued transaction missing: %v", tx10) 746 } 747 if _, ok := pool.queue[account].txs.items[tx11.Nonce()]; !ok { 748 t.Errorf("funded queued transaction missing: %v", tx10) 749 } 750 if _, ok := pool.queue[account].txs.items[tx12.Nonce()]; ok { 751 t.Errorf("out-of-fund queued transaction present: %v", tx11) 752 } 753 if pool.all.Count() != 4 { 754 t.Errorf("total transaction mismatch: have %d, want %d", pool.all.Count(), 4) 755 } 756 // Reduce the block gas limit, check that invalidated transactions are dropped 757 pool.chain.(*testBlockChain).gasLimit.Store(100) 758 <-pool.requestReset(nil, nil) 759 760 if _, ok := pool.pending[account].txs.items[tx0.Nonce()]; !ok { 761 t.Errorf("funded pending transaction missing: %v", tx0) 762 } 763 if _, ok := pool.pending[account].txs.items[tx1.Nonce()]; ok { 764 t.Errorf("over-gased pending transaction present: %v", tx1) 765 } 766 if _, ok := pool.queue[account].txs.items[tx10.Nonce()]; !ok { 767 t.Errorf("funded queued transaction missing: %v", tx10) 768 } 769 if _, ok := pool.queue[account].txs.items[tx11.Nonce()]; ok { 770 t.Errorf("over-gased queued transaction present: %v", tx11) 771 } 772 if pool.all.Count() != 2 { 773 t.Errorf("total transaction mismatch: have %d, want %d", pool.all.Count(), 2) 774 } 775 } 776 777 // Tests that if a transaction is dropped from the current pending pool (e.g. out 778 // of fund), all consecutive (still valid, but not executable) transactions are 779 // postponed back into the future queue to prevent broadcasting them. 780 func TestPostponing(t *testing.T) { 781 t.Parallel() 782 783 // Create the pool to test the postponing with 784 statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) 785 blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed)) 786 787 pool := New(testTxPoolConfig, blockchain) 788 pool.Init(testTxPoolConfig.PriceLimit, blockchain.CurrentBlock(), newReserver()) 789 defer pool.Close() 790 791 // Create two test accounts to produce different gap profiles with 792 keys := make([]*ecdsa.PrivateKey, 2) 793 accs := make([]common.Address, len(keys)) 794 795 for i := 0; i < len(keys); i++ { 796 keys[i], _ = crypto.GenerateKey() 797 accs[i] = crypto.PubkeyToAddress(keys[i].PublicKey) 798 799 testAddBalance(pool, crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(50100)) 800 } 801 // Add a batch consecutive pending transactions for validation 802 txs := []*types.Transaction{} 803 for i, key := range keys { 804 for j := 0; j < 100; j++ { 805 var tx *types.Transaction 806 if (i+j)%2 == 0 { 807 tx = transaction(uint64(j), 25000, key) 808 } else { 809 tx = transaction(uint64(j), 50000, key) 810 } 811 txs = append(txs, tx) 812 } 813 } 814 for i, err := range pool.addRemotesSync(txs) { 815 if err != nil { 816 t.Fatalf("tx %d: failed to add transactions: %v", i, err) 817 } 818 } 819 // Check that pre and post validations leave the pool as is 820 if pending := pool.pending[accs[0]].Len() + pool.pending[accs[1]].Len(); pending != len(txs) { 821 t.Errorf("pending transaction mismatch: have %d, want %d", pending, len(txs)) 822 } 823 if len(pool.queue) != 0 { 824 t.Errorf("queued accounts mismatch: have %d, want %d", len(pool.queue), 0) 825 } 826 if pool.all.Count() != len(txs) { 827 t.Errorf("total transaction mismatch: have %d, want %d", pool.all.Count(), len(txs)) 828 } 829 <-pool.requestReset(nil, nil) 830 if pending := pool.pending[accs[0]].Len() + pool.pending[accs[1]].Len(); pending != len(txs) { 831 t.Errorf("pending transaction mismatch: have %d, want %d", pending, len(txs)) 832 } 833 if len(pool.queue) != 0 { 834 t.Errorf("queued accounts mismatch: have %d, want %d", len(pool.queue), 0) 835 } 836 if pool.all.Count() != len(txs) { 837 t.Errorf("total transaction mismatch: have %d, want %d", pool.all.Count(), len(txs)) 838 } 839 // Reduce the balance of the account, and check that transactions are reorganised 840 for _, addr := range accs { 841 testAddBalance(pool, addr, big.NewInt(-1)) 842 } 843 <-pool.requestReset(nil, nil) 844 845 // The first account's first transaction remains valid, check that subsequent 846 // ones are either filtered out, or queued up for later. 847 if _, ok := pool.pending[accs[0]].txs.items[txs[0].Nonce()]; !ok { 848 t.Errorf("tx %d: valid and funded transaction missing from pending pool: %v", 0, txs[0]) 849 } 850 if _, ok := pool.queue[accs[0]].txs.items[txs[0].Nonce()]; ok { 851 t.Errorf("tx %d: valid and funded transaction present in future queue: %v", 0, txs[0]) 852 } 853 for i, tx := range txs[1:100] { 854 if i%2 == 1 { 855 if _, ok := pool.pending[accs[0]].txs.items[tx.Nonce()]; ok { 856 t.Errorf("tx %d: valid but future transaction present in pending pool: %v", i+1, tx) 857 } 858 if _, ok := pool.queue[accs[0]].txs.items[tx.Nonce()]; !ok { 859 t.Errorf("tx %d: valid but future transaction missing from future queue: %v", i+1, tx) 860 } 861 } else { 862 if _, ok := pool.pending[accs[0]].txs.items[tx.Nonce()]; ok { 863 t.Errorf("tx %d: out-of-fund transaction present in pending pool: %v", i+1, tx) 864 } 865 if _, ok := pool.queue[accs[0]].txs.items[tx.Nonce()]; ok { 866 t.Errorf("tx %d: out-of-fund transaction present in future queue: %v", i+1, tx) 867 } 868 } 869 } 870 // The second account's first transaction got invalid, check that all transactions 871 // are either filtered out, or queued up for later. 872 if pool.pending[accs[1]] != nil { 873 t.Errorf("invalidated account still has pending transactions") 874 } 875 for i, tx := range txs[100:] { 876 if i%2 == 1 { 877 if _, ok := pool.queue[accs[1]].txs.items[tx.Nonce()]; !ok { 878 t.Errorf("tx %d: valid but future transaction missing from future queue: %v", 100+i, tx) 879 } 880 } else { 881 if _, ok := pool.queue[accs[1]].txs.items[tx.Nonce()]; ok { 882 t.Errorf("tx %d: out-of-fund transaction present in future queue: %v", 100+i, tx) 883 } 884 } 885 } 886 if pool.all.Count() != len(txs)/2 { 887 t.Errorf("total transaction mismatch: have %d, want %d", pool.all.Count(), len(txs)/2) 888 } 889 } 890 891 // Tests that if the transaction pool has both executable and non-executable 892 // transactions from an origin account, filling the nonce gap moves all queued 893 // ones into the pending pool. 894 func TestGapFilling(t *testing.T) { 895 t.Parallel() 896 897 // Create a test account and fund it 898 pool, key := setupPool() 899 defer pool.Close() 900 901 account := crypto.PubkeyToAddress(key.PublicKey) 902 testAddBalance(pool, account, big.NewInt(1000000)) 903 904 // Keep track of transaction events to ensure all executables get announced 905 events := make(chan core.NewTxsEvent, testTxPoolConfig.AccountQueue+5) 906 sub := pool.txFeed.Subscribe(events) 907 defer sub.Unsubscribe() 908 909 // Create a pending and a queued transaction with a nonce-gap in between 910 pool.addRemotesSync([]*types.Transaction{ 911 transaction(0, 100000, key), 912 transaction(2, 100000, key), 913 }) 914 pending, queued := pool.Stats() 915 if pending != 1 { 916 t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 1) 917 } 918 if queued != 1 { 919 t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 1) 920 } 921 if err := validateEvents(events, 1); err != nil { 922 t.Fatalf("original event firing failed: %v", err) 923 } 924 if err := validatePoolInternals(pool); err != nil { 925 t.Fatalf("pool internal state corrupted: %v", err) 926 } 927 // Fill the nonce gap and ensure all transactions become pending 928 if err := pool.addRemoteSync(transaction(1, 100000, key)); err != nil { 929 t.Fatalf("failed to add gapped transaction: %v", err) 930 } 931 pending, queued = pool.Stats() 932 if pending != 3 { 933 t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 3) 934 } 935 if queued != 0 { 936 t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 0) 937 } 938 if err := validateEvents(events, 2); err != nil { 939 t.Fatalf("gap-filling event firing failed: %v", err) 940 } 941 if err := validatePoolInternals(pool); err != nil { 942 t.Fatalf("pool internal state corrupted: %v", err) 943 } 944 } 945 946 // Tests that if the transaction count belonging to a single account goes above 947 // some threshold, the higher transactions are dropped to prevent DOS attacks. 948 func TestQueueAccountLimiting(t *testing.T) { 949 t.Parallel() 950 951 // Create a test account and fund it 952 pool, key := setupPool() 953 defer pool.Close() 954 955 account := crypto.PubkeyToAddress(key.PublicKey) 956 testAddBalance(pool, account, big.NewInt(1000000)) 957 958 // Keep queuing up transactions and make sure all above a limit are dropped 959 for i := uint64(1); i <= testTxPoolConfig.AccountQueue+5; i++ { 960 if err := pool.addRemoteSync(transaction(i, 100000, key)); err != nil { 961 t.Fatalf("tx %d: failed to add transaction: %v", i, err) 962 } 963 if len(pool.pending) != 0 { 964 t.Errorf("tx %d: pending pool size mismatch: have %d, want %d", i, len(pool.pending), 0) 965 } 966 if i <= testTxPoolConfig.AccountQueue { 967 if pool.queue[account].Len() != int(i) { 968 t.Errorf("tx %d: queue size mismatch: have %d, want %d", i, pool.queue[account].Len(), i) 969 } 970 } else { 971 if pool.queue[account].Len() != int(testTxPoolConfig.AccountQueue) { 972 t.Errorf("tx %d: queue limit mismatch: have %d, want %d", i, pool.queue[account].Len(), testTxPoolConfig.AccountQueue) 973 } 974 } 975 } 976 if pool.all.Count() != int(testTxPoolConfig.AccountQueue) { 977 t.Errorf("total transaction mismatch: have %d, want %d", pool.all.Count(), testTxPoolConfig.AccountQueue) 978 } 979 } 980 981 // Tests that if the transaction count belonging to multiple accounts go above 982 // some threshold, the higher transactions are dropped to prevent DOS attacks. 983 // 984 // This logic should not hold for local transactions, unless the local tracking 985 // mechanism is disabled. 986 func TestQueueGlobalLimiting(t *testing.T) { 987 t.Parallel() 988 989 // Create the pool to test the limit enforcement with 990 statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) 991 blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed)) 992 993 config := testTxPoolConfig 994 config.NoLocals = true 995 config.GlobalQueue = config.AccountQueue*3 - 1 // reduce the queue limits to shorten test time (-1 to make it non divisible) 996 997 pool := New(config, blockchain) 998 pool.Init(testTxPoolConfig.PriceLimit, blockchain.CurrentBlock(), newReserver()) 999 defer pool.Close() 1000 1001 // Create a number of test accounts and fund them (last one will be the local) 1002 keys := make([]*ecdsa.PrivateKey, 5) 1003 for i := 0; i < len(keys); i++ { 1004 keys[i], _ = crypto.GenerateKey() 1005 testAddBalance(pool, crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(1000000)) 1006 } 1007 1008 // Generate and queue a batch of transactions 1009 nonces := make(map[common.Address]uint64) 1010 1011 txs := make(types.Transactions, 0, 3*config.GlobalQueue) 1012 for len(txs) < cap(txs) { 1013 key := keys[rand.Intn(len(keys)-1)] // skip adding transactions with the local account 1014 addr := crypto.PubkeyToAddress(key.PublicKey) 1015 1016 txs = append(txs, transaction(nonces[addr]+1, 100000, key)) 1017 nonces[addr]++ 1018 } 1019 // Import the batch and verify that limits have been enforced 1020 pool.addRemotesSync(txs) 1021 1022 queued := 0 1023 for addr, list := range pool.queue { 1024 if list.Len() > int(config.AccountQueue) { 1025 t.Errorf("addr %x: queued accounts overflown allowance: %d > %d", addr, list.Len(), config.AccountQueue) 1026 } 1027 queued += list.Len() 1028 } 1029 if queued > int(config.GlobalQueue) { 1030 t.Fatalf("total transactions overflow allowance: %d > %d", queued, config.GlobalQueue) 1031 } 1032 } 1033 1034 // Tests that if an account remains idle for a prolonged amount of time, any 1035 // non-executable transactions queued up are dropped to prevent wasting resources 1036 // on shuffling them around. 1037 func TestQueueTimeLimiting(t *testing.T) { 1038 // Reduce the eviction interval to a testable amount 1039 defer func(old time.Duration) { evictionInterval = old }(evictionInterval) 1040 evictionInterval = time.Millisecond * 100 1041 1042 // Create the pool to test the non-expiration enforcement 1043 statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) 1044 blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed)) 1045 1046 config := testTxPoolConfig 1047 config.Lifetime = time.Second 1048 1049 pool := New(config, blockchain) 1050 pool.Init(config.PriceLimit, blockchain.CurrentBlock(), newReserver()) 1051 defer pool.Close() 1052 1053 // Create a test account to ensure remotes expire 1054 remote, _ := crypto.GenerateKey() 1055 1056 testAddBalance(pool, crypto.PubkeyToAddress(remote.PublicKey), big.NewInt(1000000000)) 1057 1058 // Add the transaction and ensure it is queued up 1059 if err := pool.addRemote(pricedTransaction(1, 100000, big.NewInt(1), remote)); err != nil { 1060 t.Fatalf("failed to add remote transaction: %v", err) 1061 } 1062 pending, queued := pool.Stats() 1063 if pending != 0 { 1064 t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 0) 1065 } 1066 if queued != 1 { 1067 t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 2) 1068 } 1069 if err := validatePoolInternals(pool); err != nil { 1070 t.Fatalf("pool internal state corrupted: %v", err) 1071 } 1072 1073 // Allow the eviction interval to run 1074 time.Sleep(2 * evictionInterval) 1075 1076 // Transactions should not be evicted from the queue yet since lifetime duration has not passed 1077 pending, queued = pool.Stats() 1078 if pending != 0 { 1079 t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 0) 1080 } 1081 if queued != 1 { 1082 t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 2) 1083 } 1084 if err := validatePoolInternals(pool); err != nil { 1085 t.Fatalf("pool internal state corrupted: %v", err) 1086 } 1087 1088 // Wait a bit for eviction to run and clean up any leftovers, and ensure only the local remains 1089 time.Sleep(2 * config.Lifetime) 1090 1091 pending, queued = pool.Stats() 1092 if pending != 0 { 1093 t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 0) 1094 } 1095 if queued != 0 { 1096 t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 0) 1097 } 1098 if err := validatePoolInternals(pool); err != nil { 1099 t.Fatalf("pool internal state corrupted: %v", err) 1100 } 1101 1102 // remove current transactions and increase nonce to prepare for a reset and cleanup 1103 statedb.SetNonce(crypto.PubkeyToAddress(remote.PublicKey), 2, tracing.NonceChangeUnspecified) 1104 <-pool.requestReset(nil, nil) 1105 1106 // make sure queue, pending are cleared 1107 pending, queued = pool.Stats() 1108 if pending != 0 { 1109 t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 0) 1110 } 1111 if queued != 0 { 1112 t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 0) 1113 } 1114 if err := validatePoolInternals(pool); err != nil { 1115 t.Fatalf("pool internal state corrupted: %v", err) 1116 } 1117 1118 // Queue gapped transactions 1119 if err := pool.addRemoteSync(pricedTransaction(4, 100000, big.NewInt(1), remote)); err != nil { 1120 t.Fatalf("failed to add remote transaction: %v", err) 1121 } 1122 time.Sleep(5 * evictionInterval) // A half lifetime pass 1123 1124 // Queue executable transactions, the life cycle should be restarted. 1125 if err := pool.addRemoteSync(pricedTransaction(2, 100000, big.NewInt(1), remote)); err != nil { 1126 t.Fatalf("failed to add remote transaction: %v", err) 1127 } 1128 time.Sleep(6 * evictionInterval) 1129 1130 // All gapped transactions shouldn't be kicked out 1131 pending, queued = pool.Stats() 1132 if pending != 1 { 1133 t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 1) 1134 } 1135 if queued != 1 { 1136 t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 1) 1137 } 1138 if err := validatePoolInternals(pool); err != nil { 1139 t.Fatalf("pool internal state corrupted: %v", err) 1140 } 1141 1142 // The whole life time pass after last promotion, kick out stale transactions 1143 time.Sleep(2 * config.Lifetime) 1144 pending, queued = pool.Stats() 1145 if pending != 1 { 1146 t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 1) 1147 } 1148 if queued != 0 { 1149 t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 0) 1150 } 1151 if err := validatePoolInternals(pool); err != nil { 1152 t.Fatalf("pool internal state corrupted: %v", err) 1153 } 1154 } 1155 1156 // Tests that even if the transaction count belonging to a single account goes 1157 // above some threshold, as long as the transactions are executable, they are 1158 // accepted. 1159 func TestPendingLimiting(t *testing.T) { 1160 t.Parallel() 1161 1162 // Create a test account and fund it 1163 pool, key := setupPool() 1164 defer pool.Close() 1165 1166 account := crypto.PubkeyToAddress(key.PublicKey) 1167 testAddBalance(pool, account, big.NewInt(1000000000000)) 1168 1169 // Keep track of transaction events to ensure all executables get announced 1170 events := make(chan core.NewTxsEvent, testTxPoolConfig.AccountQueue+5) 1171 sub := pool.txFeed.Subscribe(events) 1172 defer sub.Unsubscribe() 1173 1174 // Keep queuing up transactions and make sure all above a limit are dropped 1175 for i := uint64(0); i < testTxPoolConfig.AccountQueue+5; i++ { 1176 if err := pool.addRemoteSync(transaction(i, 100000, key)); err != nil { 1177 t.Fatalf("tx %d: failed to add transaction: %v", i, err) 1178 } 1179 if pool.pending[account].Len() != int(i)+1 { 1180 t.Errorf("tx %d: pending pool size mismatch: have %d, want %d", i, pool.pending[account].Len(), i+1) 1181 } 1182 if len(pool.queue) != 0 { 1183 t.Errorf("tx %d: queue size mismatch: have %d, want %d", i, pool.queue[account].Len(), 0) 1184 } 1185 } 1186 if pool.all.Count() != int(testTxPoolConfig.AccountQueue+5) { 1187 t.Errorf("total transaction mismatch: have %d, want %d", pool.all.Count(), testTxPoolConfig.AccountQueue+5) 1188 } 1189 if err := validateEvents(events, int(testTxPoolConfig.AccountQueue+5)); err != nil { 1190 t.Fatalf("event firing failed: %v", err) 1191 } 1192 if err := validatePoolInternals(pool); err != nil { 1193 t.Fatalf("pool internal state corrupted: %v", err) 1194 } 1195 } 1196 1197 // Tests that if the transaction count belonging to multiple accounts go above 1198 // some hard threshold, the higher transactions are dropped to prevent DOS 1199 // attacks. 1200 func TestPendingGlobalLimiting(t *testing.T) { 1201 t.Parallel() 1202 1203 // Create the pool to test the limit enforcement with 1204 statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) 1205 blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed)) 1206 1207 config := testTxPoolConfig 1208 config.GlobalSlots = config.AccountSlots * 10 1209 1210 pool := New(config, blockchain) 1211 pool.Init(config.PriceLimit, blockchain.CurrentBlock(), newReserver()) 1212 defer pool.Close() 1213 1214 // Create a number of test accounts and fund them 1215 keys := make([]*ecdsa.PrivateKey, 5) 1216 for i := 0; i < len(keys); i++ { 1217 keys[i], _ = crypto.GenerateKey() 1218 testAddBalance(pool, crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(1000000)) 1219 } 1220 // Generate and queue a batch of transactions 1221 nonces := make(map[common.Address]uint64) 1222 1223 txs := types.Transactions{} 1224 for _, key := range keys { 1225 addr := crypto.PubkeyToAddress(key.PublicKey) 1226 for j := 0; j < int(config.GlobalSlots)/len(keys)*2; j++ { 1227 txs = append(txs, transaction(nonces[addr], 100000, key)) 1228 nonces[addr]++ 1229 } 1230 } 1231 // Import the batch and verify that limits have been enforced 1232 pool.addRemotesSync(txs) 1233 1234 pending := 0 1235 for _, list := range pool.pending { 1236 pending += list.Len() 1237 } 1238 if pending > int(config.GlobalSlots) { 1239 t.Fatalf("total pending transactions overflow allowance: %d > %d", pending, config.GlobalSlots) 1240 } 1241 if err := validatePoolInternals(pool); err != nil { 1242 t.Fatalf("pool internal state corrupted: %v", err) 1243 } 1244 } 1245 1246 // Test the limit on transaction size is enforced correctly. 1247 // This test verifies every transaction having allowed size 1248 // is added to the pool, and longer transactions are rejected. 1249 func TestAllowedTxSize(t *testing.T) { 1250 t.Parallel() 1251 1252 // Create a test account and fund it 1253 pool, key := setupPool() 1254 defer pool.Close() 1255 1256 account := crypto.PubkeyToAddress(key.PublicKey) 1257 testAddBalance(pool, account, big.NewInt(1000000000)) 1258 1259 // Find the maximum data length for the kind of transaction which will 1260 // be generated in the pool.addRemoteSync calls below. 1261 const largeDataLength = txMaxSize - 200 // enough to have a 5 bytes RLP encoding of the data length number 1262 txWithLargeData := pricedDataTransaction(0, pool.currentHead.Load().GasLimit, big.NewInt(1), key, largeDataLength) 1263 maxTxLengthWithoutData := txWithLargeData.Size() - largeDataLength // 103 bytes 1264 maxTxDataLength := txMaxSize - maxTxLengthWithoutData // 131072 - 103 = 130969 bytes 1265 1266 // Try adding a transaction with maximal allowed size 1267 tx := pricedDataTransaction(0, pool.currentHead.Load().GasLimit, big.NewInt(1), key, maxTxDataLength) 1268 if err := pool.addRemoteSync(tx); err != nil { 1269 t.Fatalf("failed to add transaction of size %d, close to maximal: %v", int(tx.Size()), err) 1270 } 1271 // Try adding a transaction with random allowed size 1272 if err := pool.addRemoteSync(pricedDataTransaction(1, pool.currentHead.Load().GasLimit, big.NewInt(1), key, uint64(rand.Intn(int(maxTxDataLength+1))))); err != nil { 1273 t.Fatalf("failed to add transaction of random allowed size: %v", err) 1274 } 1275 // Try adding a transaction above maximum size by one 1276 if err := pool.addRemoteSync(pricedDataTransaction(2, pool.currentHead.Load().GasLimit, big.NewInt(1), key, maxTxDataLength+1)); err == nil { 1277 t.Fatalf("expected rejection on slightly oversize transaction") 1278 } 1279 // Try adding a transaction above maximum size by more than one 1280 if err := pool.addRemoteSync(pricedDataTransaction(2, pool.currentHead.Load().GasLimit, big.NewInt(1), key, maxTxDataLength+1+uint64(rand.Intn(10*txMaxSize)))); err == nil { 1281 t.Fatalf("expected rejection on oversize transaction") 1282 } 1283 // Run some sanity checks on the pool internals 1284 pending, queued := pool.Stats() 1285 if pending != 2 { 1286 t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 2) 1287 } 1288 if queued != 0 { 1289 t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 0) 1290 } 1291 if err := validatePoolInternals(pool); err != nil { 1292 t.Fatalf("pool internal state corrupted: %v", err) 1293 } 1294 } 1295 1296 // Tests that if transactions start being capped, transactions are also removed from 'all' 1297 func TestCapClearsFromAll(t *testing.T) { 1298 t.Parallel() 1299 1300 // Create the pool to test the limit enforcement with 1301 statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) 1302 blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed)) 1303 1304 config := testTxPoolConfig 1305 config.AccountSlots = 2 1306 config.AccountQueue = 2 1307 config.GlobalSlots = 8 1308 1309 pool := New(config, blockchain) 1310 pool.Init(config.PriceLimit, blockchain.CurrentBlock(), newReserver()) 1311 defer pool.Close() 1312 1313 // Create a number of test accounts and fund them 1314 key, _ := crypto.GenerateKey() 1315 addr := crypto.PubkeyToAddress(key.PublicKey) 1316 testAddBalance(pool, addr, big.NewInt(1000000)) 1317 1318 txs := types.Transactions{} 1319 for j := 0; j < int(config.GlobalSlots)*2; j++ { 1320 txs = append(txs, transaction(uint64(j), 100000, key)) 1321 } 1322 // Import the batch and verify that limits have been enforced 1323 pool.addRemotes(txs) 1324 if err := validatePoolInternals(pool); err != nil { 1325 t.Fatalf("pool internal state corrupted: %v", err) 1326 } 1327 } 1328 1329 // Tests that if the transaction count belonging to multiple accounts go above 1330 // some hard threshold, if they are under the minimum guaranteed slot count then 1331 // the transactions are still kept. 1332 func TestPendingMinimumAllowance(t *testing.T) { 1333 t.Parallel() 1334 1335 // Create the pool to test the limit enforcement with 1336 statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) 1337 blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed)) 1338 1339 config := testTxPoolConfig 1340 config.GlobalSlots = 1 1341 1342 pool := New(config, blockchain) 1343 pool.Init(config.PriceLimit, blockchain.CurrentBlock(), newReserver()) 1344 defer pool.Close() 1345 1346 // Create a number of test accounts and fund them 1347 keys := make([]*ecdsa.PrivateKey, 5) 1348 for i := 0; i < len(keys); i++ { 1349 keys[i], _ = crypto.GenerateKey() 1350 testAddBalance(pool, crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(1000000)) 1351 } 1352 // Generate and queue a batch of transactions 1353 nonces := make(map[common.Address]uint64) 1354 1355 txs := types.Transactions{} 1356 for _, key := range keys { 1357 addr := crypto.PubkeyToAddress(key.PublicKey) 1358 for j := 0; j < int(config.AccountSlots)*2; j++ { 1359 txs = append(txs, transaction(nonces[addr], 100000, key)) 1360 nonces[addr]++ 1361 } 1362 } 1363 // Import the batch and verify that limits have been enforced 1364 pool.addRemotesSync(txs) 1365 1366 for addr, list := range pool.pending { 1367 if list.Len() != int(config.AccountSlots) { 1368 t.Errorf("addr %x: total pending transactions mismatch: have %d, want %d", addr, list.Len(), config.AccountSlots) 1369 } 1370 } 1371 if err := validatePoolInternals(pool); err != nil { 1372 t.Fatalf("pool internal state corrupted: %v", err) 1373 } 1374 } 1375 1376 // Tests that setting the transaction pool gas price to a higher value correctly 1377 // discards everything cheaper than that and moves any gapped transactions back 1378 // from the pending pool to the queue. 1379 func TestRepricing(t *testing.T) { 1380 t.Parallel() 1381 1382 // Create the pool to test the pricing enforcement with 1383 statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) 1384 blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed)) 1385 1386 pool := New(testTxPoolConfig, blockchain) 1387 pool.Init(testTxPoolConfig.PriceLimit, blockchain.CurrentBlock(), newReserver()) 1388 defer pool.Close() 1389 1390 // Keep track of transaction events to ensure all executables get announced 1391 events := make(chan core.NewTxsEvent, 32) 1392 sub := pool.txFeed.Subscribe(events) 1393 defer sub.Unsubscribe() 1394 1395 // Create a number of test accounts and fund them 1396 keys := make([]*ecdsa.PrivateKey, 3) 1397 for i := 0; i < len(keys); i++ { 1398 keys[i], _ = crypto.GenerateKey() 1399 testAddBalance(pool, crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(1000000)) 1400 } 1401 // Generate and queue a batch of transactions, both pending and queued 1402 txs := types.Transactions{} 1403 1404 txs = append(txs, pricedTransaction(0, 100000, big.NewInt(2), keys[0])) 1405 txs = append(txs, pricedTransaction(1, 100000, big.NewInt(1), keys[0])) 1406 txs = append(txs, pricedTransaction(2, 100000, big.NewInt(2), keys[0])) 1407 1408 txs = append(txs, pricedTransaction(0, 100000, big.NewInt(1), keys[1])) 1409 txs = append(txs, pricedTransaction(1, 100000, big.NewInt(2), keys[1])) 1410 txs = append(txs, pricedTransaction(2, 100000, big.NewInt(2), keys[1])) 1411 1412 txs = append(txs, pricedTransaction(1, 100000, big.NewInt(2), keys[2])) 1413 txs = append(txs, pricedTransaction(2, 100000, big.NewInt(1), keys[2])) 1414 txs = append(txs, pricedTransaction(3, 100000, big.NewInt(2), keys[2])) 1415 1416 // Import the batch and that both pending and queued transactions match up 1417 pool.addRemotesSync(txs) 1418 1419 pending, queued := pool.Stats() 1420 if pending != 6 { 1421 t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 6) 1422 } 1423 if queued != 3 { 1424 t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 3) 1425 } 1426 if err := validateEvents(events, 6); err != nil { 1427 t.Fatalf("original event firing failed: %v", err) 1428 } 1429 if err := validatePoolInternals(pool); err != nil { 1430 t.Fatalf("pool internal state corrupted: %v", err) 1431 } 1432 // Reprice the pool and check that underpriced transactions get dropped 1433 pool.SetGasTip(big.NewInt(2)) 1434 1435 pending, queued = pool.Stats() 1436 if pending != 1 { 1437 t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 1) 1438 } 1439 if queued != 5 { 1440 t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 5) 1441 } 1442 if err := validateEvents(events, 0); err != nil { 1443 t.Fatalf("reprice event firing failed: %v", err) 1444 } 1445 if err := validatePoolInternals(pool); err != nil { 1446 t.Fatalf("pool internal state corrupted: %v", err) 1447 } 1448 // Check that we can't add the old transactions back 1449 if err := pool.addRemote(pricedTransaction(1, 100000, big.NewInt(1), keys[0])); !errors.Is(err, txpool.ErrTxGasPriceTooLow) { 1450 t.Fatalf("adding underpriced pending transaction error mismatch: have %v, want %v", err, txpool.ErrTxGasPriceTooLow) 1451 } 1452 if err := pool.addRemote(pricedTransaction(0, 100000, big.NewInt(1), keys[1])); !errors.Is(err, txpool.ErrTxGasPriceTooLow) { 1453 t.Fatalf("adding underpriced pending transaction error mismatch: have %v, want %v", err, txpool.ErrTxGasPriceTooLow) 1454 } 1455 if err := pool.addRemote(pricedTransaction(2, 100000, big.NewInt(1), keys[2])); !errors.Is(err, txpool.ErrTxGasPriceTooLow) { 1456 t.Fatalf("adding underpriced queued transaction error mismatch: have %v, want %v", err, txpool.ErrTxGasPriceTooLow) 1457 } 1458 if err := validateEvents(events, 0); err != nil { 1459 t.Fatalf("post-reprice event firing failed: %v", err) 1460 } 1461 if err := validatePoolInternals(pool); err != nil { 1462 t.Fatalf("pool internal state corrupted: %v", err) 1463 } 1464 // we can fill gaps with properly priced transactions 1465 if err := pool.addRemote(pricedTransaction(1, 100000, big.NewInt(2), keys[0])); err != nil { 1466 t.Fatalf("failed to add pending transaction: %v", err) 1467 } 1468 if err := pool.addRemote(pricedTransaction(0, 100000, big.NewInt(2), keys[1])); err != nil { 1469 t.Fatalf("failed to add pending transaction: %v", err) 1470 } 1471 if err := pool.addRemoteSync(pricedTransaction(2, 100000, big.NewInt(2), keys[2])); err != nil { 1472 t.Fatalf("failed to add queued transaction: %v", err) 1473 } 1474 if err := validateEvents(events, 5); err != nil { 1475 t.Fatalf("post-reprice event firing failed: %v", err) 1476 } 1477 if err := validatePoolInternals(pool); err != nil { 1478 t.Fatalf("pool internal state corrupted: %v", err) 1479 } 1480 } 1481 1482 func TestMinGasPriceEnforced(t *testing.T) { 1483 t.Parallel() 1484 1485 // Create the pool to test the pricing enforcement with 1486 statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) 1487 blockchain := newTestBlockChain(eip1559Config, 10000000, statedb, new(event.Feed)) 1488 1489 txPoolConfig := DefaultConfig 1490 txPoolConfig.NoLocals = true 1491 pool := New(txPoolConfig, blockchain) 1492 pool.Init(txPoolConfig.PriceLimit, blockchain.CurrentBlock(), newReserver()) 1493 defer pool.Close() 1494 1495 key, _ := crypto.GenerateKey() 1496 testAddBalance(pool, crypto.PubkeyToAddress(key.PublicKey), big.NewInt(1000000)) 1497 1498 tx := pricedTransaction(0, 100000, big.NewInt(2), key) 1499 pool.SetGasTip(big.NewInt(tx.GasPrice().Int64() + 1)) 1500 1501 if err := pool.Add([]*types.Transaction{tx}, true)[0]; !errors.Is(err, txpool.ErrTxGasPriceTooLow) { 1502 t.Fatalf("Min tip not enforced") 1503 } 1504 1505 tx = dynamicFeeTx(0, 100000, big.NewInt(3), big.NewInt(2), key) 1506 pool.SetGasTip(big.NewInt(tx.GasTipCap().Int64() + 1)) 1507 1508 if err := pool.Add([]*types.Transaction{tx}, true)[0]; !errors.Is(err, txpool.ErrTxGasPriceTooLow) { 1509 t.Fatalf("Min tip not enforced") 1510 } 1511 } 1512 1513 // Tests that setting the transaction pool gas price to a higher value correctly 1514 // discards everything cheaper (legacy & dynamic fee) than that and moves any 1515 // gapped transactions back from the pending pool to the queue. 1516 // 1517 // Note, local transactions are never allowed to be dropped. 1518 func TestRepricingDynamicFee(t *testing.T) { 1519 t.Parallel() 1520 1521 // Create the pool to test the pricing enforcement with 1522 pool, _ := setupPoolWithConfig(eip1559Config) 1523 defer pool.Close() 1524 1525 // Keep track of transaction events to ensure all executables get announced 1526 events := make(chan core.NewTxsEvent, 32) 1527 sub := pool.txFeed.Subscribe(events) 1528 defer sub.Unsubscribe() 1529 1530 // Create a number of test accounts and fund them 1531 keys := make([]*ecdsa.PrivateKey, 4) 1532 for i := 0; i < len(keys); i++ { 1533 keys[i], _ = crypto.GenerateKey() 1534 testAddBalance(pool, crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(1000000)) 1535 } 1536 // Generate and queue a batch of transactions, both pending and queued 1537 txs := types.Transactions{} 1538 1539 txs = append(txs, pricedTransaction(0, 100000, big.NewInt(2), keys[0])) 1540 txs = append(txs, pricedTransaction(1, 100000, big.NewInt(1), keys[0])) 1541 txs = append(txs, pricedTransaction(2, 100000, big.NewInt(2), keys[0])) 1542 1543 txs = append(txs, dynamicFeeTx(0, 100000, big.NewInt(2), big.NewInt(1), keys[1])) 1544 txs = append(txs, dynamicFeeTx(1, 100000, big.NewInt(3), big.NewInt(2), keys[1])) 1545 txs = append(txs, dynamicFeeTx(2, 100000, big.NewInt(3), big.NewInt(2), keys[1])) 1546 1547 txs = append(txs, dynamicFeeTx(1, 100000, big.NewInt(2), big.NewInt(2), keys[2])) 1548 txs = append(txs, dynamicFeeTx(2, 100000, big.NewInt(1), big.NewInt(1), keys[2])) 1549 txs = append(txs, dynamicFeeTx(3, 100000, big.NewInt(2), big.NewInt(2), keys[2])) 1550 1551 // Import the batch and that both pending and queued transactions match up 1552 pool.addRemotesSync(txs) 1553 1554 pending, queued := pool.Stats() 1555 if pending != 6 { 1556 t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 6) 1557 } 1558 if queued != 3 { 1559 t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 3) 1560 } 1561 if err := validateEvents(events, 6); err != nil { 1562 t.Fatalf("original event firing failed: %v", err) 1563 } 1564 if err := validatePoolInternals(pool); err != nil { 1565 t.Fatalf("pool internal state corrupted: %v", err) 1566 } 1567 // Reprice the pool and check that underpriced transactions get dropped 1568 pool.SetGasTip(big.NewInt(2)) 1569 1570 pending, queued = pool.Stats() 1571 if pending != 1 { 1572 t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 1) 1573 } 1574 if queued != 5 { 1575 t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 5) 1576 } 1577 if err := validateEvents(events, 0); err != nil { 1578 t.Fatalf("reprice event firing failed: %v", err) 1579 } 1580 if err := validatePoolInternals(pool); err != nil { 1581 t.Fatalf("pool internal state corrupted: %v", err) 1582 } 1583 // Check that we can't add the old transactions back 1584 tx := pricedTransaction(1, 100000, big.NewInt(1), keys[0]) 1585 if err := pool.addRemote(tx); !errors.Is(err, txpool.ErrTxGasPriceTooLow) { 1586 t.Fatalf("adding underpriced pending transaction error mismatch: have %v, want %v", err, txpool.ErrTxGasPriceTooLow) 1587 } 1588 tx = dynamicFeeTx(0, 100000, big.NewInt(2), big.NewInt(1), keys[1]) 1589 if err := pool.addRemote(tx); !errors.Is(err, txpool.ErrTxGasPriceTooLow) { 1590 t.Fatalf("adding underpriced pending transaction error mismatch: have %v, want %v", err, txpool.ErrTxGasPriceTooLow) 1591 } 1592 tx = dynamicFeeTx(2, 100000, big.NewInt(1), big.NewInt(1), keys[2]) 1593 if err := pool.addRemote(tx); !errors.Is(err, txpool.ErrTxGasPriceTooLow) { 1594 t.Fatalf("adding underpriced queued transaction error mismatch: have %v, want %v", err, txpool.ErrTxGasPriceTooLow) 1595 } 1596 if err := validateEvents(events, 0); err != nil { 1597 t.Fatalf("post-reprice event firing failed: %v", err) 1598 } 1599 if err := validatePoolInternals(pool); err != nil { 1600 t.Fatalf("pool internal state corrupted: %v", err) 1601 } 1602 1603 // And we can fill gaps with properly priced transactions 1604 tx = pricedTransaction(1, 100000, big.NewInt(2), keys[0]) 1605 if err := pool.addRemote(tx); err != nil { 1606 t.Fatalf("failed to add pending transaction: %v", err) 1607 } 1608 tx = dynamicFeeTx(0, 100000, big.NewInt(3), big.NewInt(2), keys[1]) 1609 if err := pool.addRemote(tx); err != nil { 1610 t.Fatalf("failed to add pending transaction: %v", err) 1611 } 1612 tx = dynamicFeeTx(2, 100000, big.NewInt(2), big.NewInt(2), keys[2]) 1613 if err := pool.addRemoteSync(tx); err != nil { 1614 t.Fatalf("failed to add queued transaction: %v", err) 1615 } 1616 if err := validateEvents(events, 5); err != nil { 1617 t.Fatalf("post-reprice event firing failed: %v", err) 1618 } 1619 if err := validatePoolInternals(pool); err != nil { 1620 t.Fatalf("pool internal state corrupted: %v", err) 1621 } 1622 } 1623 1624 // Tests that when the pool reaches its global transaction limit, underpriced 1625 // transactions are gradually shifted out for more expensive ones and any gapped 1626 // pending transactions are moved into the queue. 1627 // 1628 // Note, local transactions are never allowed to be dropped. 1629 func TestUnderpricing(t *testing.T) { 1630 t.Parallel() 1631 1632 // Create the pool to test the pricing enforcement with 1633 statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) 1634 blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed)) 1635 1636 config := testTxPoolConfig 1637 config.GlobalSlots = 2 1638 config.GlobalQueue = 2 1639 1640 pool := New(config, blockchain) 1641 pool.Init(config.PriceLimit, blockchain.CurrentBlock(), newReserver()) 1642 defer pool.Close() 1643 1644 // Keep track of transaction events to ensure all executables get announced 1645 events := make(chan core.NewTxsEvent, 32) 1646 sub := pool.txFeed.Subscribe(events) 1647 defer sub.Unsubscribe() 1648 1649 // Create a number of test accounts and fund them 1650 keys := make([]*ecdsa.PrivateKey, 5) 1651 for i := 0; i < len(keys); i++ { 1652 keys[i], _ = crypto.GenerateKey() 1653 testAddBalance(pool, crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(10000000)) 1654 } 1655 // Generate and queue a batch of transactions, both pending and queued 1656 txs := types.Transactions{} 1657 1658 txs = append(txs, pricedTransaction(0, 100000, big.NewInt(1), keys[0])) // pending 1659 txs = append(txs, pricedTransaction(1, 100000, big.NewInt(2), keys[0])) // pending 1660 txs = append(txs, pricedTransaction(0, 100000, big.NewInt(1), keys[2])) // pending 1661 1662 txs = append(txs, pricedTransaction(1, 100000, big.NewInt(1), keys[1])) // queued 1663 // Import the batch and that both pending and queued transactions match up 1664 pool.addRemotesSync(txs) 1665 1666 pending, queued := pool.Stats() 1667 if pending != 3 { 1668 t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 3) 1669 } 1670 if queued != 1 { 1671 t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 1) 1672 } 1673 if err := validateEvents(events, 3); err != nil { 1674 t.Fatalf("original event firing failed: %v", err) 1675 } 1676 if err := validatePoolInternals(pool); err != nil { 1677 t.Fatalf("pool internal state corrupted: %v", err) 1678 } 1679 // Ensure that adding an underpriced transaction on block limit fails 1680 if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(1), keys[1])); !errors.Is(err, txpool.ErrUnderpriced) { 1681 t.Fatalf("adding underpriced pending transaction error mismatch: have %v, want %v", err, txpool.ErrUnderpriced) 1682 } 1683 // Replace a future transaction with a future transaction 1684 if err := pool.addRemoteSync(pricedTransaction(1, 100000, big.NewInt(5), keys[1])); err != nil { // +K1:1 => -K1:1 => Pend K0:0, K0:1, K2:0; Que K1:1 1685 t.Fatalf("failed to add well priced transaction: %v", err) 1686 } 1687 // Ensure that adding high priced transactions drops cheap ones, but not own 1688 if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(3), keys[1])); err != nil { // +K1:0 => -K1:1 => Pend K0:0, K0:1, K1:0, K2:0; Que - 1689 t.Fatalf("failed to add well priced transaction: %v", err) 1690 } 1691 if err := pool.addRemoteSync(pricedTransaction(2, 100000, big.NewInt(4), keys[1])); err != nil { // +K1:2 => -K0:0 => Pend K1:0, K2:0; Que K0:1 K1:2 1692 t.Fatalf("failed to add well priced transaction: %v", err) 1693 } 1694 if err := pool.addRemoteSync(pricedTransaction(3, 100000, big.NewInt(5), keys[1])); err != nil { // +K1:3 => -K0:1 => Pend K1:0, K2:0; Que K1:2 K1:3 1695 t.Fatalf("failed to add well priced transaction: %v", err) 1696 } 1697 // Ensure that replacing a pending transaction with a future transaction fails 1698 if err := pool.addRemoteSync(pricedTransaction(5, 100000, big.NewInt(6), keys[1])); !errors.Is(err, ErrFutureReplacePending) { 1699 t.Fatalf("adding future replace transaction error mismatch: have %v, want %v", err, ErrFutureReplacePending) 1700 } 1701 pending, queued = pool.Stats() 1702 if pending != 4 { 1703 t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 4) 1704 } 1705 if queued != 0 { 1706 t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 0) 1707 } 1708 if err := validateEvents(events, 4); err != nil { 1709 t.Fatalf("additional event firing failed: %v", err) 1710 } 1711 if err := validatePoolInternals(pool); err != nil { 1712 t.Fatalf("pool internal state corrupted: %v", err) 1713 } 1714 } 1715 1716 // Tests that more expensive transactions push out cheap ones from the pool, but 1717 // without producing instability by creating gaps that start jumping transactions 1718 // back and forth between queued/pending. 1719 func TestStableUnderpricing(t *testing.T) { 1720 t.Parallel() 1721 1722 // Create the pool to test the pricing enforcement with 1723 statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) 1724 blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed)) 1725 1726 config := testTxPoolConfig 1727 config.GlobalSlots = 128 1728 config.GlobalQueue = 0 1729 1730 pool := New(config, blockchain) 1731 pool.Init(config.PriceLimit, blockchain.CurrentBlock(), newReserver()) 1732 defer pool.Close() 1733 1734 // Keep track of transaction events to ensure all executables get announced 1735 events := make(chan core.NewTxsEvent, 32) 1736 sub := pool.txFeed.Subscribe(events) 1737 defer sub.Unsubscribe() 1738 1739 // Create a number of test accounts and fund them 1740 keys := make([]*ecdsa.PrivateKey, 2) 1741 for i := 0; i < len(keys); i++ { 1742 keys[i], _ = crypto.GenerateKey() 1743 testAddBalance(pool, crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(1000000)) 1744 } 1745 // Fill up the entire queue with the same transaction price points 1746 txs := types.Transactions{} 1747 for i := uint64(0); i < config.GlobalSlots; i++ { 1748 txs = append(txs, pricedTransaction(i, 100000, big.NewInt(1), keys[0])) 1749 } 1750 pool.addRemotesSync(txs) 1751 1752 pending, queued := pool.Stats() 1753 if pending != int(config.GlobalSlots) { 1754 t.Fatalf("pending transactions mismatched: have %d, want %d", pending, config.GlobalSlots) 1755 } 1756 if queued != 0 { 1757 t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 0) 1758 } 1759 if err := validateEvents(events, int(config.GlobalSlots)); err != nil { 1760 t.Fatalf("original event firing failed: %v", err) 1761 } 1762 if err := validatePoolInternals(pool); err != nil { 1763 t.Fatalf("pool internal state corrupted: %v", err) 1764 } 1765 // Ensure that adding high priced transactions drops a cheap, but doesn't produce a gap 1766 if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(3), keys[1])); err != nil { 1767 t.Fatalf("failed to add well priced transaction: %v", err) 1768 } 1769 pending, queued = pool.Stats() 1770 if pending != int(config.GlobalSlots) { 1771 t.Fatalf("pending transactions mismatched: have %d, want %d", pending, config.GlobalSlots) 1772 } 1773 if queued != 0 { 1774 t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 0) 1775 } 1776 if err := validateEvents(events, 1); err != nil { 1777 t.Fatalf("additional event firing failed: %v", err) 1778 } 1779 if err := validatePoolInternals(pool); err != nil { 1780 t.Fatalf("pool internal state corrupted: %v", err) 1781 } 1782 } 1783 1784 // Tests that when the pool reaches its global transaction limit, underpriced 1785 // transactions (legacy & dynamic fee) are gradually shifted out for more 1786 // expensive ones and any gapped pending transactions are moved into the queue. 1787 func TestUnderpricingDynamicFee(t *testing.T) { 1788 t.Parallel() 1789 1790 pool, _ := setupPoolWithConfig(eip1559Config) 1791 defer pool.Close() 1792 1793 pool.config.GlobalSlots = 2 1794 pool.config.GlobalQueue = 2 1795 1796 // Keep track of transaction events to ensure all executables get announced 1797 events := make(chan core.NewTxsEvent, 32) 1798 sub := pool.txFeed.Subscribe(events) 1799 defer sub.Unsubscribe() 1800 1801 // Create a number of test accounts and fund them 1802 keys := make([]*ecdsa.PrivateKey, 4) 1803 for i := 0; i < len(keys); i++ { 1804 keys[i], _ = crypto.GenerateKey() 1805 testAddBalance(pool, crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(1000000)) 1806 } 1807 1808 // Generate and queue a batch of transactions, both pending and queued 1809 txs := types.Transactions{} 1810 1811 txs = append(txs, dynamicFeeTx(0, 100000, big.NewInt(3), big.NewInt(2), keys[0])) // pending 1812 txs = append(txs, pricedTransaction(1, 100000, big.NewInt(2), keys[0])) // pending 1813 txs = append(txs, dynamicFeeTx(1, 100000, big.NewInt(2), big.NewInt(1), keys[1])) // queued 1814 txs = append(txs, dynamicFeeTx(0, 100000, big.NewInt(2), big.NewInt(1), keys[2])) // pending 1815 1816 // Import the batch and check that both pending and queued transactions match up 1817 pool.addRemotesSync(txs) // Pend K0:0, K0:1; Que K1:1 1818 1819 pending, queued := pool.Stats() 1820 if pending != 3 { 1821 t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 3) 1822 } 1823 if queued != 1 { 1824 t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 1) 1825 } 1826 if err := validateEvents(events, 3); err != nil { 1827 t.Fatalf("original event firing failed: %v", err) 1828 } 1829 if err := validatePoolInternals(pool); err != nil { 1830 t.Fatalf("pool internal state corrupted: %v", err) 1831 } 1832 1833 // Ensure that adding an underpriced transaction fails 1834 tx := dynamicFeeTx(0, 100000, big.NewInt(2), big.NewInt(1), keys[1]) 1835 if err := pool.addRemoteSync(tx); !errors.Is(err, txpool.ErrUnderpriced) { // Pend K0:0, K0:1, K2:0; Que K1:1 1836 t.Fatalf("adding underpriced pending transaction error mismatch: have %v, want %v", err, txpool.ErrUnderpriced) 1837 } 1838 1839 // Ensure that adding high priced transactions drops cheap ones, but not own 1840 tx = pricedTransaction(0, 100000, big.NewInt(2), keys[1]) 1841 if err := pool.addRemoteSync(tx); err != nil { // +K1:0, -K1:1 => Pend K0:0, K0:1, K1:0, K2:0; Que - 1842 t.Fatalf("failed to add well priced transaction: %v", err) 1843 } 1844 1845 tx = pricedTransaction(1, 100000, big.NewInt(3), keys[1]) 1846 if err := pool.addRemoteSync(tx); err != nil { // +K1:2, -K0:1 => Pend K0:0 K1:0, K2:0; Que K1:2 1847 t.Fatalf("failed to add well priced transaction: %v", err) 1848 } 1849 tx = dynamicFeeTx(2, 100000, big.NewInt(4), big.NewInt(1), keys[1]) 1850 if err := pool.addRemoteSync(tx); err != nil { // +K1:3, -K1:0 => Pend K0:0 K2:0; Que K1:2 K1:3 1851 t.Fatalf("failed to add well priced transaction: %v", err) 1852 } 1853 pending, queued = pool.Stats() 1854 if pending != 4 { 1855 t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 4) 1856 } 1857 if queued != 0 { 1858 t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 0) 1859 } 1860 if err := validateEvents(events, 3); err != nil { 1861 t.Fatalf("additional event firing failed: %v", err) 1862 } 1863 if err := validatePoolInternals(pool); err != nil { 1864 t.Fatalf("pool internal state corrupted: %v", err) 1865 } 1866 } 1867 1868 // Tests whether highest fee cap transaction is retained after a batch of high effective 1869 // tip transactions are added and vice versa 1870 func TestDualHeapEviction(t *testing.T) { 1871 t.Parallel() 1872 1873 pool, _ := setupPoolWithConfig(eip1559Config) 1874 defer pool.Close() 1875 1876 pool.config.GlobalSlots = 10 1877 pool.config.GlobalQueue = 10 1878 1879 var ( 1880 highTip, highCap *types.Transaction 1881 baseFee int 1882 ) 1883 1884 check := func(tx *types.Transaction, name string) { 1885 if pool.all.Get(tx.Hash()) == nil { 1886 t.Fatalf("highest %s transaction evicted from the pool", name) 1887 } 1888 } 1889 1890 add := func(urgent bool) { 1891 for i := 0; i < 20; i++ { 1892 var tx *types.Transaction 1893 // Create a test accounts and fund it 1894 key, _ := crypto.GenerateKey() 1895 testAddBalance(pool, crypto.PubkeyToAddress(key.PublicKey), big.NewInt(1000000000000)) 1896 if urgent { 1897 tx = dynamicFeeTx(0, 100000, big.NewInt(int64(baseFee+1+i)), big.NewInt(int64(1+i)), key) 1898 highTip = tx 1899 } else { 1900 tx = dynamicFeeTx(0, 100000, big.NewInt(int64(baseFee+200+i)), big.NewInt(1), key) 1901 highCap = tx 1902 } 1903 pool.addRemotesSync([]*types.Transaction{tx}) 1904 } 1905 pending, queued := pool.Stats() 1906 if pending+queued != 20 { 1907 t.Fatalf("transaction count mismatch: have %d, want %d", pending+queued, 10) 1908 } 1909 } 1910 1911 add(false) 1912 for baseFee = 0; baseFee <= 1000; baseFee += 100 { 1913 pool.priced.SetBaseFee(big.NewInt(int64(baseFee))) 1914 add(true) 1915 check(highCap, "fee cap") 1916 add(false) 1917 check(highTip, "effective tip") 1918 } 1919 1920 if err := validatePoolInternals(pool); err != nil { 1921 t.Fatalf("pool internal state corrupted: %v", err) 1922 } 1923 } 1924 1925 // Tests that the pool rejects duplicate transactions. 1926 func TestDeduplication(t *testing.T) { 1927 t.Parallel() 1928 1929 // Create the pool to test the pricing enforcement with 1930 statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) 1931 blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed)) 1932 1933 pool := New(testTxPoolConfig, blockchain) 1934 pool.Init(testTxPoolConfig.PriceLimit, blockchain.CurrentBlock(), newReserver()) 1935 defer pool.Close() 1936 1937 // Create a test account to add transactions with 1938 key, _ := crypto.GenerateKey() 1939 testAddBalance(pool, crypto.PubkeyToAddress(key.PublicKey), big.NewInt(1000000000)) 1940 1941 // Create a batch of transactions and add a few of them 1942 txs := make([]*types.Transaction, 16) 1943 for i := 0; i < len(txs); i++ { 1944 txs[i] = pricedTransaction(uint64(i), 100000, big.NewInt(1), key) 1945 } 1946 var firsts []*types.Transaction 1947 for i := 0; i < len(txs); i += 2 { 1948 firsts = append(firsts, txs[i]) 1949 } 1950 errs := pool.addRemotesSync(firsts) 1951 if len(errs) != len(firsts) { 1952 t.Fatalf("first add mismatching result count: have %d, want %d", len(errs), len(firsts)) 1953 } 1954 for i, err := range errs { 1955 if err != nil { 1956 t.Errorf("add %d failed: %v", i, err) 1957 } 1958 } 1959 pending, queued := pool.Stats() 1960 if pending != 1 { 1961 t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 1) 1962 } 1963 if queued != len(txs)/2-1 { 1964 t.Fatalf("queued transactions mismatched: have %d, want %d", queued, len(txs)/2-1) 1965 } 1966 // Try to add all of them now and ensure previous ones error out as knowns 1967 errs = pool.addRemotesSync(txs) 1968 if len(errs) != len(txs) { 1969 t.Fatalf("all add mismatching result count: have %d, want %d", len(errs), len(txs)) 1970 } 1971 for i, err := range errs { 1972 if i%2 == 0 && err == nil { 1973 t.Errorf("add %d succeeded, should have failed as known", i) 1974 } 1975 if i%2 == 1 && err != nil { 1976 t.Errorf("add %d failed: %v", i, err) 1977 } 1978 } 1979 pending, queued = pool.Stats() 1980 if pending != len(txs) { 1981 t.Fatalf("pending transactions mismatched: have %d, want %d", pending, len(txs)) 1982 } 1983 if queued != 0 { 1984 t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 0) 1985 } 1986 if err := validatePoolInternals(pool); err != nil { 1987 t.Fatalf("pool internal state corrupted: %v", err) 1988 } 1989 } 1990 1991 // Tests that the pool rejects replacement transactions that don't meet the minimum 1992 // price bump required. 1993 func TestReplacement(t *testing.T) { 1994 t.Parallel() 1995 1996 // Create the pool to test the pricing enforcement with 1997 statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) 1998 blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed)) 1999 2000 pool := New(testTxPoolConfig, blockchain) 2001 pool.Init(testTxPoolConfig.PriceLimit, blockchain.CurrentBlock(), newReserver()) 2002 defer pool.Close() 2003 2004 // Keep track of transaction events to ensure all executables get announced 2005 events := make(chan core.NewTxsEvent, 32) 2006 sub := pool.txFeed.Subscribe(events) 2007 defer sub.Unsubscribe() 2008 2009 // Create a test account to add transactions with 2010 key, _ := crypto.GenerateKey() 2011 testAddBalance(pool, crypto.PubkeyToAddress(key.PublicKey), big.NewInt(1000000000)) 2012 2013 // Add pending transactions, ensuring the minimum price bump is enforced for replacement (for ultra low prices too) 2014 price := int64(100) 2015 threshold := (price * (100 + int64(testTxPoolConfig.PriceBump))) / 100 2016 2017 if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(1), key)); err != nil { 2018 t.Fatalf("failed to add original cheap pending transaction: %v", err) 2019 } 2020 if err := pool.addRemote(pricedTransaction(0, 100001, big.NewInt(1), key)); !errors.Is(err, txpool.ErrReplaceUnderpriced) { 2021 t.Fatalf("original cheap pending transaction replacement error mismatch: have %v, want %v", err, txpool.ErrReplaceUnderpriced) 2022 } 2023 if err := pool.addRemote(pricedTransaction(0, 100000, big.NewInt(2), key)); err != nil { 2024 t.Fatalf("failed to replace original cheap pending transaction: %v", err) 2025 } 2026 if err := validateEvents(events, 2); err != nil { 2027 t.Fatalf("cheap replacement event firing failed: %v", err) 2028 } 2029 2030 if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(price), key)); err != nil { 2031 t.Fatalf("failed to add original proper pending transaction: %v", err) 2032 } 2033 if err := pool.addRemote(pricedTransaction(0, 100001, big.NewInt(threshold-1), key)); !errors.Is(err, txpool.ErrReplaceUnderpriced) { 2034 t.Fatalf("original proper pending transaction replacement error mismatch: have %v, want %v", err, txpool.ErrReplaceUnderpriced) 2035 } 2036 if err := pool.addRemote(pricedTransaction(0, 100000, big.NewInt(threshold), key)); err != nil { 2037 t.Fatalf("failed to replace original proper pending transaction: %v", err) 2038 } 2039 if err := validateEvents(events, 2); err != nil { 2040 t.Fatalf("proper replacement event firing failed: %v", err) 2041 } 2042 2043 // Add queued transactions, ensuring the minimum price bump is enforced for replacement (for ultra low prices too) 2044 if err := pool.addRemote(pricedTransaction(2, 100000, big.NewInt(1), key)); err != nil { 2045 t.Fatalf("failed to add original cheap queued transaction: %v", err) 2046 } 2047 if err := pool.addRemote(pricedTransaction(2, 100001, big.NewInt(1), key)); !errors.Is(err, txpool.ErrReplaceUnderpriced) { 2048 t.Fatalf("original cheap queued transaction replacement error mismatch: have %v, want %v", err, txpool.ErrReplaceUnderpriced) 2049 } 2050 if err := pool.addRemote(pricedTransaction(2, 100000, big.NewInt(2), key)); err != nil { 2051 t.Fatalf("failed to replace original cheap queued transaction: %v", err) 2052 } 2053 2054 if err := pool.addRemote(pricedTransaction(2, 100000, big.NewInt(price), key)); err != nil { 2055 t.Fatalf("failed to add original proper queued transaction: %v", err) 2056 } 2057 if err := pool.addRemote(pricedTransaction(2, 100001, big.NewInt(threshold-1), key)); !errors.Is(err, txpool.ErrReplaceUnderpriced) { 2058 t.Fatalf("original proper queued transaction replacement error mismatch: have %v, want %v", err, txpool.ErrReplaceUnderpriced) 2059 } 2060 if err := pool.addRemote(pricedTransaction(2, 100000, big.NewInt(threshold), key)); err != nil { 2061 t.Fatalf("failed to replace original proper queued transaction: %v", err) 2062 } 2063 2064 if err := validateEvents(events, 0); err != nil { 2065 t.Fatalf("queued replacement event firing failed: %v", err) 2066 } 2067 if err := validatePoolInternals(pool); err != nil { 2068 t.Fatalf("pool internal state corrupted: %v", err) 2069 } 2070 } 2071 2072 // Tests that the pool rejects replacement dynamic fee transactions that don't 2073 // meet the minimum price bump required. 2074 func TestReplacementDynamicFee(t *testing.T) { 2075 t.Parallel() 2076 2077 // Create the pool to test the pricing enforcement with 2078 pool, key := setupPoolWithConfig(eip1559Config) 2079 defer pool.Close() 2080 testAddBalance(pool, crypto.PubkeyToAddress(key.PublicKey), big.NewInt(1000000000)) 2081 2082 // Keep track of transaction events to ensure all executables get announced 2083 events := make(chan core.NewTxsEvent, 32) 2084 sub := pool.txFeed.Subscribe(events) 2085 defer sub.Unsubscribe() 2086 2087 // Add pending transactions, ensuring the minimum price bump is enforced for replacement (for ultra low prices too) 2088 gasFeeCap := int64(100) 2089 feeCapThreshold := (gasFeeCap * (100 + int64(testTxPoolConfig.PriceBump))) / 100 2090 gasTipCap := int64(60) 2091 tipThreshold := (gasTipCap * (100 + int64(testTxPoolConfig.PriceBump))) / 100 2092 2093 // Run the following identical checks for both the pending and queue pools: 2094 // 1. Send initial tx => accept 2095 // 2. Don't bump tip or fee cap => discard 2096 // 3. Bump both more than min => accept 2097 // 4. Check events match expected (2 new executable txs during pending, 0 during queue) 2098 // 5. Send new tx with larger tip and gasFeeCap => accept 2099 // 6. Bump tip max allowed so it's still underpriced => discard 2100 // 7. Bump fee cap max allowed so it's still underpriced => discard 2101 // 8. Bump tip min for acceptance => discard 2102 // 9. Bump feecap min for acceptance => discard 2103 // 10. Bump feecap and tip min for acceptance => accept 2104 // 11. Check events match expected (2 new executable txs during pending, 0 during queue) 2105 stages := []string{"pending", "queued"} 2106 for _, stage := range stages { 2107 // Since state is empty, 0 nonce txs are "executable" and can go 2108 // into pending immediately. 2 nonce txs are "gapped" 2109 nonce := uint64(0) 2110 if stage == "queued" { 2111 nonce = 2 2112 } 2113 2114 // 1. Send initial tx => accept 2115 tx := dynamicFeeTx(nonce, 100000, big.NewInt(2), big.NewInt(1), key) 2116 if err := pool.addRemoteSync(tx); err != nil { 2117 t.Fatalf("failed to add original cheap %s transaction: %v", stage, err) 2118 } 2119 // 2. Don't bump tip or feecap => discard 2120 tx = dynamicFeeTx(nonce, 100001, big.NewInt(2), big.NewInt(1), key) 2121 if err := pool.addRemote(tx); !errors.Is(err, txpool.ErrReplaceUnderpriced) { 2122 t.Fatalf("original cheap %s transaction replacement error mismatch: have %v, want %v", stage, err, txpool.ErrReplaceUnderpriced) 2123 } 2124 // 3. Bump both more than min => accept 2125 tx = dynamicFeeTx(nonce, 100000, big.NewInt(3), big.NewInt(2), key) 2126 if err := pool.addRemote(tx); err != nil { 2127 t.Fatalf("failed to replace original cheap %s transaction: %v", stage, err) 2128 } 2129 // 4. Check events match expected (2 new executable txs during pending, 0 during queue) 2130 count := 2 2131 if stage == "queued" { 2132 count = 0 2133 } 2134 if err := validateEvents(events, count); err != nil { 2135 t.Fatalf("cheap %s replacement event firing failed: %v", stage, err) 2136 } 2137 // 5. Send new tx with larger tip and feeCap => accept 2138 tx = dynamicFeeTx(nonce, 100000, big.NewInt(gasFeeCap), big.NewInt(gasTipCap), key) 2139 if err := pool.addRemoteSync(tx); err != nil { 2140 t.Fatalf("failed to add original proper %s transaction: %v", stage, err) 2141 } 2142 2143 // 6. Bump tip max allowed so it's still underpriced => discard 2144 tx = dynamicFeeTx(nonce, 100000, big.NewInt(gasFeeCap), big.NewInt(tipThreshold-1), key) 2145 if err := pool.addRemote(tx); !errors.Is(err, txpool.ErrReplaceUnderpriced) { 2146 t.Fatalf("original proper %s transaction replacement error mismatch: have %v, want %v", stage, err, txpool.ErrReplaceUnderpriced) 2147 } 2148 // 7. Bump fee cap max allowed so it's still underpriced => discard 2149 tx = dynamicFeeTx(nonce, 100000, big.NewInt(feeCapThreshold-1), big.NewInt(gasTipCap), key) 2150 if err := pool.addRemote(tx); !errors.Is(err, txpool.ErrReplaceUnderpriced) { 2151 t.Fatalf("original proper %s transaction replacement error mismatch: have %v, want %v", stage, err, txpool.ErrReplaceUnderpriced) 2152 } 2153 // 8. Bump tip min for acceptance => accept 2154 tx = dynamicFeeTx(nonce, 100000, big.NewInt(gasFeeCap), big.NewInt(tipThreshold), key) 2155 if err := pool.addRemote(tx); !errors.Is(err, txpool.ErrReplaceUnderpriced) { 2156 t.Fatalf("original proper %s transaction replacement error mismatch: have %v, want %v", stage, err, txpool.ErrReplaceUnderpriced) 2157 } 2158 // 9. Bump fee cap min for acceptance => accept 2159 tx = dynamicFeeTx(nonce, 100000, big.NewInt(feeCapThreshold), big.NewInt(gasTipCap), key) 2160 if err := pool.addRemote(tx); !errors.Is(err, txpool.ErrReplaceUnderpriced) { 2161 t.Fatalf("original proper %s transaction replacement error mismatch: have %v, want %v", stage, err, txpool.ErrReplaceUnderpriced) 2162 } 2163 // 10. Check events match expected (3 new executable txs during pending, 0 during queue) 2164 tx = dynamicFeeTx(nonce, 100000, big.NewInt(feeCapThreshold), big.NewInt(tipThreshold), key) 2165 if err := pool.addRemote(tx); err != nil { 2166 t.Fatalf("failed to replace original cheap %s transaction: %v", stage, err) 2167 } 2168 // 11. Check events match expected (3 new executable txs during pending, 0 during queue) 2169 count = 2 2170 if stage == "queued" { 2171 count = 0 2172 } 2173 if err := validateEvents(events, count); err != nil { 2174 t.Fatalf("replacement %s event firing failed: %v", stage, err) 2175 } 2176 } 2177 2178 if err := validatePoolInternals(pool); err != nil { 2179 t.Fatalf("pool internal state corrupted: %v", err) 2180 } 2181 } 2182 2183 // TestStatusCheck tests that the pool can correctly retrieve the 2184 // pending status of individual transactions. 2185 func TestStatusCheck(t *testing.T) { 2186 t.Parallel() 2187 2188 // Create the pool to test the status retrievals with 2189 statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) 2190 blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed)) 2191 2192 pool := New(testTxPoolConfig, blockchain) 2193 pool.Init(testTxPoolConfig.PriceLimit, blockchain.CurrentBlock(), newReserver()) 2194 defer pool.Close() 2195 2196 // Create the test accounts to check various transaction statuses with 2197 keys := make([]*ecdsa.PrivateKey, 3) 2198 for i := 0; i < len(keys); i++ { 2199 keys[i], _ = crypto.GenerateKey() 2200 testAddBalance(pool, crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(1000000)) 2201 } 2202 // Generate and queue a batch of transactions, both pending and queued 2203 txs := types.Transactions{} 2204 2205 txs = append(txs, pricedTransaction(0, 100000, big.NewInt(1), keys[0])) // Pending only 2206 txs = append(txs, pricedTransaction(0, 100000, big.NewInt(1), keys[1])) // Pending and queued 2207 txs = append(txs, pricedTransaction(2, 100000, big.NewInt(1), keys[1])) 2208 txs = append(txs, pricedTransaction(2, 100000, big.NewInt(1), keys[2])) // Queued only 2209 2210 // Import the transaction and ensure they are correctly added 2211 pool.addRemotesSync(txs) 2212 2213 pending, queued := pool.Stats() 2214 if pending != 2 { 2215 t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 2) 2216 } 2217 if queued != 2 { 2218 t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 2) 2219 } 2220 if err := validatePoolInternals(pool); err != nil { 2221 t.Fatalf("pool internal state corrupted: %v", err) 2222 } 2223 // Retrieve the status of each transaction and validate them 2224 hashes := make([]common.Hash, len(txs)) 2225 for i, tx := range txs { 2226 hashes[i] = tx.Hash() 2227 } 2228 hashes = append(hashes, common.Hash{}) 2229 expect := []txpool.TxStatus{txpool.TxStatusPending, txpool.TxStatusPending, txpool.TxStatusQueued, txpool.TxStatusQueued, txpool.TxStatusUnknown} 2230 2231 for i := 0; i < len(hashes); i++ { 2232 if status := pool.Status(hashes[i]); status != expect[i] { 2233 t.Errorf("transaction %d: status mismatch: have %v, want %v", i, status, expect[i]) 2234 } 2235 } 2236 } 2237 2238 // Test the transaction slots consumption is computed correctly 2239 func TestSlotCount(t *testing.T) { 2240 t.Parallel() 2241 2242 key, _ := crypto.GenerateKey() 2243 2244 // Check that an empty transaction consumes a single slot 2245 smallTx := pricedDataTransaction(0, 0, big.NewInt(0), key, 0) 2246 if slots := numSlots(smallTx); slots != 1 { 2247 t.Fatalf("small transactions slot count mismatch: have %d want %d", slots, 1) 2248 } 2249 // Check that a large transaction consumes the correct number of slots 2250 bigTx := pricedDataTransaction(0, 0, big.NewInt(0), key, uint64(10*txSlotSize)) 2251 if slots := numSlots(bigTx); slots != 11 { 2252 t.Fatalf("big transactions slot count mismatch: have %d want %d", slots, 11) 2253 } 2254 } 2255 2256 // TestSetCodeTransactions tests a few scenarios regarding the EIP-7702 2257 // SetCodeTx. 2258 func TestSetCodeTransactions(t *testing.T) { 2259 t.Parallel() 2260 2261 // Create the pool to test the status retrievals with 2262 statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) 2263 blockchain := newTestBlockChain(params.MergedTestChainConfig, 1000000, statedb, new(event.Feed)) 2264 2265 pool := New(testTxPoolConfig, blockchain) 2266 pool.Init(testTxPoolConfig.PriceLimit, blockchain.CurrentBlock(), newReserver()) 2267 defer pool.Close() 2268 2269 // Create the test accounts 2270 var ( 2271 keyA, _ = crypto.GenerateKey() 2272 keyB, _ = crypto.GenerateKey() 2273 keyC, _ = crypto.GenerateKey() 2274 addrA = crypto.PubkeyToAddress(keyA.PublicKey) 2275 addrB = crypto.PubkeyToAddress(keyB.PublicKey) 2276 addrC = crypto.PubkeyToAddress(keyC.PublicKey) 2277 ) 2278 testAddBalance(pool, addrA, big.NewInt(params.Ether)) 2279 testAddBalance(pool, addrB, big.NewInt(params.Ether)) 2280 testAddBalance(pool, addrC, big.NewInt(params.Ether)) 2281 2282 for _, tt := range []struct { 2283 name string 2284 pending int 2285 queued int 2286 run func(string) 2287 }{ 2288 { 2289 // Check that only one in-flight transaction is allowed for accounts 2290 // with delegation set. 2291 name: "accept-one-inflight-tx-of-delegated-account", 2292 pending: 1, 2293 run: func(name string) { 2294 aa := common.Address{0xaa, 0xaa} 2295 statedb.SetCode(addrA, append(types.DelegationPrefix, aa.Bytes()...)) 2296 statedb.SetCode(aa, []byte{byte(vm.ADDRESS), byte(vm.PUSH0), byte(vm.SSTORE)}) 2297 2298 // Send gapped transaction, it should be rejected. 2299 if err := pool.addRemoteSync(pricedTransaction(2, 100000, big.NewInt(1), keyA)); !errors.Is(err, ErrOutOfOrderTxFromDelegated) { 2300 t.Fatalf("%s: error mismatch: want %v, have %v", name, ErrOutOfOrderTxFromDelegated, err) 2301 } 2302 // Send transactions. First is accepted, second is rejected. 2303 if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(1), keyA)); err != nil { 2304 t.Fatalf("%s: failed to add remote transaction: %v", name, err) 2305 } 2306 // Second and further transactions shall be rejected 2307 if err := pool.addRemoteSync(pricedTransaction(1, 100000, big.NewInt(1), keyA)); !errors.Is(err, txpool.ErrInflightTxLimitReached) { 2308 t.Fatalf("%s: error mismatch: want %v, have %v", name, txpool.ErrInflightTxLimitReached, err) 2309 } 2310 // Check gapped transaction again. 2311 if err := pool.addRemoteSync(pricedTransaction(2, 100000, big.NewInt(1), keyA)); !errors.Is(err, txpool.ErrInflightTxLimitReached) { 2312 t.Fatalf("%s: error mismatch: want %v, have %v", name, txpool.ErrInflightTxLimitReached, err) 2313 } 2314 // Replace by fee. 2315 if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(10), keyA)); err != nil { 2316 t.Fatalf("%s: failed to replace with remote transaction: %v", name, err) 2317 } 2318 2319 // Reset the delegation, avoid leaking state into the other tests 2320 statedb.SetCode(addrA, nil) 2321 }, 2322 }, 2323 { 2324 // This test is analogous to the previous one, but the delegation is pending 2325 // instead of set. 2326 name: "allow-one-tx-from-pooled-delegation", 2327 pending: 2, 2328 run: func(name string) { 2329 // Create a pending delegation request from B. 2330 if err := pool.addRemoteSync(setCodeTx(0, keyA, []unsignedAuth{{0, keyB}})); err != nil { 2331 t.Fatalf("%s: failed to add with remote setcode transaction: %v", name, err) 2332 } 2333 // First transaction from B is accepted. 2334 if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(1), keyB)); err != nil { 2335 t.Fatalf("%s: failed to add remote transaction: %v", name, err) 2336 } 2337 // Second transaction fails due to limit. 2338 if err := pool.addRemoteSync(pricedTransaction(1, 100000, big.NewInt(1), keyB)); !errors.Is(err, txpool.ErrInflightTxLimitReached) { 2339 t.Fatalf("%s: error mismatch: want %v, have %v", name, txpool.ErrInflightTxLimitReached, err) 2340 } 2341 // Replace by fee for first transaction from B works. 2342 if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(2), keyB)); err != nil { 2343 t.Fatalf("%s: failed to add remote transaction: %v", name, err) 2344 } 2345 }, 2346 }, 2347 { 2348 // This is the symmetric case of the previous one, where the delegation request 2349 // is received after the transaction. The resulting state shall be the same. 2350 name: "accept-authorization-from-sender-of-one-inflight-tx", 2351 pending: 2, 2352 run: func(name string) { 2353 // The first in-flight transaction is accepted. 2354 if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(1), keyB)); err != nil { 2355 t.Fatalf("%s: failed to add with pending delegation: %v", name, err) 2356 } 2357 // Delegation is accepted. 2358 if err := pool.addRemoteSync(setCodeTx(0, keyA, []unsignedAuth{{0, keyB}})); err != nil { 2359 t.Fatalf("%s: failed to add remote transaction: %v", name, err) 2360 } 2361 // The second in-flight transaction is rejected. 2362 if err := pool.addRemoteSync(pricedTransaction(1, 100000, big.NewInt(1), keyB)); !errors.Is(err, txpool.ErrInflightTxLimitReached) { 2363 t.Fatalf("%s: error mismatch: want %v, have %v", name, txpool.ErrInflightTxLimitReached, err) 2364 } 2365 }, 2366 }, 2367 { 2368 name: "reject-authorization-from-sender-with-more-than-one-inflight-tx", 2369 pending: 2, 2370 run: func(name string) { 2371 // Submit two transactions. 2372 if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(1), keyB)); err != nil { 2373 t.Fatalf("%s: failed to add with pending delegation: %v", name, err) 2374 } 2375 if err := pool.addRemoteSync(pricedTransaction(1, 100000, big.NewInt(1), keyB)); err != nil { 2376 t.Fatalf("%s: failed to add with pending delegation: %v", name, err) 2377 } 2378 // Delegation rejected since two txs are already in-flight. 2379 if err := pool.addRemoteSync(setCodeTx(0, keyA, []unsignedAuth{{0, keyB}})); !errors.Is(err, ErrAuthorityReserved) { 2380 t.Fatalf("%s: error mismatch: want %v, have %v", name, ErrAuthorityReserved, err) 2381 } 2382 }, 2383 }, 2384 { 2385 name: "allow-setcode-tx-with-pending-authority-tx", 2386 pending: 2, 2387 run: func(name string) { 2388 // Send two transactions where the first has no conflicting delegations and 2389 // the second should be allowed despite conflicting with the authorities in the first. 2390 if err := pool.addRemoteSync(setCodeTx(0, keyA, []unsignedAuth{{1, keyC}})); err != nil { 2391 t.Fatalf("%s: failed to add with remote setcode transaction: %v", name, err) 2392 } 2393 if err := pool.addRemoteSync(setCodeTx(0, keyB, []unsignedAuth{{1, keyC}})); err != nil { 2394 t.Fatalf("%s: failed to add conflicting delegation: %v", name, err) 2395 } 2396 }, 2397 }, 2398 { 2399 name: "replace-by-fee-setcode-tx", 2400 pending: 1, 2401 run: func(name string) { 2402 if err := pool.addRemoteSync(setCodeTx(0, keyB, []unsignedAuth{{1, keyC}})); err != nil { 2403 t.Fatalf("%s: failed to add with remote setcode transaction: %v", name, err) 2404 } 2405 if err := pool.addRemoteSync(pricedSetCodeTx(0, 250000, uint256.NewInt(2000), uint256.NewInt(2), keyB, []unsignedAuth{{0, keyC}})); err != nil { 2406 t.Fatalf("%s: failed to add with remote setcode transaction: %v", name, err) 2407 } 2408 }, 2409 }, 2410 { 2411 name: "allow-more-than-one-tx-from-replaced-authority", 2412 pending: 3, 2413 run: func(name string) { 2414 // Send transaction from A with B as an authority. 2415 if err := pool.addRemoteSync(pricedSetCodeTx(0, 250000, uint256.NewInt(10), uint256.NewInt(3), keyA, []unsignedAuth{{0, keyB}})); err != nil { 2416 t.Fatalf("%s: failed to add with remote setcode transaction: %v", name, err) 2417 } 2418 // Replace transaction with another having C as an authority. 2419 if err := pool.addRemoteSync(pricedSetCodeTx(0, 250000, uint256.NewInt(3000), uint256.NewInt(300), keyA, []unsignedAuth{{0, keyC}})); err != nil { 2420 t.Fatalf("%s: failed to add with remote setcode transaction: %v", name, err) 2421 } 2422 // B should not be considred as having an in-flight delegation, so 2423 // should allow more than one pooled transaction. 2424 if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(10), keyB)); err != nil { 2425 t.Fatalf("%s: failed to replace with remote transaction: %v", name, err) 2426 } 2427 if err := pool.addRemoteSync(pricedTransaction(1, 100000, big.NewInt(10), keyB)); err != nil { 2428 t.Fatalf("%s: failed to replace with remote transaction: %v", name, err) 2429 } 2430 }, 2431 }, 2432 { 2433 // This test is analogous to the previous one, but the the replaced 2434 // transaction is self-sponsored. 2435 name: "allow-tx-from-replaced-self-sponsor-authority", 2436 pending: 3, 2437 run: func(name string) { 2438 // Send transaction from A with A as an authority. 2439 if err := pool.addRemoteSync(pricedSetCodeTx(0, 250000, uint256.NewInt(10), uint256.NewInt(3), keyA, []unsignedAuth{{0, keyA}})); err != nil { 2440 t.Fatalf("%s: failed to add with remote setcode transaction: %v", name, err) 2441 } 2442 // Replace transaction with a transaction with B as an authority. 2443 if err := pool.addRemoteSync(pricedSetCodeTx(0, 250000, uint256.NewInt(30), uint256.NewInt(30), keyA, []unsignedAuth{{0, keyB}})); err != nil { 2444 t.Fatalf("%s: failed to add with remote setcode transaction: %v", name, err) 2445 } 2446 // The one in-flight transaction limit from A no longer applies, so we 2447 // can stack a second transaction for the account. 2448 if err := pool.addRemoteSync(pricedTransaction(1, 100000, big.NewInt(1000), keyA)); err != nil { 2449 t.Fatalf("%s: failed to replace with remote transaction: %v", name, err) 2450 } 2451 // B should still be able to send transactions. 2452 if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(1000), keyB)); err != nil { 2453 t.Fatalf("%s: failed to replace with remote transaction: %v", name, err) 2454 } 2455 // However B still has the limitation to one in-flight transaction. 2456 if err := pool.addRemoteSync(pricedTransaction(1, 100000, big.NewInt(1), keyB)); !errors.Is(err, txpool.ErrInflightTxLimitReached) { 2457 t.Fatalf("%s: error mismatch: want %v, have %v", name, txpool.ErrInflightTxLimitReached, err) 2458 } 2459 }, 2460 }, 2461 { 2462 name: "replacements-respect-inflight-tx-count", 2463 pending: 2, 2464 run: func(name string) { 2465 // Send transaction from A with B as an authority. 2466 if err := pool.addRemoteSync(pricedSetCodeTx(0, 250000, uint256.NewInt(10), uint256.NewInt(3), keyA, []unsignedAuth{{0, keyB}})); err != nil { 2467 t.Fatalf("%s: failed to add with remote setcode transaction: %v", name, err) 2468 } 2469 // Send two transactions from B. Only the first should be accepted due 2470 // to in-flight limit. 2471 if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(1), keyB)); err != nil { 2472 t.Fatalf("%s: failed to add remote transaction: %v", name, err) 2473 } 2474 if err := pool.addRemoteSync(pricedTransaction(1, 100000, big.NewInt(1), keyB)); !errors.Is(err, txpool.ErrInflightTxLimitReached) { 2475 t.Fatalf("%s: error mismatch: want %v, have %v", name, txpool.ErrInflightTxLimitReached, err) 2476 } 2477 // Replace the in-flight transaction from B. 2478 if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(30), keyB)); err != nil { 2479 t.Fatalf("%s: failed to replace with remote transaction: %v", name, err) 2480 } 2481 // Ensure the in-flight limit for B is still in place. 2482 if err := pool.addRemoteSync(pricedTransaction(1, 100000, big.NewInt(1), keyB)); !errors.Is(err, txpool.ErrInflightTxLimitReached) { 2483 t.Fatalf("%s: error mismatch: want %v, have %v", name, txpool.ErrInflightTxLimitReached, err) 2484 } 2485 }, 2486 }, 2487 { 2488 // Since multiple authorizations can be pending simultaneously, replacing 2489 // one of them should not break the one in-flight-transaction limit. 2490 name: "track-multiple-conflicting-delegations", 2491 pending: 3, 2492 run: func(name string) { 2493 // Send two setcode txs both with C as an authority. 2494 if err := pool.addRemoteSync(pricedSetCodeTx(0, 250000, uint256.NewInt(10), uint256.NewInt(3), keyA, []unsignedAuth{{0, keyC}})); err != nil { 2495 t.Fatalf("%s: failed to add with remote setcode transaction: %v", name, err) 2496 } 2497 if err := pool.addRemoteSync(pricedSetCodeTx(0, 250000, uint256.NewInt(30), uint256.NewInt(30), keyB, []unsignedAuth{{0, keyC}})); err != nil { 2498 t.Fatalf("%s: failed to add with remote setcode transaction: %v", name, err) 2499 } 2500 // Replace the tx from A with a non-setcode tx. 2501 if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(1000), keyA)); err != nil { 2502 t.Fatalf("%s: failed to replace with remote transaction: %v", name, err) 2503 } 2504 // Make sure we can only pool one tx from keyC since it is still a 2505 // pending authority. 2506 if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(1000), keyC)); err != nil { 2507 t.Fatalf("%s: failed to added single pooled for account with pending delegation: %v", name, err) 2508 } 2509 if err, want := pool.addRemoteSync(pricedTransaction(1, 100000, big.NewInt(1000), keyC)), txpool.ErrInflightTxLimitReached; !errors.Is(err, want) { 2510 t.Fatalf("%s: error mismatch: want %v, have %v", name, want, err) 2511 } 2512 }, 2513 }, 2514 { 2515 name: "remove-hash-from-authority-tracker", 2516 pending: 10, 2517 run: func(name string) { 2518 var keys []*ecdsa.PrivateKey 2519 for i := 0; i < 30; i++ { 2520 key, _ := crypto.GenerateKey() 2521 keys = append(keys, key) 2522 addr := crypto.PubkeyToAddress(key.PublicKey) 2523 testAddBalance(pool, addr, big.NewInt(params.Ether)) 2524 } 2525 // Create a transactions with 3 unique auths so the lookup's auth map is 2526 // filled with addresses. 2527 for i := 0; i < 30; i += 3 { 2528 if err := pool.addRemoteSync(pricedSetCodeTx(0, 250000, uint256.NewInt(10), uint256.NewInt(3), keys[i], []unsignedAuth{{0, keys[i]}, {0, keys[i+1]}, {0, keys[i+2]}})); err != nil { 2529 t.Fatalf("%s: failed to add with remote setcode transaction: %v", name, err) 2530 } 2531 } 2532 // Replace one of the transactions with a normal transaction so that the 2533 // original hash is removed from the tracker. The hash should be 2534 // associated with 3 different authorities. 2535 if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(1000), keys[0])); err != nil { 2536 t.Fatalf("%s: failed to replace with remote transaction: %v", name, err) 2537 } 2538 }, 2539 }, 2540 } { 2541 tt.run(tt.name) 2542 pending, queued := pool.Stats() 2543 if pending != tt.pending { 2544 t.Fatalf("%s: pending transactions mismatched: have %d, want %d", tt.name, pending, tt.pending) 2545 } 2546 if queued != tt.queued { 2547 t.Fatalf("%s: queued transactions mismatched: have %d, want %d", tt.name, queued, tt.queued) 2548 } 2549 if err := validatePoolInternals(pool); err != nil { 2550 t.Fatalf("%s: pool internal state corrupted: %v", tt.name, err) 2551 } 2552 pool.Clear() 2553 } 2554 } 2555 2556 func TestSetCodeTransactionsReorg(t *testing.T) { 2557 t.Parallel() 2558 2559 // Create the pool to test the status retrievals with 2560 statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) 2561 blockchain := newTestBlockChain(params.MergedTestChainConfig, 1000000, statedb, new(event.Feed)) 2562 2563 pool := New(testTxPoolConfig, blockchain) 2564 pool.Init(testTxPoolConfig.PriceLimit, blockchain.CurrentBlock(), newReserver()) 2565 defer pool.Close() 2566 2567 // Create the test accounts 2568 var ( 2569 keyA, _ = crypto.GenerateKey() 2570 addrA = crypto.PubkeyToAddress(keyA.PublicKey) 2571 ) 2572 testAddBalance(pool, addrA, big.NewInt(params.Ether)) 2573 // Send an authorization for 0x42 2574 var authList []types.SetCodeAuthorization 2575 auth, _ := types.SignSetCode(keyA, types.SetCodeAuthorization{ 2576 ChainID: *uint256.MustFromBig(params.TestChainConfig.ChainID), 2577 Address: common.Address{0x42}, 2578 Nonce: 0, 2579 }) 2580 authList = append(authList, auth) 2581 if err := pool.addRemoteSync(pricedSetCodeTxWithAuth(0, 250000, uint256.NewInt(10), uint256.NewInt(3), keyA, authList)); err != nil { 2582 t.Fatalf("failed to add with remote setcode transaction: %v", err) 2583 } 2584 // Simulate the chain moving 2585 blockchain.statedb.SetNonce(addrA, 1, tracing.NonceChangeAuthorization) 2586 blockchain.statedb.SetCode(addrA, types.AddressToDelegation(auth.Address)) 2587 <-pool.requestReset(nil, nil) 2588 // Set an authorization for 0x00 2589 auth, _ = types.SignSetCode(keyA, types.SetCodeAuthorization{ 2590 ChainID: *uint256.MustFromBig(params.TestChainConfig.ChainID), 2591 Address: common.Address{}, 2592 Nonce: 0, 2593 }) 2594 authList = append(authList, auth) 2595 if err := pool.addRemoteSync(pricedSetCodeTxWithAuth(1, 250000, uint256.NewInt(10), uint256.NewInt(3), keyA, authList)); err != nil { 2596 t.Fatalf("failed to add with remote setcode transaction: %v", err) 2597 } 2598 // Try to add a transactions in 2599 if err := pool.addRemoteSync(pricedTransaction(2, 100000, big.NewInt(1000), keyA)); !errors.Is(err, txpool.ErrInflightTxLimitReached) { 2600 t.Fatalf("unexpected error %v, expecting %v", err, txpool.ErrInflightTxLimitReached) 2601 } 2602 // Simulate the chain moving 2603 blockchain.statedb.SetNonce(addrA, 2, tracing.NonceChangeAuthorization) 2604 blockchain.statedb.SetCode(addrA, nil) 2605 <-pool.requestReset(nil, nil) 2606 // Now send two transactions from addrA 2607 if err := pool.addRemoteSync(pricedTransaction(2, 100000, big.NewInt(1000), keyA)); err != nil { 2608 t.Fatalf("failed to added single transaction: %v", err) 2609 } 2610 if err := pool.addRemoteSync(pricedTransaction(3, 100000, big.NewInt(1000), keyA)); err != nil { 2611 t.Fatalf("failed to added single transaction: %v", err) 2612 } 2613 } 2614 2615 // Benchmarks the speed of validating the contents of the pending queue of the 2616 // transaction pool. 2617 func BenchmarkPendingDemotion100(b *testing.B) { benchmarkPendingDemotion(b, 100) } 2618 func BenchmarkPendingDemotion1000(b *testing.B) { benchmarkPendingDemotion(b, 1000) } 2619 func BenchmarkPendingDemotion10000(b *testing.B) { benchmarkPendingDemotion(b, 10000) } 2620 2621 func benchmarkPendingDemotion(b *testing.B, size int) { 2622 // Add a batch of transactions to a pool one by one 2623 pool, key := setupPool() 2624 defer pool.Close() 2625 2626 account := crypto.PubkeyToAddress(key.PublicKey) 2627 testAddBalance(pool, account, big.NewInt(1000000)) 2628 2629 for i := 0; i < size; i++ { 2630 tx := transaction(uint64(i), 100000, key) 2631 pool.promoteTx(account, tx.Hash(), tx) 2632 } 2633 // Benchmark the speed of pool validation 2634 b.ResetTimer() 2635 for i := 0; i < b.N; i++ { 2636 pool.demoteUnexecutables() 2637 } 2638 } 2639 2640 // Benchmarks the speed of scheduling the contents of the future queue of the 2641 // transaction pool. 2642 func BenchmarkFuturePromotion100(b *testing.B) { benchmarkFuturePromotion(b, 100) } 2643 func BenchmarkFuturePromotion1000(b *testing.B) { benchmarkFuturePromotion(b, 1000) } 2644 func BenchmarkFuturePromotion10000(b *testing.B) { benchmarkFuturePromotion(b, 10000) } 2645 2646 func benchmarkFuturePromotion(b *testing.B, size int) { 2647 // Add a batch of transactions to a pool one by one 2648 pool, key := setupPool() 2649 defer pool.Close() 2650 2651 account := crypto.PubkeyToAddress(key.PublicKey) 2652 testAddBalance(pool, account, big.NewInt(1000000)) 2653 2654 for i := 0; i < size; i++ { 2655 tx := transaction(uint64(1+i), 100000, key) 2656 pool.enqueueTx(tx.Hash(), tx, true) 2657 } 2658 // Benchmark the speed of pool validation 2659 b.ResetTimer() 2660 for i := 0; i < b.N; i++ { 2661 pool.promoteExecutables(nil) 2662 } 2663 } 2664 2665 // Benchmarks the speed of batched transaction insertion. 2666 func BenchmarkBatchInsert100(b *testing.B) { benchmarkBatchInsert(b, 100) } 2667 func BenchmarkBatchInsert1000(b *testing.B) { benchmarkBatchInsert(b, 1000) } 2668 func BenchmarkBatchInsert10000(b *testing.B) { benchmarkBatchInsert(b, 10000) } 2669 2670 func benchmarkBatchInsert(b *testing.B, size int) { 2671 // Generate a batch of transactions to enqueue into the pool 2672 pool, key := setupPool() 2673 defer pool.Close() 2674 2675 account := crypto.PubkeyToAddress(key.PublicKey) 2676 testAddBalance(pool, account, big.NewInt(1000000000000000000)) 2677 2678 batches := make([]types.Transactions, b.N) 2679 for i := 0; i < b.N; i++ { 2680 batches[i] = make(types.Transactions, size) 2681 for j := 0; j < size; j++ { 2682 batches[i][j] = transaction(uint64(size*i+j), 100000, key) 2683 } 2684 } 2685 // Benchmark importing the transactions into the queue 2686 b.ResetTimer() 2687 for _, batch := range batches { 2688 pool.addRemotes(batch) 2689 } 2690 } 2691 2692 // Benchmarks the speed of batch transaction insertion in case of multiple accounts. 2693 func BenchmarkMultiAccountBatchInsert(b *testing.B) { 2694 // Generate a batch of transactions to enqueue into the pool 2695 pool, _ := setupPool() 2696 defer pool.Close() 2697 b.ReportAllocs() 2698 batches := make(types.Transactions, b.N) 2699 for i := 0; i < b.N; i++ { 2700 key, _ := crypto.GenerateKey() 2701 account := crypto.PubkeyToAddress(key.PublicKey) 2702 pool.currentState.AddBalance(account, uint256.NewInt(1000000), tracing.BalanceChangeUnspecified) 2703 tx := transaction(uint64(0), 100000, key) 2704 batches[i] = tx 2705 } 2706 // Benchmark importing the transactions into the queue 2707 b.ResetTimer() 2708 for _, tx := range batches { 2709 pool.addRemotesSync([]*types.Transaction{tx}) 2710 } 2711 }