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