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