github.com/neatlab/neatio@v1.7.3-0.20220425043230-d903e92fcc75/chain/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 "crypto/ecdsa" 21 "fmt" 22 "io/ioutil" 23 "math/big" 24 "math/rand" 25 "os" 26 "testing" 27 "time" 28 29 "github.com/neatlab/neatio/chain/core/rawdb" 30 "github.com/neatlab/neatio/chain/core/state" 31 "github.com/neatlab/neatio/chain/core/types" 32 "github.com/neatlab/neatio/params" 33 "github.com/neatlab/neatio/utilities/common" 34 "github.com/neatlab/neatio/utilities/crypto" 35 "github.com/neatlab/neatio/utilities/event" 36 ) 37 38 // testTxPoolConfig is a transaction pool configuration without stateful disk 39 // sideeffects used during testing. 40 var testTxPoolConfig TxPoolConfig 41 42 func init() { 43 testTxPoolConfig = DefaultTxPoolConfig 44 testTxPoolConfig.Journal = "" 45 } 46 47 type testBlockChain struct { 48 statedb *state.StateDB 49 gasLimit uint64 50 chainHeadFeed *event.Feed 51 } 52 53 func (bc *testBlockChain) CurrentBlock() *types.Block { 54 return types.NewBlock(&types.Header{ 55 GasLimit: bc.gasLimit, 56 }, nil, nil, nil) 57 } 58 59 func (bc *testBlockChain) GetBlock(hash common.Hash, number uint64) *types.Block { 60 return bc.CurrentBlock() 61 } 62 63 func (bc *testBlockChain) StateAt(common.Hash) (*state.StateDB, error) { 64 return bc.statedb, nil 65 } 66 67 func (bc *testBlockChain) SubscribeChainHeadEvent(ch chan<- ChainHeadEvent) event.Subscription { 68 return bc.chainHeadFeed.Subscribe(ch) 69 } 70 71 func transaction(nonce uint64, gaslimit uint64, key *ecdsa.PrivateKey) *types.Transaction { 72 return pricedTransaction(nonce, gaslimit, big.NewInt(1), key) 73 } 74 75 func pricedTransaction(nonce uint64, gaslimit uint64, gasprice *big.Int, key *ecdsa.PrivateKey) *types.Transaction { 76 tx, _ := types.SignTx(types.NewTransaction(nonce, common.Address{}, big.NewInt(100), gaslimit, gasprice, nil), types.HomesteadSigner{}, key) 77 return tx 78 } 79 80 func setupTxPool() (*TxPool, *ecdsa.PrivateKey) { 81 diskdb := rawdb.NewMemoryDatabase() 82 statedb, _ := state.New(common.Hash{}, state.NewDatabase(diskdb)) 83 blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} 84 85 key, _ := crypto.GenerateKey() 86 pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain, nil) 87 88 return pool, key 89 } 90 91 // validateTxPoolInternals checks various consistency invariants within the pool. 92 func validateTxPoolInternals(pool *TxPool) error { 93 pool.mu.RLock() 94 defer pool.mu.RUnlock() 95 96 // Ensure the total transaction set is consistent with pending + queued 97 pending, queued := pool.stats() 98 if total := len(pool.all); total != pending+queued { 99 return fmt.Errorf("total transaction count %d != %d pending + %d queued", total, pending, queued) 100 } 101 if priced := pool.priced.items.Len() - pool.priced.stales; priced != pending+queued { 102 return fmt.Errorf("total priced transaction count %d != %d pending + %d queued", priced, pending, queued) 103 } 104 // Ensure the next nonce to assign is the correct one 105 for addr, txs := range pool.pending { 106 // Find the last transaction 107 var last uint64 108 for nonce := range txs.txs.items { 109 if last < nonce { 110 last = nonce 111 } 112 } 113 if nonce := pool.pendingState.GetNonce(addr); nonce != last+1 { 114 return fmt.Errorf("pending nonce mismatch: have %v, want %v", nonce, last+1) 115 } 116 } 117 return nil 118 } 119 120 // validateEvents checks that the correct number of transaction addition events 121 // were fired on the pool's event feed. 122 func validateEvents(events chan TxPreEvent, count int) error { 123 for i := 0; i < count; i++ { 124 select { 125 case <-events: 126 case <-time.After(time.Second): 127 return fmt.Errorf("event #%d not fired", i) 128 } 129 } 130 select { 131 case tx := <-events: 132 return fmt.Errorf("more than %d events fired: %v", count, tx.Tx) 133 134 case <-time.After(50 * time.Millisecond): 135 // This branch should be "default", but it's a data race between goroutines, 136 // reading the event channel and pushng into it, so better wait a bit ensuring 137 // really nothing gets injected. 138 } 139 return nil 140 } 141 142 func deriveSender(tx *types.Transaction) (common.Address, error) { 143 return types.Sender(types.HomesteadSigner{}, tx) 144 } 145 146 type testChain struct { 147 *testBlockChain 148 address common.Address 149 trigger *bool 150 } 151 152 // testChain.State() is used multiple times to reset the pending state. 153 // when simulate is true it will create a state that indicates 154 // that tx0 and tx1 are included in the chain. 155 func (c *testChain) State() (*state.StateDB, error) { 156 // delay "state change" by one. The tx pool fetches the 157 // state multiple times and by delaying it a bit we simulate 158 // a state change between those fetches. 159 stdb := c.statedb 160 if *c.trigger { 161 db := rawdb.NewMemoryDatabase() 162 c.statedb, _ = state.New(common.Hash{}, state.NewDatabase(db)) 163 // simulate that the new head block included tx0 and tx1 164 c.statedb.SetNonce(c.address, 2) 165 c.statedb.SetBalance(c.address, new(big.Int).SetUint64(params.NEAT)) 166 *c.trigger = false 167 } 168 return stdb, nil 169 } 170 171 // This test simulates a scenario where a new block is imported during a 172 // state reset and tests whether the pending state is in sync with the 173 // block head event that initiated the resetState(). 174 func TestStateChangeDuringTransactionPoolReset(t *testing.T) { 175 t.Parallel() 176 177 var ( 178 db = rawdb.NewMemoryDatabase() 179 key, _ = crypto.GenerateKey() 180 address = crypto.PubkeyToAddress(key.PublicKey) 181 statedb, _ = state.New(common.Hash{}, state.NewDatabase(db)) 182 trigger = false 183 ) 184 185 // setup pool with 2 transaction in it 186 statedb.SetBalance(address, new(big.Int).SetUint64(params.NEAT)) 187 blockchain := &testChain{&testBlockChain{statedb, 1000000000, new(event.Feed)}, address, &trigger} 188 189 tx0 := transaction(0, 100000, key) 190 tx1 := transaction(1, 100000, key) 191 192 pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain, nil) 193 defer pool.Stop() 194 195 nonce := pool.State().GetNonce(address) 196 if nonce != 0 { 197 t.Fatalf("Invalid nonce, want 0, got %d", nonce) 198 } 199 200 pool.AddRemotes(types.Transactions{tx0, tx1}) 201 202 nonce = pool.State().GetNonce(address) 203 if nonce != 2 { 204 t.Fatalf("Invalid nonce, want 2, got %d", nonce) 205 } 206 207 // trigger state change in the background 208 trigger = true 209 210 pool.lockedReset(nil, nil) 211 212 pendingTx, err := pool.Pending() 213 if err != nil { 214 t.Fatalf("Could not fetch pending transactions: %v", err) 215 } 216 217 for addr, txs := range pendingTx { 218 t.Logf("%0x: %d\n", addr, len(txs)) 219 } 220 221 nonce = pool.State().GetNonce(address) 222 if nonce != 2 { 223 t.Fatalf("Invalid nonce, want 2, got %d", nonce) 224 } 225 } 226 227 func TestInvalidTransactions(t *testing.T) { 228 t.Parallel() 229 230 pool, key := setupTxPool() 231 defer pool.Stop() 232 233 tx := transaction(0, 100, key) 234 from, _ := deriveSender(tx) 235 236 pool.currentState.AddBalance(from, big.NewInt(1)) 237 if err := pool.AddRemote(tx); err != ErrInsufficientFunds { 238 t.Error("expected", ErrInsufficientFunds) 239 } 240 241 balance := new(big.Int).Add(tx.Value(), new(big.Int).Mul(new(big.Int).SetUint64(tx.Gas()), tx.GasPrice())) 242 pool.currentState.AddBalance(from, balance) 243 if err := pool.AddRemote(tx); err != ErrIntrinsicGas { 244 t.Error("expected", ErrIntrinsicGas, "got", err) 245 } 246 247 pool.currentState.SetNonce(from, 1) 248 pool.currentState.AddBalance(from, big.NewInt(0xffffffffffffff)) 249 tx = transaction(0, 100000, key) 250 if err := pool.AddRemote(tx); err != ErrNonceTooLow { 251 t.Error("expected", ErrNonceTooLow) 252 } 253 254 tx = transaction(1, 100000, key) 255 pool.gasPrice = big.NewInt(1000) 256 if err := pool.AddRemote(tx); err != ErrUnderpriced { 257 t.Error("expected", ErrUnderpriced, "got", err) 258 } 259 if err := pool.AddLocal(tx); err != nil { 260 t.Error("expected", nil, "got", err) 261 } 262 } 263 264 func TestTransactionQueue(t *testing.T) { 265 t.Parallel() 266 267 pool, key := setupTxPool() 268 defer pool.Stop() 269 270 tx := transaction(0, 100, key) 271 from, _ := deriveSender(tx) 272 pool.currentState.AddBalance(from, big.NewInt(1000)) 273 pool.lockedReset(nil, nil) 274 pool.enqueueTx(tx.Hash(), tx) 275 276 pool.promoteExecutables([]common.Address{from}) 277 if len(pool.pending) != 1 { 278 t.Error("expected valid txs to be 1 is", len(pool.pending)) 279 } 280 281 tx = transaction(1, 100, key) 282 from, _ = deriveSender(tx) 283 pool.currentState.SetNonce(from, 2) 284 pool.enqueueTx(tx.Hash(), tx) 285 pool.promoteExecutables([]common.Address{from}) 286 if _, ok := pool.pending[from].txs.items[tx.Nonce()]; ok { 287 t.Error("expected transaction to be in tx pool") 288 } 289 290 if len(pool.queue) > 0 { 291 t.Error("expected transaction queue to be empty. is", len(pool.queue)) 292 } 293 294 pool, key = setupTxPool() 295 defer pool.Stop() 296 297 tx1 := transaction(0, 100, key) 298 tx2 := transaction(10, 100, key) 299 tx3 := transaction(11, 100, key) 300 from, _ = deriveSender(tx1) 301 pool.currentState.AddBalance(from, big.NewInt(1000)) 302 pool.lockedReset(nil, nil) 303 304 pool.enqueueTx(tx1.Hash(), tx1) 305 pool.enqueueTx(tx2.Hash(), tx2) 306 pool.enqueueTx(tx3.Hash(), tx3) 307 308 pool.promoteExecutables([]common.Address{from}) 309 310 if len(pool.pending) != 1 { 311 t.Error("expected tx pool to be 1, got", len(pool.pending)) 312 } 313 if pool.queue[from].Len() != 2 { 314 t.Error("expected len(queue) == 2, got", pool.queue[from].Len()) 315 } 316 } 317 318 func TestTransactionNegativeValue(t *testing.T) { 319 t.Parallel() 320 321 pool, key := setupTxPool() 322 defer pool.Stop() 323 324 tx, _ := types.SignTx(types.NewTransaction(0, common.Address{}, big.NewInt(-1), 100, big.NewInt(1), nil), types.HomesteadSigner{}, key) 325 from, _ := deriveSender(tx) 326 pool.currentState.AddBalance(from, big.NewInt(1)) 327 if err := pool.AddRemote(tx); err != ErrNegativeValue { 328 t.Error("expected", ErrNegativeValue, "got", err) 329 } 330 } 331 332 func TestTransactionChainFork(t *testing.T) { 333 t.Parallel() 334 335 pool, key := setupTxPool() 336 defer pool.Stop() 337 338 addr := crypto.PubkeyToAddress(key.PublicKey) 339 resetState := func() { 340 db := rawdb.NewMemoryDatabase() 341 statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) 342 statedb.AddBalance(addr, big.NewInt(100000000000000)) 343 344 pool.chain = &testBlockChain{statedb, 1000000, new(event.Feed)} 345 pool.lockedReset(nil, nil) 346 } 347 resetState() 348 349 tx := transaction(0, 100000, key) 350 if _, err := pool.add(tx, false); err != nil { 351 t.Error("didn't expect error", err) 352 } 353 pool.removeTx(tx.Hash()) 354 355 // reset the pool's internal state 356 resetState() 357 if _, err := pool.add(tx, false); err != nil { 358 t.Error("didn't expect error", err) 359 } 360 } 361 362 func TestTransactionDoubleNonce(t *testing.T) { 363 t.Parallel() 364 365 pool, key := setupTxPool() 366 defer pool.Stop() 367 368 addr := crypto.PubkeyToAddress(key.PublicKey) 369 resetState := func() { 370 db := rawdb.NewMemoryDatabase() 371 statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) 372 statedb.AddBalance(addr, big.NewInt(100000000000000)) 373 374 pool.chain = &testBlockChain{statedb, 1000000, new(event.Feed)} 375 pool.lockedReset(nil, nil) 376 } 377 resetState() 378 379 signer := types.HomesteadSigner{} 380 tx1, _ := types.SignTx(types.NewTransaction(0, common.Address{}, big.NewInt(100), 100000, big.NewInt(1), nil), signer, key) 381 tx2, _ := types.SignTx(types.NewTransaction(0, common.Address{}, big.NewInt(100), 1000000, big.NewInt(2), nil), signer, key) 382 tx3, _ := types.SignTx(types.NewTransaction(0, common.Address{}, big.NewInt(100), 1000000, big.NewInt(1), nil), signer, key) 383 384 // Add the first two transaction, ensure higher priced stays only 385 if replace, err := pool.add(tx1, false); err != nil || replace { 386 t.Errorf("first transaction insert failed (%v) or reported replacement (%v)", err, replace) 387 } 388 if replace, err := pool.add(tx2, false); err != nil || !replace { 389 t.Errorf("second transaction insert failed (%v) or not reported replacement (%v)", err, replace) 390 } 391 pool.promoteExecutables([]common.Address{addr}) 392 if pool.pending[addr].Len() != 1 { 393 t.Error("expected 1 pending transactions, got", pool.pending[addr].Len()) 394 } 395 if tx := pool.pending[addr].txs.items[0]; tx.Hash() != tx2.Hash() { 396 t.Errorf("transaction mismatch: have %x, want %x", tx.Hash(), tx2.Hash()) 397 } 398 // Add the third transaction and ensure it's not saved (smaller price) 399 pool.add(tx3, false) 400 pool.promoteExecutables([]common.Address{addr}) 401 if pool.pending[addr].Len() != 1 { 402 t.Error("expected 1 pending transactions, got", pool.pending[addr].Len()) 403 } 404 if tx := pool.pending[addr].txs.items[0]; tx.Hash() != tx2.Hash() { 405 t.Errorf("transaction mismatch: have %x, want %x", tx.Hash(), tx2.Hash()) 406 } 407 // Ensure the total transaction count is correct 408 if len(pool.all) != 1 { 409 t.Error("expected 1 total transactions, got", len(pool.all)) 410 } 411 } 412 413 func TestTransactionMissingNonce(t *testing.T) { 414 t.Parallel() 415 416 pool, key := setupTxPool() 417 defer pool.Stop() 418 419 addr := crypto.PubkeyToAddress(key.PublicKey) 420 pool.currentState.AddBalance(addr, big.NewInt(100000000000000)) 421 tx := transaction(1, 100000, key) 422 if _, err := pool.add(tx, false); err != nil { 423 t.Error("didn't expect error", err) 424 } 425 if len(pool.pending) != 0 { 426 t.Error("expected 0 pending transactions, got", len(pool.pending)) 427 } 428 if pool.queue[addr].Len() != 1 { 429 t.Error("expected 1 queued transaction, got", pool.queue[addr].Len()) 430 } 431 if len(pool.all) != 1 { 432 t.Error("expected 1 total transactions, got", len(pool.all)) 433 } 434 } 435 436 func TestTransactionNonceRecovery(t *testing.T) { 437 t.Parallel() 438 439 const n = 10 440 pool, key := setupTxPool() 441 defer pool.Stop() 442 443 addr := crypto.PubkeyToAddress(key.PublicKey) 444 pool.currentState.SetNonce(addr, n) 445 pool.currentState.AddBalance(addr, big.NewInt(100000000000000)) 446 pool.lockedReset(nil, nil) 447 448 tx := transaction(n, 100000, key) 449 if err := pool.AddRemote(tx); err != nil { 450 t.Error(err) 451 } 452 // simulate some weird re-order of transactions and missing nonce(s) 453 pool.currentState.SetNonce(addr, n-1) 454 pool.lockedReset(nil, nil) 455 if fn := pool.pendingState.GetNonce(addr); fn != n-1 { 456 t.Errorf("expected nonce to be %d, got %d", n-1, fn) 457 } 458 } 459 460 // Tests that if an account runs out of funds, any pending and queued transactions 461 // are dropped. 462 func TestTransactionDropping(t *testing.T) { 463 t.Parallel() 464 465 // Create a test account and fund it 466 pool, key := setupTxPool() 467 defer pool.Stop() 468 469 account, _ := deriveSender(transaction(0, 0, key)) 470 pool.currentState.AddBalance(account, big.NewInt(1000)) 471 472 // Add some pending and some queued transactions 473 var ( 474 tx0 = transaction(0, 100, key) 475 tx1 = transaction(1, 200, key) 476 tx2 = transaction(2, 300, key) 477 tx10 = transaction(10, 100, key) 478 tx11 = transaction(11, 200, key) 479 tx12 = transaction(12, 300, key) 480 ) 481 pool.promoteTx(account, tx0.Hash(), tx0) 482 pool.promoteTx(account, tx1.Hash(), tx1) 483 pool.promoteTx(account, tx2.Hash(), tx2) 484 pool.enqueueTx(tx10.Hash(), tx10) 485 pool.enqueueTx(tx11.Hash(), tx11) 486 pool.enqueueTx(tx12.Hash(), tx12) 487 488 // Check that pre and post validations leave the pool as is 489 if pool.pending[account].Len() != 3 { 490 t.Errorf("pending transaction mismatch: have %d, want %d", pool.pending[account].Len(), 3) 491 } 492 if pool.queue[account].Len() != 3 { 493 t.Errorf("queued transaction mismatch: have %d, want %d", pool.queue[account].Len(), 3) 494 } 495 if len(pool.all) != 6 { 496 t.Errorf("total transaction mismatch: have %d, want %d", len(pool.all), 6) 497 } 498 pool.lockedReset(nil, nil) 499 if pool.pending[account].Len() != 3 { 500 t.Errorf("pending transaction mismatch: have %d, want %d", pool.pending[account].Len(), 3) 501 } 502 if pool.queue[account].Len() != 3 { 503 t.Errorf("queued transaction mismatch: have %d, want %d", pool.queue[account].Len(), 3) 504 } 505 if len(pool.all) != 6 { 506 t.Errorf("total transaction mismatch: have %d, want %d", len(pool.all), 6) 507 } 508 // Reduce the balance of the account, and check that invalidated transactions are dropped 509 pool.currentState.AddBalance(account, big.NewInt(-650)) 510 pool.lockedReset(nil, nil) 511 512 if _, ok := pool.pending[account].txs.items[tx0.Nonce()]; !ok { 513 t.Errorf("funded pending transaction missing: %v", tx0) 514 } 515 if _, ok := pool.pending[account].txs.items[tx1.Nonce()]; !ok { 516 t.Errorf("funded pending transaction missing: %v", tx0) 517 } 518 if _, ok := pool.pending[account].txs.items[tx2.Nonce()]; ok { 519 t.Errorf("out-of-fund pending transaction present: %v", tx1) 520 } 521 if _, ok := pool.queue[account].txs.items[tx10.Nonce()]; !ok { 522 t.Errorf("funded queued transaction missing: %v", tx10) 523 } 524 if _, ok := pool.queue[account].txs.items[tx11.Nonce()]; !ok { 525 t.Errorf("funded queued transaction missing: %v", tx10) 526 } 527 if _, ok := pool.queue[account].txs.items[tx12.Nonce()]; ok { 528 t.Errorf("out-of-fund queued transaction present: %v", tx11) 529 } 530 if len(pool.all) != 4 { 531 t.Errorf("total transaction mismatch: have %d, want %d", len(pool.all), 4) 532 } 533 // Reduce the block gas limit, check that invalidated transactions are dropped 534 pool.chain.(*testBlockChain).gasLimit = 100 535 pool.lockedReset(nil, nil) 536 537 if _, ok := pool.pending[account].txs.items[tx0.Nonce()]; !ok { 538 t.Errorf("funded pending transaction missing: %v", tx0) 539 } 540 if _, ok := pool.pending[account].txs.items[tx1.Nonce()]; ok { 541 t.Errorf("over-gased pending transaction present: %v", tx1) 542 } 543 if _, ok := pool.queue[account].txs.items[tx10.Nonce()]; !ok { 544 t.Errorf("funded queued transaction missing: %v", tx10) 545 } 546 if _, ok := pool.queue[account].txs.items[tx11.Nonce()]; ok { 547 t.Errorf("over-gased queued transaction present: %v", tx11) 548 } 549 if len(pool.all) != 2 { 550 t.Errorf("total transaction mismatch: have %d, want %d", len(pool.all), 2) 551 } 552 } 553 554 // Tests that if a transaction is dropped from the current pending pool (e.g. out 555 // of fund), all consecutive (still valid, but not executable) transactions are 556 // postponed back into the future queue to prevent broadcasting them. 557 func TestTransactionPostponing(t *testing.T) { 558 t.Parallel() 559 560 // Create the pool to test the postponing with 561 db := rawdb.NewMemoryDatabase() 562 statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) 563 blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} 564 565 pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain, nil) 566 defer pool.Stop() 567 568 // Create two test accounts to produce different gap profiles with 569 keys := make([]*ecdsa.PrivateKey, 2) 570 accs := make([]common.Address, len(keys)) 571 572 for i := 0; i < len(keys); i++ { 573 keys[i], _ = crypto.GenerateKey() 574 accs[i] = crypto.PubkeyToAddress(keys[i].PublicKey) 575 576 pool.currentState.AddBalance(crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(50100)) 577 } 578 // Add a batch consecutive pending transactions for validation 579 txs := []*types.Transaction{} 580 for i, key := range keys { 581 582 for j := 0; j < 100; j++ { 583 var tx *types.Transaction 584 if (i+j)%2 == 0 { 585 tx = transaction(uint64(j), 25000, key) 586 } else { 587 tx = transaction(uint64(j), 50000, key) 588 } 589 txs = append(txs, tx) 590 } 591 } 592 for i, err := range pool.AddRemotes(txs) { 593 if err != nil { 594 t.Fatalf("tx %d: failed to add transactions: %v", i, err) 595 } 596 } 597 // Check that pre and post validations leave the pool as is 598 if pending := pool.pending[accs[0]].Len() + pool.pending[accs[1]].Len(); pending != len(txs) { 599 t.Errorf("pending transaction mismatch: have %d, want %d", pending, len(txs)) 600 } 601 if len(pool.queue) != 0 { 602 t.Errorf("queued accounts mismatch: have %d, want %d", len(pool.queue), 0) 603 } 604 if len(pool.all) != len(txs) { 605 t.Errorf("total transaction mismatch: have %d, want %d", len(pool.all), len(txs)) 606 } 607 pool.lockedReset(nil, nil) 608 if pending := pool.pending[accs[0]].Len() + pool.pending[accs[1]].Len(); pending != len(txs) { 609 t.Errorf("pending transaction mismatch: have %d, want %d", pending, len(txs)) 610 } 611 if len(pool.queue) != 0 { 612 t.Errorf("queued accounts mismatch: have %d, want %d", len(pool.queue), 0) 613 } 614 if len(pool.all) != len(txs) { 615 t.Errorf("total transaction mismatch: have %d, want %d", len(pool.all), len(txs)) 616 } 617 // Reduce the balance of the account, and check that transactions are reorganised 618 for _, addr := range accs { 619 pool.currentState.AddBalance(addr, big.NewInt(-1)) 620 } 621 pool.lockedReset(nil, nil) 622 623 // The first account's first transaction remains valid, check that subsequent 624 // ones are either filtered out, or queued up for later. 625 if _, ok := pool.pending[accs[0]].txs.items[txs[0].Nonce()]; !ok { 626 t.Errorf("tx %d: valid and funded transaction missing from pending pool: %v", 0, txs[0]) 627 } 628 if _, ok := pool.queue[accs[0]].txs.items[txs[0].Nonce()]; ok { 629 t.Errorf("tx %d: valid and funded transaction present in future queue: %v", 0, txs[0]) 630 } 631 for i, tx := range txs[1:100] { 632 if i%2 == 1 { 633 if _, ok := pool.pending[accs[0]].txs.items[tx.Nonce()]; ok { 634 t.Errorf("tx %d: valid but future transaction present in pending pool: %v", i+1, tx) 635 } 636 if _, ok := pool.queue[accs[0]].txs.items[tx.Nonce()]; !ok { 637 t.Errorf("tx %d: valid but future transaction missing from future queue: %v", i+1, tx) 638 } 639 } else { 640 if _, ok := pool.pending[accs[0]].txs.items[tx.Nonce()]; ok { 641 t.Errorf("tx %d: out-of-fund transaction present in pending pool: %v", i+1, tx) 642 } 643 if _, ok := pool.queue[accs[0]].txs.items[tx.Nonce()]; ok { 644 t.Errorf("tx %d: out-of-fund transaction present in future queue: %v", i+1, tx) 645 } 646 } 647 } 648 // The second account's first transaction got invalid, check that all transactions 649 // are either filtered out, or queued up for later. 650 if pool.pending[accs[1]] != nil { 651 t.Errorf("invalidated account still has pending transactions") 652 } 653 for i, tx := range txs[100:] { 654 if i%2 == 1 { 655 if _, ok := pool.queue[accs[1]].txs.items[tx.Nonce()]; !ok { 656 t.Errorf("tx %d: valid but future transaction missing from future queue: %v", 100+i, tx) 657 } 658 } else { 659 if _, ok := pool.queue[accs[1]].txs.items[tx.Nonce()]; ok { 660 t.Errorf("tx %d: out-of-fund transaction present in future queue: %v", 100+i, tx) 661 } 662 } 663 } 664 if len(pool.all) != len(txs)/2 { 665 t.Errorf("total transaction mismatch: have %d, want %d", len(pool.all), len(txs)/2) 666 } 667 } 668 669 // Tests that if the transaction pool has both executable and non-executable 670 // transactions from an origin account, filling the nonce gap moves all queued 671 // ones into the pending pool. 672 func TestTransactionGapFilling(t *testing.T) { 673 t.Parallel() 674 675 // Create a test account and fund it 676 pool, key := setupTxPool() 677 defer pool.Stop() 678 679 account, _ := deriveSender(transaction(0, 0, key)) 680 pool.currentState.AddBalance(account, big.NewInt(1000000)) 681 682 // Keep track of transaction events to ensure all executables get announced 683 events := make(chan TxPreEvent, testTxPoolConfig.AccountQueue+5) 684 sub := pool.txFeed.Subscribe(events) 685 defer sub.Unsubscribe() 686 687 // Create a pending and a queued transaction with a nonce-gap in between 688 if err := pool.AddRemote(transaction(0, 100000, key)); err != nil { 689 t.Fatalf("failed to add pending transaction: %v", err) 690 } 691 if err := pool.AddRemote(transaction(2, 100000, key)); err != nil { 692 t.Fatalf("failed to add queued transaction: %v", err) 693 } 694 pending, queued := pool.Stats() 695 if pending != 1 { 696 t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 1) 697 } 698 if queued != 1 { 699 t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 1) 700 } 701 if err := validateEvents(events, 1); err != nil { 702 t.Fatalf("original event firing failed: %v", err) 703 } 704 if err := validateTxPoolInternals(pool); err != nil { 705 t.Fatalf("pool internal state corrupted: %v", err) 706 } 707 // Fill the nonce gap and ensure all transactions become pending 708 if err := pool.AddRemote(transaction(1, 100000, key)); err != nil { 709 t.Fatalf("failed to add gapped transaction: %v", err) 710 } 711 pending, queued = pool.Stats() 712 if pending != 3 { 713 t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 3) 714 } 715 if queued != 0 { 716 t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 0) 717 } 718 if err := validateEvents(events, 2); err != nil { 719 t.Fatalf("gap-filling event firing failed: %v", err) 720 } 721 if err := validateTxPoolInternals(pool); err != nil { 722 t.Fatalf("pool internal state corrupted: %v", err) 723 } 724 } 725 726 // Tests that if the transaction count belonging to a single account goes above 727 // some threshold, the higher transactions are dropped to prevent DOS attacks. 728 func TestTransactionQueueAccountLimiting(t *testing.T) { 729 t.Parallel() 730 731 // Create a test account and fund it 732 pool, key := setupTxPool() 733 defer pool.Stop() 734 735 account, _ := deriveSender(transaction(0, 0, key)) 736 pool.currentState.AddBalance(account, big.NewInt(1000000)) 737 738 // Keep queuing up transactions and make sure all above a limit are dropped 739 for i := uint64(1); i <= testTxPoolConfig.AccountQueue+5; i++ { 740 if err := pool.AddRemote(transaction(i, 100000, key)); err != nil { 741 t.Fatalf("tx %d: failed to add transaction: %v", i, err) 742 } 743 if len(pool.pending) != 0 { 744 t.Errorf("tx %d: pending pool size mismatch: have %d, want %d", i, len(pool.pending), 0) 745 } 746 if i <= testTxPoolConfig.AccountQueue { 747 if pool.queue[account].Len() != int(i) { 748 t.Errorf("tx %d: queue size mismatch: have %d, want %d", i, pool.queue[account].Len(), i) 749 } 750 } else { 751 if pool.queue[account].Len() != int(testTxPoolConfig.AccountQueue) { 752 t.Errorf("tx %d: queue limit mismatch: have %d, want %d", i, pool.queue[account].Len(), testTxPoolConfig.AccountQueue) 753 } 754 } 755 } 756 if len(pool.all) != int(testTxPoolConfig.AccountQueue) { 757 t.Errorf("total transaction mismatch: have %d, want %d", len(pool.all), testTxPoolConfig.AccountQueue) 758 } 759 } 760 761 // Tests that if the transaction count belonging to multiple accounts go above 762 // some threshold, the higher transactions are dropped to prevent DOS attacks. 763 // 764 // This logic should not hold for local transactions, unless the local tracking 765 // mechanism is disabled. 766 func TestTransactionQueueGlobalLimiting(t *testing.T) { 767 testTransactionQueueGlobalLimiting(t, false) 768 } 769 func TestTransactionQueueGlobalLimitingNoLocals(t *testing.T) { 770 testTransactionQueueGlobalLimiting(t, true) 771 } 772 773 func testTransactionQueueGlobalLimiting(t *testing.T, nolocals bool) { 774 t.Parallel() 775 776 // Create the pool to test the limit enforcement with 777 db := rawdb.NewMemoryDatabase() 778 statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) 779 blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} 780 781 config := testTxPoolConfig 782 config.NoLocals = nolocals 783 config.GlobalQueue = config.AccountQueue*3 - 1 // reduce the queue limits to shorten test time (-1 to make it non divisible) 784 785 pool := NewTxPool(config, params.TestChainConfig, blockchain, nil) 786 defer pool.Stop() 787 788 // Create a number of test accounts and fund them (last one will be the local) 789 keys := make([]*ecdsa.PrivateKey, 5) 790 for i := 0; i < len(keys); i++ { 791 keys[i], _ = crypto.GenerateKey() 792 pool.currentState.AddBalance(crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(1000000)) 793 } 794 local := keys[len(keys)-1] 795 796 // Generate and queue a batch of transactions 797 nonces := make(map[common.Address]uint64) 798 799 txs := make(types.Transactions, 0, 3*config.GlobalQueue) 800 for len(txs) < cap(txs) { 801 key := keys[rand.Intn(len(keys)-1)] // skip adding transactions with the local account 802 addr := crypto.PubkeyToAddress(key.PublicKey) 803 804 txs = append(txs, transaction(nonces[addr]+1, 100000, key)) 805 nonces[addr]++ 806 } 807 // Import the batch and verify that limits have been enforced 808 pool.AddRemotes(txs) 809 810 queued := 0 811 for addr, list := range pool.queue { 812 if list.Len() > int(config.AccountQueue) { 813 t.Errorf("addr %x: queued accounts overflown allowance: %d > %d", addr, list.Len(), config.AccountQueue) 814 } 815 queued += list.Len() 816 } 817 if queued > int(config.GlobalQueue) { 818 t.Fatalf("total transactions overflow allowance: %d > %d", queued, config.GlobalQueue) 819 } 820 // Generate a batch of transactions from the local account and import them 821 txs = txs[:0] 822 for i := uint64(0); i < 3*config.GlobalQueue; i++ { 823 txs = append(txs, transaction(i+1, 100000, local)) 824 } 825 pool.AddLocals(txs) 826 827 // If locals are disabled, the previous eviction algorithm should apply here too 828 if nolocals { 829 queued := 0 830 for addr, list := range pool.queue { 831 if list.Len() > int(config.AccountQueue) { 832 t.Errorf("addr %x: queued accounts overflown allowance: %d > %d", addr, list.Len(), config.AccountQueue) 833 } 834 queued += list.Len() 835 } 836 if queued > int(config.GlobalQueue) { 837 t.Fatalf("total transactions overflow allowance: %d > %d", queued, config.GlobalQueue) 838 } 839 } else { 840 // Local exemptions are enabled, make sure the local account owned the queue 841 if len(pool.queue) != 1 { 842 t.Errorf("multiple accounts in queue: have %v, want %v", len(pool.queue), 1) 843 } 844 // Also ensure no local transactions are ever dropped, even if above global limits 845 if queued := pool.queue[crypto.PubkeyToAddress(local.PublicKey)].Len(); uint64(queued) != 3*config.GlobalQueue { 846 t.Fatalf("local account queued transaction count mismatch: have %v, want %v", queued, 3*config.GlobalQueue) 847 } 848 } 849 } 850 851 // Tests that if an account remains idle for a prolonged amount of time, any 852 // non-executable transactions queued up are dropped to prevent wasting resources 853 // on shuffling them around. 854 // 855 // This logic should not hold for local transactions, unless the local tracking 856 // mechanism is disabled. 857 func TestTransactionQueueTimeLimiting(t *testing.T) { testTransactionQueueTimeLimiting(t, false) } 858 func TestTransactionQueueTimeLimitingNoLocals(t *testing.T) { 859 testTransactionQueueTimeLimiting(t, true) 860 } 861 862 func testTransactionQueueTimeLimiting(t *testing.T, nolocals bool) { 863 // Reduce the eviction interval to a testable amount 864 defer func(old time.Duration) { evictionInterval = old }(evictionInterval) 865 evictionInterval = time.Second 866 867 // Create the pool to test the non-expiration enforcement 868 db := rawdb.NewMemoryDatabase() 869 statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) 870 blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} 871 872 config := testTxPoolConfig 873 config.Lifetime = time.Second 874 config.NoLocals = nolocals 875 876 pool := NewTxPool(config, params.TestChainConfig, blockchain, nil) 877 defer pool.Stop() 878 879 // Create two test accounts to ensure remotes expire but locals do not 880 local, _ := crypto.GenerateKey() 881 remote, _ := crypto.GenerateKey() 882 883 pool.currentState.AddBalance(crypto.PubkeyToAddress(local.PublicKey), big.NewInt(1000000000)) 884 pool.currentState.AddBalance(crypto.PubkeyToAddress(remote.PublicKey), big.NewInt(1000000000)) 885 886 // Add the two transactions and ensure they both are queued up 887 if err := pool.AddLocal(pricedTransaction(1, 100000, big.NewInt(1), local)); err != nil { 888 t.Fatalf("failed to add local transaction: %v", err) 889 } 890 if err := pool.AddRemote(pricedTransaction(1, 100000, big.NewInt(1), remote)); err != nil { 891 t.Fatalf("failed to add remote transaction: %v", err) 892 } 893 pending, queued := pool.Stats() 894 if pending != 0 { 895 t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 0) 896 } 897 if queued != 2 { 898 t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 2) 899 } 900 if err := validateTxPoolInternals(pool); err != nil { 901 t.Fatalf("pool internal state corrupted: %v", err) 902 } 903 // Wait a bit for eviction to run and clean up any leftovers, and ensure only the local remains 904 time.Sleep(2 * config.Lifetime) 905 906 pending, queued = pool.Stats() 907 if pending != 0 { 908 t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 0) 909 } 910 if nolocals { 911 if queued != 0 { 912 t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 0) 913 } 914 } else { 915 if queued != 1 { 916 t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 1) 917 } 918 } 919 if err := validateTxPoolInternals(pool); err != nil { 920 t.Fatalf("pool internal state corrupted: %v", err) 921 } 922 } 923 924 // Tests that even if the transaction count belonging to a single account goes 925 // above some threshold, as long as the transactions are executable, they are 926 // accepted. 927 func TestTransactionPendingLimiting(t *testing.T) { 928 t.Parallel() 929 930 // Create a test account and fund it 931 pool, key := setupTxPool() 932 defer pool.Stop() 933 934 account, _ := deriveSender(transaction(0, 0, key)) 935 pool.currentState.AddBalance(account, big.NewInt(1000000)) 936 937 // Keep track of transaction events to ensure all executables get announced 938 events := make(chan TxPreEvent, testTxPoolConfig.AccountQueue+5) 939 sub := pool.txFeed.Subscribe(events) 940 defer sub.Unsubscribe() 941 942 // Keep queuing up transactions and make sure all above a limit are dropped 943 for i := uint64(0); i < testTxPoolConfig.AccountQueue+5; i++ { 944 if err := pool.AddRemote(transaction(i, 100000, key)); err != nil { 945 t.Fatalf("tx %d: failed to add transaction: %v", i, err) 946 } 947 if pool.pending[account].Len() != int(i)+1 { 948 t.Errorf("tx %d: pending pool size mismatch: have %d, want %d", i, pool.pending[account].Len(), i+1) 949 } 950 if len(pool.queue) != 0 { 951 t.Errorf("tx %d: queue size mismatch: have %d, want %d", i, pool.queue[account].Len(), 0) 952 } 953 } 954 if len(pool.all) != int(testTxPoolConfig.AccountQueue+5) { 955 t.Errorf("total transaction mismatch: have %d, want %d", len(pool.all), testTxPoolConfig.AccountQueue+5) 956 } 957 if err := validateEvents(events, int(testTxPoolConfig.AccountQueue+5)); err != nil { 958 t.Fatalf("event firing failed: %v", err) 959 } 960 if err := validateTxPoolInternals(pool); err != nil { 961 t.Fatalf("pool internal state corrupted: %v", err) 962 } 963 } 964 965 // Tests that the transaction limits are enforced the same way irrelevant whether 966 // the transactions are added one by one or in batches. 967 func TestTransactionQueueLimitingEquivalency(t *testing.T) { testTransactionLimitingEquivalency(t, 1) } 968 func TestTransactionPendingLimitingEquivalency(t *testing.T) { 969 testTransactionLimitingEquivalency(t, 0) 970 } 971 972 func testTransactionLimitingEquivalency(t *testing.T, origin uint64) { 973 t.Parallel() 974 975 // Add a batch of transactions to a pool one by one 976 pool1, key1 := setupTxPool() 977 defer pool1.Stop() 978 979 account1, _ := deriveSender(transaction(0, 0, key1)) 980 pool1.currentState.AddBalance(account1, big.NewInt(1000000)) 981 982 for i := uint64(0); i < testTxPoolConfig.AccountQueue+5; i++ { 983 if err := pool1.AddRemote(transaction(origin+i, 100000, key1)); err != nil { 984 t.Fatalf("tx %d: failed to add transaction: %v", i, err) 985 } 986 } 987 // Add a batch of transactions to a pool in one big batch 988 pool2, key2 := setupTxPool() 989 defer pool2.Stop() 990 991 account2, _ := deriveSender(transaction(0, 0, key2)) 992 pool2.currentState.AddBalance(account2, big.NewInt(1000000)) 993 994 txs := []*types.Transaction{} 995 for i := uint64(0); i < testTxPoolConfig.AccountQueue+5; i++ { 996 txs = append(txs, transaction(origin+i, 100000, key2)) 997 } 998 pool2.AddRemotes(txs) 999 1000 // Ensure the batch optimization honors the same pool mechanics 1001 if len(pool1.pending) != len(pool2.pending) { 1002 t.Errorf("pending transaction count mismatch: one-by-one algo: %d, batch algo: %d", len(pool1.pending), len(pool2.pending)) 1003 } 1004 if len(pool1.queue) != len(pool2.queue) { 1005 t.Errorf("queued transaction count mismatch: one-by-one algo: %d, batch algo: %d", len(pool1.queue), len(pool2.queue)) 1006 } 1007 if len(pool1.all) != len(pool2.all) { 1008 t.Errorf("total transaction count mismatch: one-by-one algo %d, batch algo %d", len(pool1.all), len(pool2.all)) 1009 } 1010 if err := validateTxPoolInternals(pool1); err != nil { 1011 t.Errorf("pool 1 internal state corrupted: %v", err) 1012 } 1013 if err := validateTxPoolInternals(pool2); err != nil { 1014 t.Errorf("pool 2 internal state corrupted: %v", err) 1015 } 1016 } 1017 1018 // Tests that if the transaction count belonging to multiple accounts go above 1019 // some hard threshold, the higher transactions are dropped to prevent DOS 1020 // attacks. 1021 func TestTransactionPendingGlobalLimiting(t *testing.T) { 1022 t.Parallel() 1023 1024 // Create the pool to test the limit enforcement with 1025 db := rawdb.NewMemoryDatabase() 1026 statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) 1027 blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} 1028 1029 config := testTxPoolConfig 1030 config.GlobalSlots = config.AccountSlots * 10 1031 1032 pool := NewTxPool(config, params.TestChainConfig, blockchain, nil) 1033 defer pool.Stop() 1034 1035 // Create a number of test accounts and fund them 1036 keys := make([]*ecdsa.PrivateKey, 5) 1037 for i := 0; i < len(keys); i++ { 1038 keys[i], _ = crypto.GenerateKey() 1039 pool.currentState.AddBalance(crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(1000000)) 1040 } 1041 // Generate and queue a batch of transactions 1042 nonces := make(map[common.Address]uint64) 1043 1044 txs := types.Transactions{} 1045 for _, key := range keys { 1046 addr := crypto.PubkeyToAddress(key.PublicKey) 1047 for j := 0; j < int(config.GlobalSlots)/len(keys)*2; j++ { 1048 txs = append(txs, transaction(nonces[addr], 100000, key)) 1049 nonces[addr]++ 1050 } 1051 } 1052 // Import the batch and verify that limits have been enforced 1053 pool.AddRemotes(txs) 1054 1055 pending := 0 1056 for _, list := range pool.pending { 1057 pending += list.Len() 1058 } 1059 if pending > int(config.GlobalSlots) { 1060 t.Fatalf("total pending transactions overflow allowance: %d > %d", pending, config.GlobalSlots) 1061 } 1062 if err := validateTxPoolInternals(pool); err != nil { 1063 t.Fatalf("pool internal state corrupted: %v", err) 1064 } 1065 } 1066 1067 // Tests that if transactions start being capped, transactions are also removed from 'all' 1068 func TestTransactionCapClearsFromAll(t *testing.T) { 1069 t.Parallel() 1070 1071 // Create the pool to test the limit enforcement with 1072 db := rawdb.NewMemoryDatabase() 1073 statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) 1074 blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} 1075 1076 config := testTxPoolConfig 1077 config.AccountSlots = 2 1078 config.AccountQueue = 2 1079 config.GlobalSlots = 8 1080 1081 pool := NewTxPool(config, params.TestChainConfig, blockchain, nil) 1082 defer pool.Stop() 1083 1084 // Create a number of test accounts and fund them 1085 key, _ := crypto.GenerateKey() 1086 addr := crypto.PubkeyToAddress(key.PublicKey) 1087 pool.currentState.AddBalance(addr, big.NewInt(1000000)) 1088 1089 txs := types.Transactions{} 1090 for j := 0; j < int(config.GlobalSlots)*2; j++ { 1091 txs = append(txs, transaction(uint64(j), 100000, key)) 1092 } 1093 // Import the batch and verify that limits have been enforced 1094 pool.AddRemotes(txs) 1095 if err := validateTxPoolInternals(pool); err != nil { 1096 t.Fatalf("pool internal state corrupted: %v", err) 1097 } 1098 } 1099 1100 // Tests that if the transaction count belonging to multiple accounts go above 1101 // some hard threshold, if they are under the minimum guaranteed slot count then 1102 // the transactions are still kept. 1103 func TestTransactionPendingMinimumAllowance(t *testing.T) { 1104 t.Parallel() 1105 1106 // Create the pool to test the limit enforcement with 1107 db := rawdb.NewMemoryDatabase() 1108 statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) 1109 blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} 1110 1111 config := testTxPoolConfig 1112 config.GlobalSlots = 0 1113 1114 pool := NewTxPool(config, params.TestChainConfig, blockchain, nil) 1115 defer pool.Stop() 1116 1117 // Create a number of test accounts and fund them 1118 keys := make([]*ecdsa.PrivateKey, 5) 1119 for i := 0; i < len(keys); i++ { 1120 keys[i], _ = crypto.GenerateKey() 1121 pool.currentState.AddBalance(crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(1000000)) 1122 } 1123 // Generate and queue a batch of transactions 1124 nonces := make(map[common.Address]uint64) 1125 1126 txs := types.Transactions{} 1127 for _, key := range keys { 1128 addr := crypto.PubkeyToAddress(key.PublicKey) 1129 for j := 0; j < int(config.AccountSlots)*2; j++ { 1130 txs = append(txs, transaction(nonces[addr], 100000, key)) 1131 nonces[addr]++ 1132 } 1133 } 1134 // Import the batch and verify that limits have been enforced 1135 pool.AddRemotes(txs) 1136 1137 for addr, list := range pool.pending { 1138 if list.Len() != int(config.AccountSlots) { 1139 t.Errorf("addr %x: total pending transactions mismatch: have %d, want %d", addr, list.Len(), config.AccountSlots) 1140 } 1141 } 1142 if err := validateTxPoolInternals(pool); err != nil { 1143 t.Fatalf("pool internal state corrupted: %v", err) 1144 } 1145 } 1146 1147 // Tests that setting the transaction pool gas price to a higher value correctly 1148 // discards everything cheaper than that and moves any gapped transactions back 1149 // from the pending pool to the queue. 1150 // 1151 // Note, local transactions are never allowed to be dropped. 1152 func TestTransactionPoolRepricing(t *testing.T) { 1153 t.Parallel() 1154 1155 // Create the pool to test the pricing enforcement with 1156 db := rawdb.NewMemoryDatabase() 1157 statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) 1158 blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} 1159 1160 pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain, nil) 1161 defer pool.Stop() 1162 1163 // Keep track of transaction events to ensure all executables get announced 1164 events := make(chan TxPreEvent, 32) 1165 sub := pool.txFeed.Subscribe(events) 1166 defer sub.Unsubscribe() 1167 1168 // Create a number of test accounts and fund them 1169 keys := make([]*ecdsa.PrivateKey, 4) 1170 for i := 0; i < len(keys); i++ { 1171 keys[i], _ = crypto.GenerateKey() 1172 pool.currentState.AddBalance(crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(1000000)) 1173 } 1174 // Generate and queue a batch of transactions, both pending and queued 1175 txs := types.Transactions{} 1176 1177 txs = append(txs, pricedTransaction(0, 100000, big.NewInt(2), keys[0])) 1178 txs = append(txs, pricedTransaction(1, 100000, big.NewInt(1), keys[0])) 1179 txs = append(txs, pricedTransaction(2, 100000, big.NewInt(2), keys[0])) 1180 1181 txs = append(txs, pricedTransaction(0, 100000, big.NewInt(1), keys[1])) 1182 txs = append(txs, pricedTransaction(1, 100000, big.NewInt(2), keys[1])) 1183 txs = append(txs, pricedTransaction(2, 100000, big.NewInt(2), keys[1])) 1184 1185 txs = append(txs, pricedTransaction(1, 100000, big.NewInt(2), keys[2])) 1186 txs = append(txs, pricedTransaction(2, 100000, big.NewInt(1), keys[2])) 1187 txs = append(txs, pricedTransaction(3, 100000, big.NewInt(2), keys[2])) 1188 1189 ltx := pricedTransaction(0, 100000, big.NewInt(1), keys[3]) 1190 1191 // Import the batch and that both pending and queued transactions match up 1192 pool.AddRemotes(txs) 1193 pool.AddLocal(ltx) 1194 1195 pending, queued := pool.Stats() 1196 if pending != 7 { 1197 t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 7) 1198 } 1199 if queued != 3 { 1200 t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 3) 1201 } 1202 if err := validateEvents(events, 7); err != nil { 1203 t.Fatalf("original event firing failed: %v", err) 1204 } 1205 if err := validateTxPoolInternals(pool); err != nil { 1206 t.Fatalf("pool internal state corrupted: %v", err) 1207 } 1208 // Reprice the pool and check that underpriced transactions get dropped 1209 pool.SetGasPrice(big.NewInt(2)) 1210 1211 pending, queued = pool.Stats() 1212 if pending != 2 { 1213 t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 2) 1214 } 1215 if queued != 5 { 1216 t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 5) 1217 } 1218 if err := validateEvents(events, 0); err != nil { 1219 t.Fatalf("reprice event firing failed: %v", err) 1220 } 1221 if err := validateTxPoolInternals(pool); err != nil { 1222 t.Fatalf("pool internal state corrupted: %v", err) 1223 } 1224 // Check that we can't add the old transactions back 1225 if err := pool.AddRemote(pricedTransaction(1, 100000, big.NewInt(1), keys[0])); err != ErrUnderpriced { 1226 t.Fatalf("adding underpriced pending transaction error mismatch: have %v, want %v", err, ErrUnderpriced) 1227 } 1228 if err := pool.AddRemote(pricedTransaction(0, 100000, big.NewInt(1), keys[1])); err != ErrUnderpriced { 1229 t.Fatalf("adding underpriced pending transaction error mismatch: have %v, want %v", err, ErrUnderpriced) 1230 } 1231 if err := pool.AddRemote(pricedTransaction(2, 100000, big.NewInt(1), keys[2])); err != ErrUnderpriced { 1232 t.Fatalf("adding underpriced queued transaction error mismatch: have %v, want %v", err, ErrUnderpriced) 1233 } 1234 if err := validateEvents(events, 0); err != nil { 1235 t.Fatalf("post-reprice event firing failed: %v", err) 1236 } 1237 if err := validateTxPoolInternals(pool); err != nil { 1238 t.Fatalf("pool internal state corrupted: %v", err) 1239 } 1240 // However we can add local underpriced transactions 1241 tx := pricedTransaction(1, 100000, big.NewInt(1), keys[3]) 1242 if err := pool.AddLocal(tx); err != nil { 1243 t.Fatalf("failed to add underpriced local transaction: %v", err) 1244 } 1245 if pending, _ = pool.Stats(); pending != 3 { 1246 t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 3) 1247 } 1248 if err := validateEvents(events, 1); err != nil { 1249 t.Fatalf("post-reprice local event firing failed: %v", err) 1250 } 1251 if err := validateTxPoolInternals(pool); err != nil { 1252 t.Fatalf("pool internal state corrupted: %v", err) 1253 } 1254 // And we can fill gaps with properly priced transactions 1255 if err := pool.AddRemote(pricedTransaction(1, 100000, big.NewInt(2), keys[0])); err != nil { 1256 t.Fatalf("failed to add pending transaction: %v", err) 1257 } 1258 if err := pool.AddRemote(pricedTransaction(0, 100000, big.NewInt(2), keys[1])); err != nil { 1259 t.Fatalf("failed to add pending transaction: %v", err) 1260 } 1261 if err := pool.AddRemote(pricedTransaction(2, 100000, big.NewInt(2), keys[2])); err != nil { 1262 t.Fatalf("failed to add queued transaction: %v", err) 1263 } 1264 if err := validateEvents(events, 5); err != nil { 1265 t.Fatalf("post-reprice event firing failed: %v", err) 1266 } 1267 if err := validateTxPoolInternals(pool); err != nil { 1268 t.Fatalf("pool internal state corrupted: %v", err) 1269 } 1270 } 1271 1272 // Tests that setting the transaction pool gas price to a higher value does not 1273 // remove local transactions. 1274 func TestTransactionPoolRepricingKeepsLocals(t *testing.T) { 1275 t.Parallel() 1276 1277 // Create the pool to test the pricing enforcement with 1278 db := rawdb.NewMemoryDatabase() 1279 statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) 1280 blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} 1281 1282 pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain, nil) 1283 defer pool.Stop() 1284 1285 // Create a number of test accounts and fund them 1286 keys := make([]*ecdsa.PrivateKey, 3) 1287 for i := 0; i < len(keys); i++ { 1288 keys[i], _ = crypto.GenerateKey() 1289 pool.currentState.AddBalance(crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(1000*1000000)) 1290 } 1291 // Create transaction (both pending and queued) with a linearly growing gasprice 1292 for i := uint64(0); i < 500; i++ { 1293 // Add pending 1294 p_tx := pricedTransaction(i, 100000, big.NewInt(int64(i)), keys[2]) 1295 if err := pool.AddLocal(p_tx); err != nil { 1296 t.Fatal(err) 1297 } 1298 // Add queued 1299 q_tx := pricedTransaction(i+501, 100000, big.NewInt(int64(i)), keys[2]) 1300 if err := pool.AddLocal(q_tx); err != nil { 1301 t.Fatal(err) 1302 } 1303 } 1304 pending, queued := pool.Stats() 1305 expPending, expQueued := 500, 500 1306 validate := func() { 1307 pending, queued = pool.Stats() 1308 if pending != expPending { 1309 t.Fatalf("pending transactions mismatched: have %d, want %d", pending, expPending) 1310 } 1311 if queued != expQueued { 1312 t.Fatalf("queued transactions mismatched: have %d, want %d", queued, expQueued) 1313 } 1314 1315 if err := validateTxPoolInternals(pool); err != nil { 1316 t.Fatalf("pool internal state corrupted: %v", err) 1317 } 1318 } 1319 validate() 1320 1321 // Reprice the pool and check that nothing is dropped 1322 pool.SetGasPrice(big.NewInt(2)) 1323 validate() 1324 1325 pool.SetGasPrice(big.NewInt(2)) 1326 pool.SetGasPrice(big.NewInt(4)) 1327 pool.SetGasPrice(big.NewInt(8)) 1328 pool.SetGasPrice(big.NewInt(100)) 1329 validate() 1330 } 1331 1332 // Tests that when the pool reaches its global transaction limit, underpriced 1333 // transactions are gradually shifted out for more expensive ones and any gapped 1334 // pending transactions are moved into the queue. 1335 // 1336 // Note, local transactions are never allowed to be dropped. 1337 func TestTransactionPoolUnderpricing(t *testing.T) { 1338 t.Parallel() 1339 1340 // Create the pool to test the pricing enforcement with 1341 db := rawdb.NewMemoryDatabase() 1342 statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) 1343 blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} 1344 1345 config := testTxPoolConfig 1346 config.GlobalSlots = 2 1347 config.GlobalQueue = 2 1348 1349 pool := NewTxPool(config, params.TestChainConfig, blockchain, nil) 1350 defer pool.Stop() 1351 1352 // Keep track of transaction events to ensure all executables get announced 1353 events := make(chan TxPreEvent, 32) 1354 sub := pool.txFeed.Subscribe(events) 1355 defer sub.Unsubscribe() 1356 1357 // Create a number of test accounts and fund them 1358 keys := make([]*ecdsa.PrivateKey, 3) 1359 for i := 0; i < len(keys); i++ { 1360 keys[i], _ = crypto.GenerateKey() 1361 pool.currentState.AddBalance(crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(1000000)) 1362 } 1363 // Generate and queue a batch of transactions, both pending and queued 1364 txs := types.Transactions{} 1365 1366 txs = append(txs, pricedTransaction(0, 100000, big.NewInt(1), keys[0])) 1367 txs = append(txs, pricedTransaction(1, 100000, big.NewInt(2), keys[0])) 1368 1369 txs = append(txs, pricedTransaction(1, 100000, big.NewInt(1), keys[1])) 1370 1371 ltx := pricedTransaction(0, 100000, big.NewInt(1), keys[2]) 1372 1373 // Import the batch and that both pending and queued transactions match up 1374 pool.AddRemotes(txs) 1375 pool.AddLocal(ltx) 1376 1377 pending, queued := pool.Stats() 1378 if pending != 3 { 1379 t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 3) 1380 } 1381 if queued != 1 { 1382 t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 1) 1383 } 1384 if err := validateEvents(events, 3); err != nil { 1385 t.Fatalf("original event firing failed: %v", err) 1386 } 1387 if err := validateTxPoolInternals(pool); err != nil { 1388 t.Fatalf("pool internal state corrupted: %v", err) 1389 } 1390 // Ensure that adding an underpriced transaction on block limit fails 1391 if err := pool.AddRemote(pricedTransaction(0, 100000, big.NewInt(1), keys[1])); err != ErrUnderpriced { 1392 t.Fatalf("adding underpriced pending transaction error mismatch: have %v, want %v", err, ErrUnderpriced) 1393 } 1394 // Ensure that adding high priced transactions drops cheap ones, but not own 1395 if err := pool.AddRemote(pricedTransaction(0, 100000, big.NewInt(3), keys[1])); err != nil { 1396 t.Fatalf("failed to add well priced transaction: %v", err) 1397 } 1398 if err := pool.AddRemote(pricedTransaction(2, 100000, big.NewInt(4), keys[1])); err != nil { 1399 t.Fatalf("failed to add well priced transaction: %v", err) 1400 } 1401 if err := pool.AddRemote(pricedTransaction(3, 100000, big.NewInt(5), keys[1])); err != nil { 1402 t.Fatalf("failed to add well priced transaction: %v", err) 1403 } 1404 pending, queued = pool.Stats() 1405 if pending != 2 { 1406 t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 2) 1407 } 1408 if queued != 2 { 1409 t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 2) 1410 } 1411 if err := validateEvents(events, 2); err != nil { 1412 t.Fatalf("additional event firing failed: %v", err) 1413 } 1414 if err := validateTxPoolInternals(pool); err != nil { 1415 t.Fatalf("pool internal state corrupted: %v", err) 1416 } 1417 // Ensure that adding local transactions can push out even higher priced ones 1418 tx := pricedTransaction(1, 100000, big.NewInt(0), keys[2]) 1419 if err := pool.AddLocal(tx); err != nil { 1420 t.Fatalf("failed to add underpriced local transaction: %v", err) 1421 } 1422 pending, queued = pool.Stats() 1423 if pending != 2 { 1424 t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 2) 1425 } 1426 if queued != 2 { 1427 t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 2) 1428 } 1429 if err := validateEvents(events, 1); err != nil { 1430 t.Fatalf("local event firing failed: %v", err) 1431 } 1432 if err := validateTxPoolInternals(pool); err != nil { 1433 t.Fatalf("pool internal state corrupted: %v", err) 1434 } 1435 } 1436 1437 // Tests that the pool rejects replacement transactions that don't meet the minimum 1438 // price bump required. 1439 func TestTransactionReplacement(t *testing.T) { 1440 t.Parallel() 1441 1442 // Create the pool to test the pricing enforcement with 1443 db := rawdb.NewMemoryDatabase() 1444 statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) 1445 blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} 1446 1447 pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain, nil) 1448 defer pool.Stop() 1449 1450 // Keep track of transaction events to ensure all executables get announced 1451 events := make(chan TxPreEvent, 32) 1452 sub := pool.txFeed.Subscribe(events) 1453 defer sub.Unsubscribe() 1454 1455 // Create a test account to add transactions with 1456 key, _ := crypto.GenerateKey() 1457 pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(1000000000)) 1458 1459 // Add pending transactions, ensuring the minimum price bump is enforced for replacement (for ultra low prices too) 1460 price := int64(100) 1461 threshold := (price * (100 + int64(testTxPoolConfig.PriceBump))) / 100 1462 1463 if err := pool.AddRemote(pricedTransaction(0, 100000, big.NewInt(1), key)); err != nil { 1464 t.Fatalf("failed to add original cheap pending transaction: %v", err) 1465 } 1466 if err := pool.AddRemote(pricedTransaction(0, 100001, big.NewInt(1), key)); err != ErrReplaceUnderpriced { 1467 t.Fatalf("original cheap pending transaction replacement error mismatch: have %v, want %v", err, ErrReplaceUnderpriced) 1468 } 1469 if err := pool.AddRemote(pricedTransaction(0, 100000, big.NewInt(2), key)); err != nil { 1470 t.Fatalf("failed to replace original cheap pending transaction: %v", err) 1471 } 1472 if err := validateEvents(events, 2); err != nil { 1473 t.Fatalf("cheap replacement event firing failed: %v", err) 1474 } 1475 1476 if err := pool.AddRemote(pricedTransaction(0, 100000, big.NewInt(price), key)); err != nil { 1477 t.Fatalf("failed to add original proper pending transaction: %v", err) 1478 } 1479 if err := pool.AddRemote(pricedTransaction(0, 100001, big.NewInt(threshold-1), key)); err != ErrReplaceUnderpriced { 1480 t.Fatalf("original proper pending transaction replacement error mismatch: have %v, want %v", err, ErrReplaceUnderpriced) 1481 } 1482 if err := pool.AddRemote(pricedTransaction(0, 100000, big.NewInt(threshold), key)); err != nil { 1483 t.Fatalf("failed to replace original proper pending transaction: %v", err) 1484 } 1485 if err := validateEvents(events, 2); err != nil { 1486 t.Fatalf("proper replacement event firing failed: %v", err) 1487 } 1488 // Add queued transactions, ensuring the minimum price bump is enforced for replacement (for ultra low prices too) 1489 if err := pool.AddRemote(pricedTransaction(2, 100000, big.NewInt(1), key)); err != nil { 1490 t.Fatalf("failed to add original cheap queued transaction: %v", err) 1491 } 1492 if err := pool.AddRemote(pricedTransaction(2, 100001, big.NewInt(1), key)); err != ErrReplaceUnderpriced { 1493 t.Fatalf("original cheap queued transaction replacement error mismatch: have %v, want %v", err, ErrReplaceUnderpriced) 1494 } 1495 if err := pool.AddRemote(pricedTransaction(2, 100000, big.NewInt(2), key)); err != nil { 1496 t.Fatalf("failed to replace original cheap queued transaction: %v", err) 1497 } 1498 1499 if err := pool.AddRemote(pricedTransaction(2, 100000, big.NewInt(price), key)); err != nil { 1500 t.Fatalf("failed to add original proper queued transaction: %v", err) 1501 } 1502 if err := pool.AddRemote(pricedTransaction(2, 100001, big.NewInt(threshold-1), key)); err != ErrReplaceUnderpriced { 1503 t.Fatalf("original proper queued transaction replacement error mismatch: have %v, want %v", err, ErrReplaceUnderpriced) 1504 } 1505 if err := pool.AddRemote(pricedTransaction(2, 100000, big.NewInt(threshold), key)); err != nil { 1506 t.Fatalf("failed to replace original proper queued transaction: %v", err) 1507 } 1508 1509 if err := validateEvents(events, 0); err != nil { 1510 t.Fatalf("queued replacement event firing failed: %v", err) 1511 } 1512 if err := validateTxPoolInternals(pool); err != nil { 1513 t.Fatalf("pool internal state corrupted: %v", err) 1514 } 1515 } 1516 1517 // Tests that local transactions are journaled to disk, but remote transactions 1518 // get discarded between restarts. 1519 func TestTransactionJournaling(t *testing.T) { testTransactionJournaling(t, false) } 1520 func TestTransactionJournalingNoLocals(t *testing.T) { testTransactionJournaling(t, true) } 1521 1522 func testTransactionJournaling(t *testing.T, nolocals bool) { 1523 t.Parallel() 1524 1525 // Create a temporary file for the journal 1526 file, err := ioutil.TempFile("", "") 1527 if err != nil { 1528 t.Fatalf("failed to create temporary journal: %v", err) 1529 } 1530 journal := file.Name() 1531 defer os.Remove(journal) 1532 1533 // Clean up the temporary file, we only need the path for now 1534 file.Close() 1535 os.Remove(journal) 1536 1537 // Create the original pool to inject transaction into the journal 1538 db := rawdb.NewMemoryDatabase() 1539 statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) 1540 blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} 1541 1542 config := testTxPoolConfig 1543 config.NoLocals = nolocals 1544 config.Journal = journal 1545 config.Rejournal = time.Second 1546 1547 pool := NewTxPool(config, params.TestChainConfig, blockchain, nil) 1548 1549 // Create two test accounts to ensure remotes expire but locals do not 1550 local, _ := crypto.GenerateKey() 1551 remote, _ := crypto.GenerateKey() 1552 1553 pool.currentState.AddBalance(crypto.PubkeyToAddress(local.PublicKey), big.NewInt(1000000000)) 1554 pool.currentState.AddBalance(crypto.PubkeyToAddress(remote.PublicKey), big.NewInt(1000000000)) 1555 1556 // Add three local and a remote transactions and ensure they are queued up 1557 if err := pool.AddLocal(pricedTransaction(0, 100000, big.NewInt(1), local)); err != nil { 1558 t.Fatalf("failed to add local transaction: %v", err) 1559 } 1560 if err := pool.AddLocal(pricedTransaction(1, 100000, big.NewInt(1), local)); err != nil { 1561 t.Fatalf("failed to add local transaction: %v", err) 1562 } 1563 if err := pool.AddLocal(pricedTransaction(2, 100000, big.NewInt(1), local)); err != nil { 1564 t.Fatalf("failed to add local transaction: %v", err) 1565 } 1566 if err := pool.AddRemote(pricedTransaction(0, 100000, big.NewInt(1), remote)); err != nil { 1567 t.Fatalf("failed to add remote transaction: %v", err) 1568 } 1569 pending, queued := pool.Stats() 1570 if pending != 4 { 1571 t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 4) 1572 } 1573 if queued != 0 { 1574 t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 0) 1575 } 1576 if err := validateTxPoolInternals(pool); err != nil { 1577 t.Fatalf("pool internal state corrupted: %v", err) 1578 } 1579 // Terminate the old pool, bump the local nonce, create a new pool and ensure relevant transaction survive 1580 pool.Stop() 1581 statedb.SetNonce(crypto.PubkeyToAddress(local.PublicKey), 1) 1582 blockchain = &testBlockChain{statedb, 1000000, new(event.Feed)} 1583 1584 pool = NewTxPool(config, params.TestChainConfig, blockchain, nil) 1585 1586 pending, queued = pool.Stats() 1587 if queued != 0 { 1588 t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 0) 1589 } 1590 if nolocals { 1591 if pending != 0 { 1592 t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 0) 1593 } 1594 } else { 1595 if pending != 2 { 1596 t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 2) 1597 } 1598 } 1599 if err := validateTxPoolInternals(pool); err != nil { 1600 t.Fatalf("pool internal state corrupted: %v", err) 1601 } 1602 // Bump the nonce temporarily and ensure the newly invalidated transaction is removed 1603 statedb.SetNonce(crypto.PubkeyToAddress(local.PublicKey), 2) 1604 pool.lockedReset(nil, nil) 1605 time.Sleep(2 * config.Rejournal) 1606 pool.Stop() 1607 1608 statedb.SetNonce(crypto.PubkeyToAddress(local.PublicKey), 1) 1609 blockchain = &testBlockChain{statedb, 1000000, new(event.Feed)} 1610 pool = NewTxPool(config, params.TestChainConfig, blockchain, nil) 1611 1612 pending, queued = pool.Stats() 1613 if pending != 0 { 1614 t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 0) 1615 } 1616 if nolocals { 1617 if queued != 0 { 1618 t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 0) 1619 } 1620 } else { 1621 if queued != 1 { 1622 t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 1) 1623 } 1624 } 1625 if err := validateTxPoolInternals(pool); err != nil { 1626 t.Fatalf("pool internal state corrupted: %v", err) 1627 } 1628 pool.Stop() 1629 } 1630 1631 // TestTransactionStatusCheck tests that the pool can correctly retrieve the 1632 // pending status of individual transactions. 1633 func TestTransactionStatusCheck(t *testing.T) { 1634 t.Parallel() 1635 1636 // Create the pool to test the status retrievals with 1637 db := rawdb.NewMemoryDatabase() 1638 statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) 1639 blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} 1640 1641 pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain, nil) 1642 defer pool.Stop() 1643 1644 // Create the test accounts to check various transaction statuses with 1645 keys := make([]*ecdsa.PrivateKey, 3) 1646 for i := 0; i < len(keys); i++ { 1647 keys[i], _ = crypto.GenerateKey() 1648 pool.currentState.AddBalance(crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(1000000)) 1649 } 1650 // Generate and queue a batch of transactions, both pending and queued 1651 txs := types.Transactions{} 1652 1653 txs = append(txs, pricedTransaction(0, 100000, big.NewInt(1), keys[0])) // Pending only 1654 txs = append(txs, pricedTransaction(0, 100000, big.NewInt(1), keys[1])) // Pending and queued 1655 txs = append(txs, pricedTransaction(2, 100000, big.NewInt(1), keys[1])) 1656 txs = append(txs, pricedTransaction(2, 100000, big.NewInt(1), keys[2])) // Queued only 1657 1658 // Import the transaction and ensure they are correctly added 1659 pool.AddRemotes(txs) 1660 1661 pending, queued := pool.Stats() 1662 if pending != 2 { 1663 t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 2) 1664 } 1665 if queued != 2 { 1666 t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 2) 1667 } 1668 if err := validateTxPoolInternals(pool); err != nil { 1669 t.Fatalf("pool internal state corrupted: %v", err) 1670 } 1671 // Retrieve the status of each transaction and validate them 1672 hashes := make([]common.Hash, len(txs)) 1673 for i, tx := range txs { 1674 hashes[i] = tx.Hash() 1675 } 1676 hashes = append(hashes, common.Hash{}) 1677 1678 statuses := pool.Status(hashes) 1679 expect := []TxStatus{TxStatusPending, TxStatusPending, TxStatusQueued, TxStatusQueued, TxStatusUnknown} 1680 1681 for i := 0; i < len(statuses); i++ { 1682 if statuses[i] != expect[i] { 1683 t.Errorf("transaction %d: status mismatch: have %v, want %v", i, statuses[i], expect[i]) 1684 } 1685 } 1686 } 1687 1688 // Benchmarks the speed of validating the contents of the pending queue of the 1689 // transaction pool. 1690 func BenchmarkPendingDemotion100(b *testing.B) { benchmarkPendingDemotion(b, 100) } 1691 func BenchmarkPendingDemotion1000(b *testing.B) { benchmarkPendingDemotion(b, 1000) } 1692 func BenchmarkPendingDemotion10000(b *testing.B) { benchmarkPendingDemotion(b, 10000) } 1693 1694 func benchmarkPendingDemotion(b *testing.B, size int) { 1695 // Add a batch of transactions to a pool one by one 1696 pool, key := setupTxPool() 1697 defer pool.Stop() 1698 1699 account, _ := deriveSender(transaction(0, 0, key)) 1700 pool.currentState.AddBalance(account, big.NewInt(1000000)) 1701 1702 for i := 0; i < size; i++ { 1703 tx := transaction(uint64(i), 100000, key) 1704 pool.promoteTx(account, tx.Hash(), tx) 1705 } 1706 // Benchmark the speed of pool validation 1707 b.ResetTimer() 1708 for i := 0; i < b.N; i++ { 1709 pool.demoteUnexecutables() 1710 } 1711 } 1712 1713 // Benchmarks the speed of scheduling the contents of the future queue of the 1714 // transaction pool. 1715 func BenchmarkFuturePromotion100(b *testing.B) { benchmarkFuturePromotion(b, 100) } 1716 func BenchmarkFuturePromotion1000(b *testing.B) { benchmarkFuturePromotion(b, 1000) } 1717 func BenchmarkFuturePromotion10000(b *testing.B) { benchmarkFuturePromotion(b, 10000) } 1718 1719 func benchmarkFuturePromotion(b *testing.B, size int) { 1720 // Add a batch of transactions to a pool one by one 1721 pool, key := setupTxPool() 1722 defer pool.Stop() 1723 1724 account, _ := deriveSender(transaction(0, 0, key)) 1725 pool.currentState.AddBalance(account, big.NewInt(1000000)) 1726 1727 for i := 0; i < size; i++ { 1728 tx := transaction(uint64(1+i), 100000, key) 1729 pool.enqueueTx(tx.Hash(), tx) 1730 } 1731 // Benchmark the speed of pool validation 1732 b.ResetTimer() 1733 for i := 0; i < b.N; i++ { 1734 pool.promoteExecutables(nil) 1735 } 1736 } 1737 1738 // Benchmarks the speed of iterative transaction insertion. 1739 func BenchmarkPoolInsert(b *testing.B) { 1740 // Generate a batch of transactions to enqueue into the pool 1741 pool, key := setupTxPool() 1742 defer pool.Stop() 1743 1744 account, _ := deriveSender(transaction(0, 0, key)) 1745 pool.currentState.AddBalance(account, big.NewInt(1000000)) 1746 1747 txs := make(types.Transactions, b.N) 1748 for i := 0; i < b.N; i++ { 1749 txs[i] = transaction(uint64(i), 100000, key) 1750 } 1751 // Benchmark importing the transactions into the queue 1752 b.ResetTimer() 1753 for _, tx := range txs { 1754 pool.AddRemote(tx) 1755 } 1756 } 1757 1758 // Benchmarks the speed of batched transaction insertion. 1759 func BenchmarkPoolBatchInsert100(b *testing.B) { benchmarkPoolBatchInsert(b, 100) } 1760 func BenchmarkPoolBatchInsert1000(b *testing.B) { benchmarkPoolBatchInsert(b, 1000) } 1761 func BenchmarkPoolBatchInsert10000(b *testing.B) { benchmarkPoolBatchInsert(b, 10000) } 1762 1763 func benchmarkPoolBatchInsert(b *testing.B, size int) { 1764 // Generate a batch of transactions to enqueue into the pool 1765 pool, key := setupTxPool() 1766 defer pool.Stop() 1767 1768 account, _ := deriveSender(transaction(0, 0, key)) 1769 pool.currentState.AddBalance(account, big.NewInt(1000000)) 1770 1771 batches := make([]types.Transactions, b.N) 1772 for i := 0; i < b.N; i++ { 1773 batches[i] = make(types.Transactions, size) 1774 for j := 0; j < size; j++ { 1775 batches[i][j] = transaction(uint64(size*i+j), 100000, key) 1776 } 1777 } 1778 // Benchmark importing the transactions into the queue 1779 b.ResetTimer() 1780 for _, batch := range batches { 1781 pool.AddRemotes(batch) 1782 } 1783 }