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