github.com/alanchchen/go-ethereum@v1.6.6-0.20170601190819-6171d01b1195/core/tx_pool_test.go (about) 1 // Copyright 2015 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package core 18 19 import ( 20 "crypto/ecdsa" 21 "math/big" 22 "math/rand" 23 "testing" 24 "time" 25 26 "github.com/ethereum/go-ethereum/common" 27 "github.com/ethereum/go-ethereum/core/state" 28 "github.com/ethereum/go-ethereum/core/types" 29 "github.com/ethereum/go-ethereum/crypto" 30 "github.com/ethereum/go-ethereum/ethdb" 31 "github.com/ethereum/go-ethereum/event" 32 "github.com/ethereum/go-ethereum/params" 33 ) 34 35 func transaction(nonce uint64, gaslimit *big.Int, key *ecdsa.PrivateKey) *types.Transaction { 36 return pricedTransaction(nonce, gaslimit, big.NewInt(1), key) 37 } 38 39 func pricedTransaction(nonce uint64, gaslimit, gasprice *big.Int, key *ecdsa.PrivateKey) *types.Transaction { 40 tx, _ := types.SignTx(types.NewTransaction(nonce, common.Address{}, big.NewInt(100), gaslimit, gasprice, nil), types.HomesteadSigner{}, key) 41 return tx 42 } 43 44 func setupTxPool() (*TxPool, *ecdsa.PrivateKey) { 45 db, _ := ethdb.NewMemDatabase() 46 statedb, _ := state.New(common.Hash{}, db) 47 48 key, _ := crypto.GenerateKey() 49 newPool := NewTxPool(DefaultTxPoolConfig, params.TestChainConfig, new(event.TypeMux), func() (*state.StateDB, error) { return statedb, nil }, func() *big.Int { return big.NewInt(1000000) }) 50 newPool.resetState() 51 52 return newPool, key 53 } 54 55 func deriveSender(tx *types.Transaction) (common.Address, error) { 56 return types.Sender(types.HomesteadSigner{}, tx) 57 } 58 59 // This test simulates a scenario where a new block is imported during a 60 // state reset and tests whether the pending state is in sync with the 61 // block head event that initiated the resetState(). 62 func TestStateChangeDuringPoolReset(t *testing.T) { 63 var ( 64 db, _ = ethdb.NewMemDatabase() 65 key, _ = crypto.GenerateKey() 66 address = crypto.PubkeyToAddress(key.PublicKey) 67 mux = new(event.TypeMux) 68 statedb, _ = state.New(common.Hash{}, db) 69 trigger = false 70 ) 71 72 // setup pool with 2 transaction in it 73 statedb.SetBalance(address, new(big.Int).SetUint64(params.Ether)) 74 75 tx0 := transaction(0, big.NewInt(100000), key) 76 tx1 := transaction(1, big.NewInt(100000), key) 77 78 // stateFunc is used multiple times to reset the pending state. 79 // when simulate is true it will create a state that indicates 80 // that tx0 and tx1 are included in the chain. 81 stateFunc := func() (*state.StateDB, error) { 82 // delay "state change" by one. The tx pool fetches the 83 // state multiple times and by delaying it a bit we simulate 84 // a state change between those fetches. 85 stdb := statedb 86 if trigger { 87 statedb, _ = state.New(common.Hash{}, db) 88 // simulate that the new head block included tx0 and tx1 89 statedb.SetNonce(address, 2) 90 statedb.SetBalance(address, new(big.Int).SetUint64(params.Ether)) 91 trigger = false 92 } 93 return stdb, nil 94 } 95 96 gasLimitFunc := func() *big.Int { return big.NewInt(1000000000) } 97 98 txpool := NewTxPool(DefaultTxPoolConfig, params.TestChainConfig, mux, stateFunc, gasLimitFunc) 99 txpool.resetState() 100 101 nonce := txpool.State().GetNonce(address) 102 if nonce != 0 { 103 t.Fatalf("Invalid nonce, want 0, got %d", nonce) 104 } 105 106 txpool.AddBatch(types.Transactions{tx0, tx1}) 107 108 nonce = txpool.State().GetNonce(address) 109 if nonce != 2 { 110 t.Fatalf("Invalid nonce, want 2, got %d", nonce) 111 } 112 113 // trigger state change in the background 114 trigger = true 115 116 txpool.resetState() 117 118 pendingTx, err := txpool.Pending() 119 if err != nil { 120 t.Fatalf("Could not fetch pending transactions: %v", err) 121 } 122 123 for addr, txs := range pendingTx { 124 t.Logf("%0x: %d\n", addr, len(txs)) 125 } 126 127 nonce = txpool.State().GetNonce(address) 128 if nonce != 2 { 129 t.Fatalf("Invalid nonce, want 2, got %d", nonce) 130 } 131 } 132 133 func TestInvalidTransactions(t *testing.T) { 134 pool, key := setupTxPool() 135 136 tx := transaction(0, big.NewInt(100), key) 137 from, _ := deriveSender(tx) 138 currentState, _ := pool.currentState() 139 currentState.AddBalance(from, big.NewInt(1)) 140 if err := pool.Add(tx); err != ErrInsufficientFunds { 141 t.Error("expected", ErrInsufficientFunds) 142 } 143 144 balance := new(big.Int).Add(tx.Value(), new(big.Int).Mul(tx.Gas(), tx.GasPrice())) 145 currentState.AddBalance(from, balance) 146 if err := pool.Add(tx); err != ErrIntrinsicGas { 147 t.Error("expected", ErrIntrinsicGas, "got", err) 148 } 149 150 currentState.SetNonce(from, 1) 151 currentState.AddBalance(from, big.NewInt(0xffffffffffffff)) 152 tx = transaction(0, big.NewInt(100000), key) 153 if err := pool.Add(tx); err != ErrNonce { 154 t.Error("expected", ErrNonce) 155 } 156 157 tx = transaction(1, big.NewInt(100000), key) 158 pool.gasPrice = big.NewInt(1000) 159 if err := pool.Add(tx); err != ErrUnderpriced { 160 t.Error("expected", ErrUnderpriced, "got", err) 161 } 162 163 pool.SetLocal(tx) 164 if err := pool.Add(tx); err != nil { 165 t.Error("expected", nil, "got", err) 166 } 167 } 168 169 func TestTransactionQueue(t *testing.T) { 170 pool, key := setupTxPool() 171 tx := transaction(0, big.NewInt(100), key) 172 from, _ := deriveSender(tx) 173 currentState, _ := pool.currentState() 174 currentState.AddBalance(from, big.NewInt(1000)) 175 pool.resetState() 176 pool.enqueueTx(tx.Hash(), tx) 177 178 pool.promoteExecutables(currentState, []common.Address{from}) 179 if len(pool.pending) != 1 { 180 t.Error("expected valid txs to be 1 is", len(pool.pending)) 181 } 182 183 tx = transaction(1, big.NewInt(100), key) 184 from, _ = deriveSender(tx) 185 currentState.SetNonce(from, 2) 186 pool.enqueueTx(tx.Hash(), tx) 187 pool.promoteExecutables(currentState, []common.Address{from}) 188 if _, ok := pool.pending[from].txs.items[tx.Nonce()]; ok { 189 t.Error("expected transaction to be in tx pool") 190 } 191 192 if len(pool.queue) > 0 { 193 t.Error("expected transaction queue to be empty. is", len(pool.queue)) 194 } 195 196 pool, key = setupTxPool() 197 tx1 := transaction(0, big.NewInt(100), key) 198 tx2 := transaction(10, big.NewInt(100), key) 199 tx3 := transaction(11, big.NewInt(100), key) 200 from, _ = deriveSender(tx1) 201 currentState, _ = pool.currentState() 202 currentState.AddBalance(from, big.NewInt(1000)) 203 pool.resetState() 204 205 pool.enqueueTx(tx1.Hash(), tx1) 206 pool.enqueueTx(tx2.Hash(), tx2) 207 pool.enqueueTx(tx3.Hash(), tx3) 208 209 pool.promoteExecutables(currentState, []common.Address{from}) 210 211 if len(pool.pending) != 1 { 212 t.Error("expected tx pool to be 1, got", len(pool.pending)) 213 } 214 if pool.queue[from].Len() != 2 { 215 t.Error("expected len(queue) == 2, got", pool.queue[from].Len()) 216 } 217 } 218 219 func TestRemoveTx(t *testing.T) { 220 pool, key := setupTxPool() 221 tx := transaction(0, big.NewInt(100), key) 222 from, _ := deriveSender(tx) 223 currentState, _ := pool.currentState() 224 currentState.AddBalance(from, big.NewInt(1)) 225 226 pool.enqueueTx(tx.Hash(), tx) 227 pool.promoteTx(from, tx.Hash(), tx) 228 if len(pool.queue) != 1 { 229 t.Error("expected queue to be 1, got", len(pool.queue)) 230 } 231 if len(pool.pending) != 1 { 232 t.Error("expected pending to be 1, got", len(pool.pending)) 233 } 234 pool.Remove(tx.Hash()) 235 if len(pool.queue) > 0 { 236 t.Error("expected queue to be 0, got", len(pool.queue)) 237 } 238 if len(pool.pending) > 0 { 239 t.Error("expected pending to be 0, got", len(pool.pending)) 240 } 241 } 242 243 func TestNegativeValue(t *testing.T) { 244 pool, key := setupTxPool() 245 246 tx, _ := types.SignTx(types.NewTransaction(0, common.Address{}, big.NewInt(-1), big.NewInt(100), big.NewInt(1), nil), types.HomesteadSigner{}, key) 247 from, _ := deriveSender(tx) 248 currentState, _ := pool.currentState() 249 currentState.AddBalance(from, big.NewInt(1)) 250 if err := pool.Add(tx); err != ErrNegativeValue { 251 t.Error("expected", ErrNegativeValue, "got", err) 252 } 253 } 254 255 func TestTransactionChainFork(t *testing.T) { 256 pool, key := setupTxPool() 257 addr := crypto.PubkeyToAddress(key.PublicKey) 258 resetState := func() { 259 db, _ := ethdb.NewMemDatabase() 260 statedb, _ := state.New(common.Hash{}, db) 261 pool.currentState = func() (*state.StateDB, error) { return statedb, nil } 262 currentState, _ := pool.currentState() 263 currentState.AddBalance(addr, big.NewInt(100000000000000)) 264 pool.resetState() 265 } 266 resetState() 267 268 tx := transaction(0, big.NewInt(100000), key) 269 if _, err := pool.add(tx); err != nil { 270 t.Error("didn't expect error", err) 271 } 272 pool.RemoveBatch([]*types.Transaction{tx}) 273 274 // reset the pool's internal state 275 resetState() 276 if _, err := pool.add(tx); err != nil { 277 t.Error("didn't expect error", err) 278 } 279 } 280 281 func TestTransactionDoubleNonce(t *testing.T) { 282 pool, key := setupTxPool() 283 addr := crypto.PubkeyToAddress(key.PublicKey) 284 resetState := func() { 285 db, _ := ethdb.NewMemDatabase() 286 statedb, _ := state.New(common.Hash{}, db) 287 pool.currentState = func() (*state.StateDB, error) { return statedb, nil } 288 currentState, _ := pool.currentState() 289 currentState.AddBalance(addr, big.NewInt(100000000000000)) 290 pool.resetState() 291 } 292 resetState() 293 294 signer := types.HomesteadSigner{} 295 tx1, _ := types.SignTx(types.NewTransaction(0, common.Address{}, big.NewInt(100), big.NewInt(100000), big.NewInt(1), nil), signer, key) 296 tx2, _ := types.SignTx(types.NewTransaction(0, common.Address{}, big.NewInt(100), big.NewInt(1000000), big.NewInt(2), nil), signer, key) 297 tx3, _ := types.SignTx(types.NewTransaction(0, common.Address{}, big.NewInt(100), big.NewInt(1000000), big.NewInt(1), nil), signer, key) 298 299 // Add the first two transaction, ensure higher priced stays only 300 if replace, err := pool.add(tx1); err != nil || replace { 301 t.Errorf("first transaction insert failed (%v) or reported replacement (%v)", err, replace) 302 } 303 if replace, err := pool.add(tx2); err != nil || !replace { 304 t.Errorf("second transaction insert failed (%v) or not reported replacement (%v)", err, replace) 305 } 306 state, _ := pool.currentState() 307 pool.promoteExecutables(state, []common.Address{addr}) 308 if pool.pending[addr].Len() != 1 { 309 t.Error("expected 1 pending transactions, got", pool.pending[addr].Len()) 310 } 311 if tx := pool.pending[addr].txs.items[0]; tx.Hash() != tx2.Hash() { 312 t.Errorf("transaction mismatch: have %x, want %x", tx.Hash(), tx2.Hash()) 313 } 314 // Add the third transaction and ensure it's not saved (smaller price) 315 pool.add(tx3) 316 pool.promoteExecutables(state, []common.Address{addr}) 317 if pool.pending[addr].Len() != 1 { 318 t.Error("expected 1 pending transactions, got", pool.pending[addr].Len()) 319 } 320 if tx := pool.pending[addr].txs.items[0]; tx.Hash() != tx2.Hash() { 321 t.Errorf("transaction mismatch: have %x, want %x", tx.Hash(), tx2.Hash()) 322 } 323 // Ensure the total transaction count is correct 324 if len(pool.all) != 1 { 325 t.Error("expected 1 total transactions, got", len(pool.all)) 326 } 327 } 328 329 func TestMissingNonce(t *testing.T) { 330 pool, key := setupTxPool() 331 addr := crypto.PubkeyToAddress(key.PublicKey) 332 currentState, _ := pool.currentState() 333 currentState.AddBalance(addr, big.NewInt(100000000000000)) 334 tx := transaction(1, big.NewInt(100000), key) 335 if _, err := pool.add(tx); err != nil { 336 t.Error("didn't expect error", err) 337 } 338 if len(pool.pending) != 0 { 339 t.Error("expected 0 pending transactions, got", len(pool.pending)) 340 } 341 if pool.queue[addr].Len() != 1 { 342 t.Error("expected 1 queued transaction, got", pool.queue[addr].Len()) 343 } 344 if len(pool.all) != 1 { 345 t.Error("expected 1 total transactions, got", len(pool.all)) 346 } 347 } 348 349 func TestNonceRecovery(t *testing.T) { 350 const n = 10 351 pool, key := setupTxPool() 352 addr := crypto.PubkeyToAddress(key.PublicKey) 353 currentState, _ := pool.currentState() 354 currentState.SetNonce(addr, n) 355 currentState.AddBalance(addr, big.NewInt(100000000000000)) 356 pool.resetState() 357 tx := transaction(n, big.NewInt(100000), key) 358 if err := pool.Add(tx); err != nil { 359 t.Error(err) 360 } 361 // simulate some weird re-order of transactions and missing nonce(s) 362 currentState.SetNonce(addr, n-1) 363 pool.resetState() 364 if fn := pool.pendingState.GetNonce(addr); fn != n+1 { 365 t.Errorf("expected nonce to be %d, got %d", n+1, fn) 366 } 367 } 368 369 func TestRemovedTxEvent(t *testing.T) { 370 pool, key := setupTxPool() 371 tx := transaction(0, big.NewInt(1000000), key) 372 from, _ := deriveSender(tx) 373 currentState, _ := pool.currentState() 374 currentState.AddBalance(from, big.NewInt(1000000000000)) 375 pool.resetState() 376 pool.eventMux.Post(RemovedTransactionEvent{types.Transactions{tx}}) 377 pool.eventMux.Post(ChainHeadEvent{nil}) 378 if pool.pending[from].Len() != 1 { 379 t.Error("expected 1 pending tx, got", pool.pending[from].Len()) 380 } 381 if len(pool.all) != 1 { 382 t.Error("expected 1 total transactions, got", len(pool.all)) 383 } 384 } 385 386 // Tests that if an account runs out of funds, any pending and queued transactions 387 // are dropped. 388 func TestTransactionDropping(t *testing.T) { 389 // Create a test account and fund it 390 pool, key := setupTxPool() 391 account, _ := deriveSender(transaction(0, big.NewInt(0), key)) 392 393 state, _ := pool.currentState() 394 state.AddBalance(account, big.NewInt(1000)) 395 396 // Add some pending and some queued transactions 397 var ( 398 tx0 = transaction(0, big.NewInt(100), key) 399 tx1 = transaction(1, big.NewInt(200), key) 400 tx2 = transaction(2, big.NewInt(300), key) 401 tx10 = transaction(10, big.NewInt(100), key) 402 tx11 = transaction(11, big.NewInt(200), key) 403 tx12 = transaction(12, big.NewInt(300), key) 404 ) 405 pool.promoteTx(account, tx0.Hash(), tx0) 406 pool.promoteTx(account, tx1.Hash(), tx1) 407 pool.promoteTx(account, tx1.Hash(), tx2) 408 pool.enqueueTx(tx10.Hash(), tx10) 409 pool.enqueueTx(tx11.Hash(), tx11) 410 pool.enqueueTx(tx11.Hash(), tx12) 411 412 // Check that pre and post validations leave the pool as is 413 if pool.pending[account].Len() != 3 { 414 t.Errorf("pending transaction mismatch: have %d, want %d", pool.pending[account].Len(), 3) 415 } 416 if pool.queue[account].Len() != 3 { 417 t.Errorf("queued transaction mismatch: have %d, want %d", pool.queue[account].Len(), 3) 418 } 419 if len(pool.all) != 4 { 420 t.Errorf("total transaction mismatch: have %d, want %d", len(pool.all), 4) 421 } 422 pool.resetState() 423 if pool.pending[account].Len() != 3 { 424 t.Errorf("pending transaction mismatch: have %d, want %d", pool.pending[account].Len(), 3) 425 } 426 if pool.queue[account].Len() != 3 { 427 t.Errorf("queued transaction mismatch: have %d, want %d", pool.queue[account].Len(), 3) 428 } 429 if len(pool.all) != 4 { 430 t.Errorf("total transaction mismatch: have %d, want %d", len(pool.all), 4) 431 } 432 // Reduce the balance of the account, and check that invalidated transactions are dropped 433 state.AddBalance(account, big.NewInt(-650)) 434 pool.resetState() 435 436 if _, ok := pool.pending[account].txs.items[tx0.Nonce()]; !ok { 437 t.Errorf("funded pending transaction missing: %v", tx0) 438 } 439 if _, ok := pool.pending[account].txs.items[tx1.Nonce()]; !ok { 440 t.Errorf("funded pending transaction missing: %v", tx0) 441 } 442 if _, ok := pool.pending[account].txs.items[tx2.Nonce()]; ok { 443 t.Errorf("out-of-fund pending transaction present: %v", tx1) 444 } 445 if _, ok := pool.queue[account].txs.items[tx10.Nonce()]; !ok { 446 t.Errorf("funded queued transaction missing: %v", tx10) 447 } 448 if _, ok := pool.queue[account].txs.items[tx11.Nonce()]; !ok { 449 t.Errorf("funded queued transaction missing: %v", tx10) 450 } 451 if _, ok := pool.queue[account].txs.items[tx12.Nonce()]; ok { 452 t.Errorf("out-of-fund queued transaction present: %v", tx11) 453 } 454 if len(pool.all) != 4 { 455 t.Errorf("total transaction mismatch: have %d, want %d", len(pool.all), 4) 456 } 457 // Reduce the block gas limit, check that invalidated transactions are dropped 458 pool.gasLimit = func() *big.Int { return big.NewInt(100) } 459 pool.resetState() 460 461 if _, ok := pool.pending[account].txs.items[tx0.Nonce()]; !ok { 462 t.Errorf("funded pending transaction missing: %v", tx0) 463 } 464 if _, ok := pool.pending[account].txs.items[tx1.Nonce()]; ok { 465 t.Errorf("over-gased pending transaction present: %v", tx1) 466 } 467 if _, ok := pool.queue[account].txs.items[tx10.Nonce()]; !ok { 468 t.Errorf("funded queued transaction missing: %v", tx10) 469 } 470 if _, ok := pool.queue[account].txs.items[tx11.Nonce()]; ok { 471 t.Errorf("over-gased queued transaction present: %v", tx11) 472 } 473 if len(pool.all) != 2 { 474 t.Errorf("total transaction mismatch: have %d, want %d", len(pool.all), 2) 475 } 476 } 477 478 // Tests that if a transaction is dropped from the current pending pool (e.g. out 479 // of fund), all consecutive (still valid, but not executable) transactions are 480 // postponed back into the future queue to prevent broadcasting them. 481 func TestTransactionPostponing(t *testing.T) { 482 // Create a test account and fund it 483 pool, key := setupTxPool() 484 account, _ := deriveSender(transaction(0, big.NewInt(0), key)) 485 486 state, _ := pool.currentState() 487 state.AddBalance(account, big.NewInt(1000)) 488 489 // Add a batch consecutive pending transactions for validation 490 txns := []*types.Transaction{} 491 for i := 0; i < 100; i++ { 492 var tx *types.Transaction 493 if i%2 == 0 { 494 tx = transaction(uint64(i), big.NewInt(100), key) 495 } else { 496 tx = transaction(uint64(i), big.NewInt(500), key) 497 } 498 pool.promoteTx(account, tx.Hash(), tx) 499 txns = append(txns, tx) 500 } 501 // Check that pre and post validations leave the pool as is 502 if pool.pending[account].Len() != len(txns) { 503 t.Errorf("pending transaction mismatch: have %d, want %d", pool.pending[account].Len(), len(txns)) 504 } 505 if len(pool.queue) != 0 { 506 t.Errorf("queued transaction mismatch: have %d, want %d", pool.queue[account].Len(), 0) 507 } 508 if len(pool.all) != len(txns) { 509 t.Errorf("total transaction mismatch: have %d, want %d", len(pool.all), len(txns)) 510 } 511 pool.resetState() 512 if pool.pending[account].Len() != len(txns) { 513 t.Errorf("pending transaction mismatch: have %d, want %d", pool.pending[account].Len(), len(txns)) 514 } 515 if len(pool.queue) != 0 { 516 t.Errorf("queued transaction mismatch: have %d, want %d", pool.queue[account].Len(), 0) 517 } 518 if len(pool.all) != len(txns) { 519 t.Errorf("total transaction mismatch: have %d, want %d", len(pool.all), len(txns)) 520 } 521 // Reduce the balance of the account, and check that transactions are reorganised 522 state.AddBalance(account, big.NewInt(-750)) 523 pool.resetState() 524 525 if _, ok := pool.pending[account].txs.items[txns[0].Nonce()]; !ok { 526 t.Errorf("tx %d: valid and funded transaction missing from pending pool: %v", 0, txns[0]) 527 } 528 if _, ok := pool.queue[account].txs.items[txns[0].Nonce()]; ok { 529 t.Errorf("tx %d: valid and funded transaction present in future queue: %v", 0, txns[0]) 530 } 531 for i, tx := range txns[1:] { 532 if i%2 == 1 { 533 if _, ok := pool.pending[account].txs.items[tx.Nonce()]; ok { 534 t.Errorf("tx %d: valid but future transaction present in pending pool: %v", i+1, tx) 535 } 536 if _, ok := pool.queue[account].txs.items[tx.Nonce()]; !ok { 537 t.Errorf("tx %d: valid but future transaction missing from future queue: %v", i+1, tx) 538 } 539 } else { 540 if _, ok := pool.pending[account].txs.items[tx.Nonce()]; ok { 541 t.Errorf("tx %d: out-of-fund transaction present in pending pool: %v", i+1, tx) 542 } 543 if _, ok := pool.queue[account].txs.items[tx.Nonce()]; ok { 544 t.Errorf("tx %d: out-of-fund transaction present in future queue: %v", i+1, tx) 545 } 546 } 547 } 548 if len(pool.all) != len(txns)/2 { 549 t.Errorf("total transaction mismatch: have %d, want %d", len(pool.all), len(txns)/2) 550 } 551 } 552 553 // Tests that if the transaction count belonging to a single account goes above 554 // some threshold, the higher transactions are dropped to prevent DOS attacks. 555 func TestTransactionQueueAccountLimiting(t *testing.T) { 556 // Create a test account and fund it 557 pool, key := setupTxPool() 558 account, _ := deriveSender(transaction(0, big.NewInt(0), key)) 559 560 state, _ := pool.currentState() 561 state.AddBalance(account, big.NewInt(1000000)) 562 pool.resetState() 563 564 // Keep queuing up transactions and make sure all above a limit are dropped 565 for i := uint64(1); i <= DefaultTxPoolConfig.AccountQueue+5; i++ { 566 if err := pool.Add(transaction(i, big.NewInt(100000), key)); err != nil { 567 t.Fatalf("tx %d: failed to add transaction: %v", i, err) 568 } 569 if len(pool.pending) != 0 { 570 t.Errorf("tx %d: pending pool size mismatch: have %d, want %d", i, len(pool.pending), 0) 571 } 572 if i <= DefaultTxPoolConfig.AccountQueue { 573 if pool.queue[account].Len() != int(i) { 574 t.Errorf("tx %d: queue size mismatch: have %d, want %d", i, pool.queue[account].Len(), i) 575 } 576 } else { 577 if pool.queue[account].Len() != int(DefaultTxPoolConfig.AccountQueue) { 578 t.Errorf("tx %d: queue limit mismatch: have %d, want %d", i, pool.queue[account].Len(), DefaultTxPoolConfig.AccountQueue) 579 } 580 } 581 } 582 if len(pool.all) != int(DefaultTxPoolConfig.AccountQueue) { 583 t.Errorf("total transaction mismatch: have %d, want %d", len(pool.all), DefaultTxPoolConfig.AccountQueue) 584 } 585 } 586 587 // Tests that if the transaction count belonging to multiple accounts go above 588 // some threshold, the higher transactions are dropped to prevent DOS attacks. 589 func TestTransactionQueueGlobalLimiting(t *testing.T) { 590 // Reduce the queue limits to shorten test time 591 defer func(old uint64) { DefaultTxPoolConfig.GlobalQueue = old }(DefaultTxPoolConfig.GlobalQueue) 592 DefaultTxPoolConfig.GlobalQueue = DefaultTxPoolConfig.AccountQueue * 3 593 594 // Create the pool to test the limit enforcement with 595 db, _ := ethdb.NewMemDatabase() 596 statedb, _ := state.New(common.Hash{}, db) 597 598 pool := NewTxPool(DefaultTxPoolConfig, params.TestChainConfig, new(event.TypeMux), func() (*state.StateDB, error) { return statedb, nil }, func() *big.Int { return big.NewInt(1000000) }) 599 pool.resetState() 600 601 // Create a number of test accounts and fund them 602 state, _ := pool.currentState() 603 604 keys := make([]*ecdsa.PrivateKey, 5) 605 for i := 0; i < len(keys); i++ { 606 keys[i], _ = crypto.GenerateKey() 607 state.AddBalance(crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(1000000)) 608 } 609 // Generate and queue a batch of transactions 610 nonces := make(map[common.Address]uint64) 611 612 txs := make(types.Transactions, 0, 3*DefaultTxPoolConfig.GlobalQueue) 613 for len(txs) < cap(txs) { 614 key := keys[rand.Intn(len(keys))] 615 addr := crypto.PubkeyToAddress(key.PublicKey) 616 617 txs = append(txs, transaction(nonces[addr]+1, big.NewInt(100000), key)) 618 nonces[addr]++ 619 } 620 // Import the batch and verify that limits have been enforced 621 pool.AddBatch(txs) 622 623 queued := 0 624 for addr, list := range pool.queue { 625 if list.Len() > int(DefaultTxPoolConfig.AccountQueue) { 626 t.Errorf("addr %x: queued accounts overflown allowance: %d > %d", addr, list.Len(), DefaultTxPoolConfig.AccountQueue) 627 } 628 queued += list.Len() 629 } 630 if queued > int(DefaultTxPoolConfig.GlobalQueue) { 631 t.Fatalf("total transactions overflow allowance: %d > %d", queued, DefaultTxPoolConfig.GlobalQueue) 632 } 633 } 634 635 // Tests that if an account remains idle for a prolonged amount of time, any 636 // non-executable transactions queued up are dropped to prevent wasting resources 637 // on shuffling them around. 638 func TestTransactionQueueTimeLimiting(t *testing.T) { 639 // Reduce the queue limits to shorten test time 640 defer func(old time.Duration) { DefaultTxPoolConfig.Lifetime = old }(DefaultTxPoolConfig.Lifetime) 641 defer func(old time.Duration) { evictionInterval = old }(evictionInterval) 642 DefaultTxPoolConfig.Lifetime = time.Second 643 evictionInterval = time.Second 644 645 // Create a test account and fund it 646 pool, key := setupTxPool() 647 account, _ := deriveSender(transaction(0, big.NewInt(0), key)) 648 649 state, _ := pool.currentState() 650 state.AddBalance(account, big.NewInt(1000000)) 651 652 // Queue up a batch of transactions 653 for i := uint64(1); i <= DefaultTxPoolConfig.AccountQueue; i++ { 654 if err := pool.Add(transaction(i, big.NewInt(100000), key)); err != nil { 655 t.Fatalf("tx %d: failed to add transaction: %v", i, err) 656 } 657 } 658 // Wait until at least two expiration cycles hit and make sure the transactions are gone 659 time.Sleep(2 * evictionInterval) 660 if len(pool.queue) > 0 { 661 t.Fatalf("old transactions remained after eviction") 662 } 663 } 664 665 // Tests that even if the transaction count belonging to a single account goes 666 // above some threshold, as long as the transactions are executable, they are 667 // accepted. 668 func TestTransactionPendingLimiting(t *testing.T) { 669 // Create a test account and fund it 670 pool, key := setupTxPool() 671 account, _ := deriveSender(transaction(0, big.NewInt(0), key)) 672 673 state, _ := pool.currentState() 674 state.AddBalance(account, big.NewInt(1000000)) 675 pool.resetState() 676 677 // Keep queuing up transactions and make sure all above a limit are dropped 678 for i := uint64(0); i < DefaultTxPoolConfig.AccountQueue+5; i++ { 679 if err := pool.Add(transaction(i, big.NewInt(100000), key)); err != nil { 680 t.Fatalf("tx %d: failed to add transaction: %v", i, err) 681 } 682 if pool.pending[account].Len() != int(i)+1 { 683 t.Errorf("tx %d: pending pool size mismatch: have %d, want %d", i, pool.pending[account].Len(), i+1) 684 } 685 if len(pool.queue) != 0 { 686 t.Errorf("tx %d: queue size mismatch: have %d, want %d", i, pool.queue[account].Len(), 0) 687 } 688 } 689 if len(pool.all) != int(DefaultTxPoolConfig.AccountQueue+5) { 690 t.Errorf("total transaction mismatch: have %d, want %d", len(pool.all), DefaultTxPoolConfig.AccountQueue+5) 691 } 692 } 693 694 // Tests that the transaction limits are enforced the same way irrelevant whether 695 // the transactions are added one by one or in batches. 696 func TestTransactionQueueLimitingEquivalency(t *testing.T) { testTransactionLimitingEquivalency(t, 1) } 697 func TestTransactionPendingLimitingEquivalency(t *testing.T) { testTransactionLimitingEquivalency(t, 0) } 698 699 func testTransactionLimitingEquivalency(t *testing.T, origin uint64) { 700 // Add a batch of transactions to a pool one by one 701 pool1, key1 := setupTxPool() 702 account1, _ := deriveSender(transaction(0, big.NewInt(0), key1)) 703 state1, _ := pool1.currentState() 704 state1.AddBalance(account1, big.NewInt(1000000)) 705 706 for i := uint64(0); i < DefaultTxPoolConfig.AccountQueue+5; i++ { 707 if err := pool1.Add(transaction(origin+i, big.NewInt(100000), key1)); err != nil { 708 t.Fatalf("tx %d: failed to add transaction: %v", i, err) 709 } 710 } 711 // Add a batch of transactions to a pool in one big batch 712 pool2, key2 := setupTxPool() 713 account2, _ := deriveSender(transaction(0, big.NewInt(0), key2)) 714 state2, _ := pool2.currentState() 715 state2.AddBalance(account2, big.NewInt(1000000)) 716 717 txns := []*types.Transaction{} 718 for i := uint64(0); i < DefaultTxPoolConfig.AccountQueue+5; i++ { 719 txns = append(txns, transaction(origin+i, big.NewInt(100000), key2)) 720 } 721 pool2.AddBatch(txns) 722 723 // Ensure the batch optimization honors the same pool mechanics 724 if len(pool1.pending) != len(pool2.pending) { 725 t.Errorf("pending transaction count mismatch: one-by-one algo: %d, batch algo: %d", len(pool1.pending), len(pool2.pending)) 726 } 727 if len(pool1.queue) != len(pool2.queue) { 728 t.Errorf("queued transaction count mismatch: one-by-one algo: %d, batch algo: %d", len(pool1.queue), len(pool2.queue)) 729 } 730 if len(pool1.all) != len(pool2.all) { 731 t.Errorf("total transaction count mismatch: one-by-one algo %d, batch algo %d", len(pool1.all), len(pool2.all)) 732 } 733 } 734 735 // Tests that if the transaction count belonging to multiple accounts go above 736 // some hard threshold, the higher transactions are dropped to prevent DOS 737 // attacks. 738 func TestTransactionPendingGlobalLimiting(t *testing.T) { 739 // Reduce the queue limits to shorten test time 740 defer func(old uint64) { DefaultTxPoolConfig.GlobalSlots = old }(DefaultTxPoolConfig.GlobalSlots) 741 DefaultTxPoolConfig.GlobalSlots = DefaultTxPoolConfig.AccountSlots * 10 742 743 // Create the pool to test the limit enforcement with 744 db, _ := ethdb.NewMemDatabase() 745 statedb, _ := state.New(common.Hash{}, db) 746 747 pool := NewTxPool(DefaultTxPoolConfig, params.TestChainConfig, new(event.TypeMux), func() (*state.StateDB, error) { return statedb, nil }, func() *big.Int { return big.NewInt(1000000) }) 748 pool.resetState() 749 750 // Create a number of test accounts and fund them 751 state, _ := pool.currentState() 752 753 keys := make([]*ecdsa.PrivateKey, 5) 754 for i := 0; i < len(keys); i++ { 755 keys[i], _ = crypto.GenerateKey() 756 state.AddBalance(crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(1000000)) 757 } 758 // Generate and queue a batch of transactions 759 nonces := make(map[common.Address]uint64) 760 761 txs := types.Transactions{} 762 for _, key := range keys { 763 addr := crypto.PubkeyToAddress(key.PublicKey) 764 for j := 0; j < int(DefaultTxPoolConfig.GlobalSlots)/len(keys)*2; j++ { 765 txs = append(txs, transaction(nonces[addr], big.NewInt(100000), key)) 766 nonces[addr]++ 767 } 768 } 769 // Import the batch and verify that limits have been enforced 770 pool.AddBatch(txs) 771 772 pending := 0 773 for _, list := range pool.pending { 774 pending += list.Len() 775 } 776 if pending > int(DefaultTxPoolConfig.GlobalSlots) { 777 t.Fatalf("total pending transactions overflow allowance: %d > %d", pending, DefaultTxPoolConfig.GlobalSlots) 778 } 779 } 780 781 // Tests that if the transaction count belonging to multiple accounts go above 782 // some hard threshold, if they are under the minimum guaranteed slot count then 783 // the transactions are still kept. 784 func TestTransactionPendingMinimumAllowance(t *testing.T) { 785 // Reduce the queue limits to shorten test time 786 defer func(old uint64) { DefaultTxPoolConfig.GlobalSlots = old }(DefaultTxPoolConfig.GlobalSlots) 787 DefaultTxPoolConfig.GlobalSlots = 0 788 789 // Create the pool to test the limit enforcement with 790 db, _ := ethdb.NewMemDatabase() 791 statedb, _ := state.New(common.Hash{}, db) 792 793 pool := NewTxPool(DefaultTxPoolConfig, params.TestChainConfig, new(event.TypeMux), func() (*state.StateDB, error) { return statedb, nil }, func() *big.Int { return big.NewInt(1000000) }) 794 pool.resetState() 795 796 // Create a number of test accounts and fund them 797 state, _ := pool.currentState() 798 799 keys := make([]*ecdsa.PrivateKey, 5) 800 for i := 0; i < len(keys); i++ { 801 keys[i], _ = crypto.GenerateKey() 802 state.AddBalance(crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(1000000)) 803 } 804 // Generate and queue a batch of transactions 805 nonces := make(map[common.Address]uint64) 806 807 txs := types.Transactions{} 808 for _, key := range keys { 809 addr := crypto.PubkeyToAddress(key.PublicKey) 810 for j := 0; j < int(DefaultTxPoolConfig.AccountSlots)*2; j++ { 811 txs = append(txs, transaction(nonces[addr], big.NewInt(100000), key)) 812 nonces[addr]++ 813 } 814 } 815 // Import the batch and verify that limits have been enforced 816 pool.AddBatch(txs) 817 818 for addr, list := range pool.pending { 819 if list.Len() != int(DefaultTxPoolConfig.AccountSlots) { 820 t.Errorf("addr %x: total pending transactions mismatch: have %d, want %d", addr, list.Len(), DefaultTxPoolConfig.AccountSlots) 821 } 822 } 823 } 824 825 // Tests that setting the transaction pool gas price to a higher value correctly 826 // discards everything cheaper than that and moves any gapped transactions back 827 // from the pending pool to the queue. 828 // 829 // Note, local transactions are never allowed to be dropped. 830 func TestTransactionPoolRepricing(t *testing.T) { 831 // Create the pool to test the pricing enforcement with 832 db, _ := ethdb.NewMemDatabase() 833 statedb, _ := state.New(common.Hash{}, db) 834 835 pool := NewTxPool(DefaultTxPoolConfig, params.TestChainConfig, new(event.TypeMux), func() (*state.StateDB, error) { return statedb, nil }, func() *big.Int { return big.NewInt(1000000) }) 836 pool.resetState() 837 838 // Create a number of test accounts and fund them 839 state, _ := pool.currentState() 840 841 keys := make([]*ecdsa.PrivateKey, 3) 842 for i := 0; i < len(keys); i++ { 843 keys[i], _ = crypto.GenerateKey() 844 state.AddBalance(crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(1000000)) 845 } 846 // Generate and queue a batch of transactions, both pending and queued 847 txs := types.Transactions{} 848 849 txs = append(txs, pricedTransaction(0, big.NewInt(100000), big.NewInt(2), keys[0])) 850 txs = append(txs, pricedTransaction(1, big.NewInt(100000), big.NewInt(1), keys[0])) 851 txs = append(txs, pricedTransaction(2, big.NewInt(100000), big.NewInt(2), keys[0])) 852 853 txs = append(txs, pricedTransaction(1, big.NewInt(100000), big.NewInt(2), keys[1])) 854 txs = append(txs, pricedTransaction(2, big.NewInt(100000), big.NewInt(1), keys[1])) 855 txs = append(txs, pricedTransaction(3, big.NewInt(100000), big.NewInt(2), keys[1])) 856 857 txs = append(txs, pricedTransaction(0, big.NewInt(100000), big.NewInt(1), keys[2])) 858 pool.SetLocal(txs[len(txs)-1]) // prevent this one from ever being dropped 859 860 // Import the batch and that both pending and queued transactions match up 861 pool.AddBatch(txs) 862 863 pending, queued := pool.stats() 864 if pending != 4 { 865 t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 4) 866 } 867 if queued != 3 { 868 t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 3) 869 } 870 // Reprice the pool and check that underpriced transactions get dropped 871 pool.SetGasPrice(big.NewInt(2)) 872 873 pending, queued = pool.stats() 874 if pending != 2 { 875 t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 2) 876 } 877 if queued != 3 { 878 t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 3) 879 } 880 // Check that we can't add the old transactions back 881 if err := pool.Add(pricedTransaction(1, big.NewInt(100000), big.NewInt(1), keys[0])); err != ErrUnderpriced { 882 t.Fatalf("adding underpriced pending transaction error mismatch: have %v, want %v", err, ErrUnderpriced) 883 } 884 if err := pool.Add(pricedTransaction(2, big.NewInt(100000), big.NewInt(1), keys[1])); err != ErrUnderpriced { 885 t.Fatalf("adding underpriced queued transaction error mismatch: have %v, want %v", err, ErrUnderpriced) 886 } 887 // However we can add local underpriced transactions 888 tx := pricedTransaction(1, big.NewInt(100000), big.NewInt(1), keys[2]) 889 890 pool.SetLocal(tx) // prevent this one from ever being dropped 891 if err := pool.Add(tx); err != nil { 892 t.Fatalf("failed to add underpriced local transaction: %v", err) 893 } 894 if pending, _ = pool.stats(); pending != 3 { 895 t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 3) 896 } 897 } 898 899 // Tests that when the pool reaches its global transaction limit, underpriced 900 // transactions are gradually shifted out for more expensive ones and any gapped 901 // pending transactions are moved into te queue. 902 // 903 // Note, local transactions are never allowed to be dropped. 904 func TestTransactionPoolUnderpricing(t *testing.T) { 905 // Reduce the queue limits to shorten test time 906 defer func(old uint64) { DefaultTxPoolConfig.GlobalSlots = old }(DefaultTxPoolConfig.GlobalSlots) 907 DefaultTxPoolConfig.GlobalSlots = 2 908 909 defer func(old uint64) { DefaultTxPoolConfig.GlobalQueue = old }(DefaultTxPoolConfig.GlobalQueue) 910 DefaultTxPoolConfig.GlobalQueue = 2 911 912 // Create the pool to test the pricing enforcement with 913 db, _ := ethdb.NewMemDatabase() 914 statedb, _ := state.New(common.Hash{}, db) 915 916 pool := NewTxPool(DefaultTxPoolConfig, params.TestChainConfig, new(event.TypeMux), func() (*state.StateDB, error) { return statedb, nil }, func() *big.Int { return big.NewInt(1000000) }) 917 pool.resetState() 918 919 // Create a number of test accounts and fund them 920 state, _ := pool.currentState() 921 922 keys := make([]*ecdsa.PrivateKey, 3) 923 for i := 0; i < len(keys); i++ { 924 keys[i], _ = crypto.GenerateKey() 925 state.AddBalance(crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(1000000)) 926 } 927 // Generate and queue a batch of transactions, both pending and queued 928 txs := types.Transactions{} 929 930 txs = append(txs, pricedTransaction(0, big.NewInt(100000), big.NewInt(1), keys[0])) 931 txs = append(txs, pricedTransaction(1, big.NewInt(100000), big.NewInt(2), keys[0])) 932 933 txs = append(txs, pricedTransaction(1, big.NewInt(100000), big.NewInt(1), keys[1])) 934 935 txs = append(txs, pricedTransaction(0, big.NewInt(100000), big.NewInt(1), keys[2])) 936 pool.SetLocal(txs[len(txs)-1]) // prevent this one from ever being dropped 937 938 // Import the batch and that both pending and queued transactions match up 939 pool.AddBatch(txs) 940 941 pending, queued := pool.stats() 942 if pending != 3 { 943 t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 3) 944 } 945 if queued != 1 { 946 t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 1) 947 } 948 // Ensure that adding an underpriced transaction on block limit fails 949 if err := pool.Add(pricedTransaction(0, big.NewInt(100000), big.NewInt(1), keys[1])); err != ErrUnderpriced { 950 t.Fatalf("adding underpriced pending transaction error mismatch: have %v, want %v", err, ErrUnderpriced) 951 } 952 // Ensure that adding high priced transactions drops cheap ones, but not own 953 if err := pool.Add(pricedTransaction(0, big.NewInt(100000), big.NewInt(3), keys[1])); err != nil { 954 t.Fatalf("failed to add well priced transaction: %v", err) 955 } 956 if err := pool.Add(pricedTransaction(2, big.NewInt(100000), big.NewInt(4), keys[1])); err != nil { 957 t.Fatalf("failed to add well priced transaction: %v", err) 958 } 959 if err := pool.Add(pricedTransaction(3, big.NewInt(100000), big.NewInt(5), keys[1])); err != nil { 960 t.Fatalf("failed to add well priced transaction: %v", err) 961 } 962 pending, queued = pool.stats() 963 if pending != 2 { 964 t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 2) 965 } 966 if queued != 2 { 967 t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 2) 968 } 969 // Ensure that adding local transactions can push out even higher priced ones 970 tx := pricedTransaction(1, big.NewInt(100000), big.NewInt(0), keys[2]) 971 972 pool.SetLocal(tx) // prevent this one from ever being dropped 973 if err := pool.Add(tx); err != nil { 974 t.Fatalf("failed to add underpriced local transaction: %v", err) 975 } 976 pending, queued = pool.stats() 977 if pending != 2 { 978 t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 2) 979 } 980 if queued != 2 { 981 t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 2) 982 } 983 } 984 985 // Tests that the pool rejects replacement transactions that don't meet the minimum 986 // price bump required. 987 func TestTransactionReplacement(t *testing.T) { 988 // Create the pool to test the pricing enforcement with 989 db, _ := ethdb.NewMemDatabase() 990 statedb, _ := state.New(common.Hash{}, db) 991 992 pool := NewTxPool(DefaultTxPoolConfig, params.TestChainConfig, new(event.TypeMux), func() (*state.StateDB, error) { return statedb, nil }, func() *big.Int { return big.NewInt(1000000) }) 993 pool.resetState() 994 995 // Create a a test account to add transactions with 996 key, _ := crypto.GenerateKey() 997 998 state, _ := pool.currentState() 999 state.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(1000000000)) 1000 1001 // Add pending transactions, ensuring the minimum price bump is enforced for replacement (for ultra low prices too) 1002 price := int64(100) 1003 threshold := (price * (100 + int64(DefaultTxPoolConfig.PriceBump))) / 100 1004 1005 if err := pool.Add(pricedTransaction(0, big.NewInt(100000), big.NewInt(1), key)); err != nil { 1006 t.Fatalf("failed to add original cheap pending transaction: %v", err) 1007 } 1008 if err := pool.Add(pricedTransaction(0, big.NewInt(100001), big.NewInt(1), key)); err != ErrReplaceUnderpriced { 1009 t.Fatalf("original cheap pending transaction replacement error mismatch: have %v, want %v", err, ErrReplaceUnderpriced) 1010 } 1011 if err := pool.Add(pricedTransaction(0, big.NewInt(100000), big.NewInt(2), key)); err != nil { 1012 t.Fatalf("failed to replace original cheap pending transaction: %v", err) 1013 } 1014 1015 if err := pool.Add(pricedTransaction(0, big.NewInt(100000), big.NewInt(price), key)); err != nil { 1016 t.Fatalf("failed to add original proper pending transaction: %v", err) 1017 } 1018 if err := pool.Add(pricedTransaction(0, big.NewInt(100000), big.NewInt(threshold), key)); err != ErrReplaceUnderpriced { 1019 t.Fatalf("original proper pending transaction replacement error mismatch: have %v, want %v", err, ErrReplaceUnderpriced) 1020 } 1021 if err := pool.Add(pricedTransaction(0, big.NewInt(100000), big.NewInt(threshold+1), key)); err != nil { 1022 t.Fatalf("failed to replace original proper pending transaction: %v", err) 1023 } 1024 // Add queued transactions, ensuring the minimum price bump is enforced for replacement (for ultra low prices too) 1025 if err := pool.Add(pricedTransaction(2, big.NewInt(100000), big.NewInt(1), key)); err != nil { 1026 t.Fatalf("failed to add original queued transaction: %v", err) 1027 } 1028 if err := pool.Add(pricedTransaction(2, big.NewInt(100001), big.NewInt(1), key)); err != ErrReplaceUnderpriced { 1029 t.Fatalf("original queued transaction replacement error mismatch: have %v, want %v", err, ErrReplaceUnderpriced) 1030 } 1031 if err := pool.Add(pricedTransaction(2, big.NewInt(100000), big.NewInt(2), key)); err != nil { 1032 t.Fatalf("failed to replace original queued transaction: %v", err) 1033 } 1034 1035 if err := pool.Add(pricedTransaction(2, big.NewInt(100000), big.NewInt(price), key)); err != nil { 1036 t.Fatalf("failed to add original queued transaction: %v", err) 1037 } 1038 if err := pool.Add(pricedTransaction(2, big.NewInt(100001), big.NewInt(threshold), key)); err != ErrReplaceUnderpriced { 1039 t.Fatalf("original queued transaction replacement error mismatch: have %v, want %v", err, ErrReplaceUnderpriced) 1040 } 1041 if err := pool.Add(pricedTransaction(2, big.NewInt(100000), big.NewInt(threshold+1), key)); err != nil { 1042 t.Fatalf("failed to replace original queued transaction: %v", err) 1043 } 1044 } 1045 1046 // Benchmarks the speed of validating the contents of the pending queue of the 1047 // transaction pool. 1048 func BenchmarkPendingDemotion100(b *testing.B) { benchmarkPendingDemotion(b, 100) } 1049 func BenchmarkPendingDemotion1000(b *testing.B) { benchmarkPendingDemotion(b, 1000) } 1050 func BenchmarkPendingDemotion10000(b *testing.B) { benchmarkPendingDemotion(b, 10000) } 1051 1052 func benchmarkPendingDemotion(b *testing.B, size int) { 1053 // Add a batch of transactions to a pool one by one 1054 pool, key := setupTxPool() 1055 account, _ := deriveSender(transaction(0, big.NewInt(0), key)) 1056 state, _ := pool.currentState() 1057 state.AddBalance(account, big.NewInt(1000000)) 1058 1059 for i := 0; i < size; i++ { 1060 tx := transaction(uint64(i), big.NewInt(100000), key) 1061 pool.promoteTx(account, tx.Hash(), tx) 1062 } 1063 // Benchmark the speed of pool validation 1064 b.ResetTimer() 1065 for i := 0; i < b.N; i++ { 1066 pool.demoteUnexecutables(state) 1067 } 1068 } 1069 1070 // Benchmarks the speed of scheduling the contents of the future queue of the 1071 // transaction pool. 1072 func BenchmarkFuturePromotion100(b *testing.B) { benchmarkFuturePromotion(b, 100) } 1073 func BenchmarkFuturePromotion1000(b *testing.B) { benchmarkFuturePromotion(b, 1000) } 1074 func BenchmarkFuturePromotion10000(b *testing.B) { benchmarkFuturePromotion(b, 10000) } 1075 1076 func benchmarkFuturePromotion(b *testing.B, size int) { 1077 // Add a batch of transactions to a pool one by one 1078 pool, key := setupTxPool() 1079 account, _ := deriveSender(transaction(0, big.NewInt(0), key)) 1080 state, _ := pool.currentState() 1081 state.AddBalance(account, big.NewInt(1000000)) 1082 1083 for i := 0; i < size; i++ { 1084 tx := transaction(uint64(1+i), big.NewInt(100000), key) 1085 pool.enqueueTx(tx.Hash(), tx) 1086 } 1087 // Benchmark the speed of pool validation 1088 b.ResetTimer() 1089 for i := 0; i < b.N; i++ { 1090 pool.promoteExecutables(state, nil) 1091 } 1092 } 1093 1094 // Benchmarks the speed of iterative transaction insertion. 1095 func BenchmarkPoolInsert(b *testing.B) { 1096 // Generate a batch of transactions to enqueue into the pool 1097 pool, key := setupTxPool() 1098 account, _ := deriveSender(transaction(0, big.NewInt(0), key)) 1099 state, _ := pool.currentState() 1100 state.AddBalance(account, big.NewInt(1000000)) 1101 1102 txs := make(types.Transactions, b.N) 1103 for i := 0; i < b.N; i++ { 1104 txs[i] = transaction(uint64(i), big.NewInt(100000), key) 1105 } 1106 // Benchmark importing the transactions into the queue 1107 b.ResetTimer() 1108 for _, tx := range txs { 1109 pool.Add(tx) 1110 } 1111 } 1112 1113 // Benchmarks the speed of batched transaction insertion. 1114 func BenchmarkPoolBatchInsert100(b *testing.B) { benchmarkPoolBatchInsert(b, 100) } 1115 func BenchmarkPoolBatchInsert1000(b *testing.B) { benchmarkPoolBatchInsert(b, 1000) } 1116 func BenchmarkPoolBatchInsert10000(b *testing.B) { benchmarkPoolBatchInsert(b, 10000) } 1117 1118 func benchmarkPoolBatchInsert(b *testing.B, size int) { 1119 // Generate a batch of transactions to enqueue into the pool 1120 pool, key := setupTxPool() 1121 account, _ := deriveSender(transaction(0, big.NewInt(0), key)) 1122 state, _ := pool.currentState() 1123 state.AddBalance(account, big.NewInt(1000000)) 1124 1125 batches := make([]types.Transactions, b.N) 1126 for i := 0; i < b.N; i++ { 1127 batches[i] = make(types.Transactions, size) 1128 for j := 0; j < size; j++ { 1129 batches[i][j] = transaction(uint64(size*i+j), big.NewInt(100000), key) 1130 } 1131 } 1132 // Benchmark importing the transactions into the queue 1133 b.ResetTimer() 1134 for _, batch := range batches { 1135 pool.AddBatch(batch) 1136 } 1137 }