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