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