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