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