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