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