github.com/ethereumproject/go-ethereum@v5.5.2+incompatible/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 "testing" 23 24 "github.com/ethereumproject/go-ethereum/common" 25 "github.com/ethereumproject/go-ethereum/core/state" 26 "github.com/ethereumproject/go-ethereum/core/types" 27 "github.com/ethereumproject/go-ethereum/crypto" 28 "github.com/ethereumproject/go-ethereum/ethdb" 29 "github.com/ethereumproject/go-ethereum/event" 30 ) 31 32 func transaction(nonce uint64, gaslimit *big.Int, key *ecdsa.PrivateKey) *types.Transaction { 33 tx, _ := types.NewTransaction(nonce, common.Address{}, big.NewInt(100), gaslimit, big.NewInt(1), nil).SignECDSA(key) 34 return tx 35 } 36 37 func setupTxPool() (*TxPool, *ecdsa.PrivateKey) { 38 db, _ := ethdb.NewMemDatabase() 39 statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) 40 41 var m event.TypeMux 42 key, _ := crypto.GenerateKey() 43 newPool := NewTxPool(testChainConfig(), &m, func() (*state.StateDB, error) { return statedb, nil }, func() *big.Int { return big.NewInt(1000000) }) 44 newPool.resetState() 45 return newPool, key 46 } 47 48 func deriveSender(tx *types.Transaction) (common.Address, error) { 49 return types.Sender(types.BasicSigner{}, tx) 50 } 51 52 func TestInvalidTransactions(t *testing.T) { 53 pool, key := setupTxPool() 54 55 tx := transaction(0, big.NewInt(100), key) 56 if err := pool.Add(tx); err != ErrNonExistentAccount { 57 t.Error("expected", ErrNonExistentAccount) 58 } 59 60 from, _ := deriveSender(tx) 61 currentState, _ := pool.currentState() 62 currentState.AddBalance(from, big.NewInt(1)) 63 if err := pool.Add(tx); err != ErrInsufficientFunds { 64 t.Error("expected", ErrInsufficientFunds) 65 } 66 67 balance := new(big.Int).Add(tx.Value(), new(big.Int).Mul(tx.Gas(), tx.GasPrice())) 68 currentState.AddBalance(from, balance) 69 if err := pool.Add(tx); err != ErrIntrinsicGas { 70 t.Error("expected", ErrIntrinsicGas, "got", err) 71 } 72 73 currentState.SetNonce(from, 1) 74 currentState.AddBalance(from, big.NewInt(0xffffffffffffff)) 75 tx = transaction(0, big.NewInt(100000), key) 76 if err := pool.Add(tx); err != ErrNonce { 77 t.Error("expected", ErrNonce) 78 } 79 80 tx = transaction(1, big.NewInt(100000), key) 81 pool.minGasPrice = big.NewInt(1000) 82 if err := pool.Add(tx); err != ErrCheap { 83 t.Error("expected", ErrCheap, "got", err) 84 } 85 86 pool.SetLocal(tx) 87 if err := pool.Add(tx); err != nil { 88 t.Error("expected", nil, "got", err) 89 } 90 } 91 92 func TestTransactionQueue(t *testing.T) { 93 pool, key := setupTxPool() 94 tx := transaction(0, big.NewInt(100), key) 95 from, _ := tx.From() 96 currentState, _ := pool.currentState() 97 currentState.AddBalance(from, big.NewInt(1000)) 98 pool.queueTx(tx.Hash(), tx) 99 100 pool.checkQueue() 101 if len(pool.pending) != 1 { 102 t.Error("expected valid txs to be 1 is", len(pool.pending)) 103 } 104 105 tx = transaction(1, big.NewInt(100), key) 106 from, _ = deriveSender(tx) 107 currentState.SetNonce(from, 2) 108 pool.queueTx(tx.Hash(), tx) 109 pool.checkQueue() 110 if _, ok := pool.pending[tx.Hash()]; ok { 111 t.Error("expected transaction to be in tx pool") 112 } 113 114 if len(pool.queue[from]) > 0 { 115 t.Error("expected transaction queue to be empty. is", len(pool.queue[from])) 116 } 117 118 pool, key = setupTxPool() 119 tx1 := transaction(0, big.NewInt(100), key) 120 tx2 := transaction(10, big.NewInt(100), key) 121 tx3 := transaction(11, big.NewInt(100), key) 122 from, _ = tx1.From() 123 currentState, _ = pool.currentState() 124 currentState.AddBalance(from, big.NewInt(1000)) 125 pool.queueTx(tx1.Hash(), tx1) 126 pool.queueTx(tx2.Hash(), tx2) 127 pool.queueTx(tx3.Hash(), tx3) 128 129 pool.checkQueue() 130 131 if len(pool.pending) != 1 { 132 t.Error("expected tx pool to be 1, got", len(pool.pending)) 133 } 134 if len(pool.queue[from]) != 2 { 135 t.Error("expected len(queue) == 2, got", len(pool.queue[from])) 136 } 137 } 138 139 func TestRemoveTx(t *testing.T) { 140 pool, key := setupTxPool() 141 tx := transaction(0, big.NewInt(100), key) 142 from, _ := deriveSender(tx) 143 currentState, _ := pool.currentState() 144 currentState.AddBalance(from, big.NewInt(1)) 145 pool.queueTx(tx.Hash(), tx) 146 pool.addTx(tx.Hash(), from, tx) 147 if len(pool.queue) != 1 { 148 t.Error("expected queue to be 1, got", len(pool.queue)) 149 } 150 151 if len(pool.pending) != 1 { 152 t.Error("expected txs to be 1, got", len(pool.pending)) 153 } 154 155 pool.RemoveTx(tx.Hash()) 156 157 if len(pool.queue) > 0 { 158 t.Error("expected queue to be 0, got", len(pool.queue)) 159 } 160 161 if len(pool.pending) > 0 { 162 t.Error("expected txs to be 0, got", len(pool.pending)) 163 } 164 } 165 166 func TestNegativeValue(t *testing.T) { 167 pool, key := setupTxPool() 168 169 tx, _ := types.NewTransaction(0, common.Address{}, big.NewInt(-1), big.NewInt(100), big.NewInt(1), nil).SignECDSA(key) 170 from, _ := deriveSender(tx) 171 currentState, _ := pool.currentState() 172 currentState.AddBalance(from, big.NewInt(1)) 173 if err := pool.Add(tx); err != ErrNegativeValue { 174 t.Error("expected", ErrNegativeValue, "got", err) 175 } 176 } 177 178 func TestTransactionChainFork(t *testing.T) { 179 pool, key := setupTxPool() 180 addr := crypto.PubkeyToAddress(key.PublicKey) 181 resetState := func() { 182 db, _ := ethdb.NewMemDatabase() 183 statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) 184 pool.currentState = func() (*state.StateDB, error) { return statedb, nil } 185 currentState, _ := pool.currentState() 186 currentState.AddBalance(addr, big.NewInt(100000000000000)) 187 pool.resetState() 188 } 189 resetState() 190 191 tx := transaction(0, big.NewInt(100000), key) 192 if err := pool.add(tx); err != nil { 193 t.Error("didn't expect error", err) 194 } 195 pool.RemoveTransactions([]*types.Transaction{tx}) 196 197 // reset the pool's internal state 198 resetState() 199 if err := pool.add(tx); err != nil { 200 t.Error("didn't expect error", err) 201 } 202 } 203 204 func TestTransactionDoubleNonce(t *testing.T) { 205 pool, key := setupTxPool() 206 addr := crypto.PubkeyToAddress(key.PublicKey) 207 resetState := func() { 208 db, _ := ethdb.NewMemDatabase() 209 statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) 210 pool.currentState = func() (*state.StateDB, error) { return statedb, nil } 211 currentState, _ := pool.currentState() 212 currentState.AddBalance(addr, big.NewInt(100000000000000)) 213 pool.resetState() 214 } 215 resetState() 216 217 tx := transaction(0, big.NewInt(100000), key) 218 tx2 := transaction(0, big.NewInt(1000000), key) 219 if err := pool.add(tx); err != nil { 220 t.Error("didn't expect error", err) 221 } 222 if err := pool.add(tx2); err != nil { 223 t.Error("didn't expect error", err) 224 } 225 226 pool.checkQueue() 227 if len(pool.pending) != 2 { 228 t.Error("expected 2 pending txs. Got", len(pool.pending)) 229 } 230 } 231 232 func TestMissingNonce(t *testing.T) { 233 pool, key := setupTxPool() 234 addr := crypto.PubkeyToAddress(key.PublicKey) 235 currentState, _ := pool.currentState() 236 currentState.AddBalance(addr, big.NewInt(100000000000000)) 237 tx := transaction(1, big.NewInt(100000), key) 238 if err := pool.add(tx); err != nil { 239 t.Error("didn't expect error", err) 240 } 241 if len(pool.pending) != 0 { 242 t.Error("expected 0 pending transactions, got", len(pool.pending)) 243 } 244 if len(pool.queue[addr]) != 1 { 245 t.Error("expected 1 queued transaction, got", len(pool.queue[addr])) 246 } 247 } 248 249 func TestNonceRecovery(t *testing.T) { 250 const n = 10 251 pool, key := setupTxPool() 252 addr := crypto.PubkeyToAddress(key.PublicKey) 253 currentState, _ := pool.currentState() 254 currentState.SetNonce(addr, n) 255 currentState.AddBalance(addr, big.NewInt(100000000000000)) 256 pool.resetState() 257 tx := transaction(n, big.NewInt(100000), key) 258 if err := pool.Add(tx); err != nil { 259 t.Error(err) 260 } 261 // simulate some weird re-order of transactions and missing nonce(s) 262 currentState.SetNonce(addr, n-1) 263 pool.resetState() 264 if fn := pool.pendingState.GetNonce(addr); fn != n+1 { 265 t.Errorf("expected nonce to be %d, got %d", n+1, fn) 266 } 267 } 268 269 func TestRemovedTxEvent(t *testing.T) { 270 pool, key := setupTxPool() 271 tx := transaction(0, big.NewInt(1000000), key) 272 from, _ := deriveSender(tx) 273 currentState, _ := pool.currentState() 274 currentState.AddBalance(from, big.NewInt(1000000000000)) 275 pool.eventMux.Post(RemovedTransactionEvent{types.Transactions{tx}}) 276 pool.eventMux.Post(ChainHeadEvent{nil}) 277 if len(pool.pending) != 1 { 278 t.Error("expected 1 pending tx, got", len(pool.pending)) 279 } 280 } 281 282 // Tests that if an account runs out of funds, any pending and queued transactions 283 // are dropped. 284 func TestTransactionDropping(t *testing.T) { 285 // Create a test account and fund it 286 pool, key := setupTxPool() 287 account, _ := deriveSender(transaction(0, big.NewInt(0), key)) 288 289 state, _ := pool.currentState() 290 state.AddBalance(account, big.NewInt(1000)) 291 292 // Add some pending and some queued transactions 293 var ( 294 tx0 = transaction(0, big.NewInt(100), key) 295 tx1 = transaction(1, big.NewInt(200), key) 296 tx10 = transaction(10, big.NewInt(100), key) 297 tx11 = transaction(11, big.NewInt(200), key) 298 ) 299 pool.addTx(tx0.Hash(), account, tx0) 300 pool.addTx(tx1.Hash(), account, tx1) 301 pool.queueTx(tx10.Hash(), tx10) 302 pool.queueTx(tx11.Hash(), tx11) 303 304 // Check that pre and post validations leave the pool as is 305 if len(pool.pending) != 2 { 306 t.Errorf("pending transaction mismatch: have %d, want %d", len(pool.pending), 2) 307 } 308 if len(pool.queue[account]) != 2 { 309 t.Errorf("queued transaction mismatch: have %d, want %d", len(pool.queue), 2) 310 } 311 pool.resetState() 312 if len(pool.pending) != 2 { 313 t.Errorf("pending transaction mismatch: have %d, want %d", len(pool.pending), 2) 314 } 315 if len(pool.queue[account]) != 2 { 316 t.Errorf("queued transaction mismatch: have %d, want %d", len(pool.queue), 2) 317 } 318 // Reduce the balance of the account, and check that invalidated transactions are dropped 319 state.AddBalance(account, big.NewInt(-750)) 320 pool.resetState() 321 322 if _, ok := pool.pending[tx0.Hash()]; !ok { 323 t.Errorf("funded pending transaction missing: %v", tx0) 324 } 325 if _, ok := pool.pending[tx1.Hash()]; ok { 326 t.Errorf("out-of-fund pending transaction present: %v", tx1) 327 } 328 if _, ok := pool.queue[account][tx10.Hash()]; !ok { 329 t.Errorf("funded queued transaction missing: %v", tx10) 330 } 331 if _, ok := pool.queue[account][tx11.Hash()]; ok { 332 t.Errorf("out-of-fund queued transaction present: %v", tx11) 333 } 334 } 335 336 // Tests that if a transaction is dropped from the current pending pool (e.g. out 337 // of fund), all consecutive (still valid, but not executable) transactions are 338 // postponed back into the future queue to prevent broadcasting them. 339 func TestTransactionPostponing(t *testing.T) { 340 // Create a test account and fund it 341 pool, key := setupTxPool() 342 account, _ := deriveSender(transaction(0, big.NewInt(0), key)) 343 344 state, _ := pool.currentState() 345 state.AddBalance(account, big.NewInt(1000)) 346 347 // Add a batch consecutive pending transactions for validation 348 txns := []*types.Transaction{} 349 for i := 0; i < 100; i++ { 350 var tx *types.Transaction 351 if i%2 == 0 { 352 tx = transaction(uint64(i), big.NewInt(100), key) 353 } else { 354 tx = transaction(uint64(i), big.NewInt(500), key) 355 } 356 pool.addTx(tx.Hash(), account, tx) 357 txns = append(txns, tx) 358 } 359 // Check that pre and post validations leave the pool as is 360 if len(pool.pending) != len(txns) { 361 t.Errorf("pending transaction mismatch: have %d, want %d", len(pool.pending), len(txns)) 362 } 363 if len(pool.queue[account]) != 0 { 364 t.Errorf("queued transaction mismatch: have %d, want %d", len(pool.queue), 0) 365 } 366 pool.resetState() 367 if len(pool.pending) != len(txns) { 368 t.Errorf("pending transaction mismatch: have %d, want %d", len(pool.pending), len(txns)) 369 } 370 if len(pool.queue[account]) != 0 { 371 t.Errorf("queued transaction mismatch: have %d, want %d", len(pool.queue), 0) 372 } 373 // Reduce the balance of the account, and check that transactions are reorganised 374 state.AddBalance(account, big.NewInt(-750)) 375 pool.resetState() 376 377 if _, ok := pool.pending[txns[0].Hash()]; !ok { 378 t.Errorf("tx %d: valid and funded transaction missing from pending pool: %v", 0, txns[0]) 379 } 380 if _, ok := pool.queue[account][txns[0].Hash()]; ok { 381 t.Errorf("tx %d: valid and funded transaction present in future queue: %v", 0, txns[0]) 382 } 383 for i, tx := range txns[1:] { 384 if i%2 == 1 { 385 if _, ok := pool.pending[tx.Hash()]; ok { 386 t.Errorf("tx %d: valid but future transaction present in pending pool: %v", i+1, tx) 387 } 388 if _, ok := pool.queue[account][tx.Hash()]; !ok { 389 t.Errorf("tx %d: valid but future transaction missing from future queue: %v", i+1, tx) 390 } 391 } else { 392 if _, ok := pool.pending[tx.Hash()]; ok { 393 t.Errorf("tx %d: out-of-fund transaction present in pending pool: %v", i+1, tx) 394 } 395 if _, ok := pool.queue[account][tx.Hash()]; ok { 396 t.Errorf("tx %d: out-of-fund transaction present in future queue: %v", i+1, tx) 397 } 398 } 399 } 400 } 401 402 // Tests that if the transaction count belonging to a single account goes above 403 // some threshold, the higher transactions are dropped to prevent DOS attacks. 404 func TestTransactionQueueLimiting(t *testing.T) { 405 // Create a test account and fund it 406 pool, key := setupTxPool() 407 account, _ := deriveSender(transaction(0, big.NewInt(0), key)) 408 409 state, _ := pool.currentState() 410 state.AddBalance(account, big.NewInt(1000000)) 411 412 // Keep queuing up transactions and make sure all above a limit are dropped 413 for i := uint64(1); i <= maxQueued+5; i++ { 414 if err := pool.Add(transaction(i, big.NewInt(100000), key)); err != nil { 415 t.Fatalf("tx %d: failed to add transaction: %v", i, err) 416 } 417 if len(pool.pending) != 0 { 418 t.Errorf("tx %d: pending pool size mismatch: have %d, want %d", i, len(pool.pending), 0) 419 } 420 if i <= maxQueued { 421 if len(pool.queue[account]) != int(i) { 422 t.Errorf("tx %d: queue size mismatch: have %d, want %d", i, len(pool.queue[account]), i) 423 } 424 } else { 425 if len(pool.queue[account]) != maxQueued { 426 t.Errorf("tx %d: queue limit mismatch: have %d, want %d", i, len(pool.queue[account]), maxQueued) 427 } 428 } 429 } 430 } 431 432 // Tests that even if the transaction count belonging to a single account goes 433 // above some threshold, as long as the transactions are executable, they are 434 // accepted. 435 func TestTransactionPendingLimiting(t *testing.T) { 436 // Create a test account and fund it 437 pool, key := setupTxPool() 438 account, _ := deriveSender(transaction(0, big.NewInt(0), key)) 439 440 state, _ := pool.currentState() 441 state.AddBalance(account, big.NewInt(1000000)) 442 443 // Keep queuing up transactions and make sure all above a limit are dropped 444 for i := uint64(0); i < maxQueued+5; i++ { 445 if err := pool.Add(transaction(i, big.NewInt(100000), key)); err != nil { 446 t.Fatalf("tx %d: failed to add transaction: %v", i, err) 447 } 448 if len(pool.pending) != int(i)+1 { 449 t.Errorf("tx %d: pending pool size mismatch: have %d, want %d", i, len(pool.pending), i+1) 450 } 451 if len(pool.queue[account]) != 0 { 452 t.Errorf("tx %d: queue size mismatch: have %d, want %d", i, len(pool.queue[account]), 0) 453 } 454 } 455 } 456 457 // Tests that the transaction limits are enforced the same way irrelevant whether 458 // the transactions are added one by one or in batches. 459 func TestTransactionQueueLimitingEquivalency(t *testing.T) { testTransactionLimitingEquivalency(t, 1) } 460 func TestTransactionPendingLimitingEquivalency(t *testing.T) { testTransactionLimitingEquivalency(t, 0) } 461 462 func testTransactionLimitingEquivalency(t *testing.T, origin uint64) { 463 // Add a batch of transactions to a pool one by one 464 pool1, key1 := setupTxPool() 465 account1, _ := deriveSender(transaction(0, big.NewInt(0), key1)) 466 state1, _ := pool1.currentState() 467 state1.AddBalance(account1, big.NewInt(1000000)) 468 469 for i := uint64(0); i < maxQueued+5; i++ { 470 if err := pool1.Add(transaction(origin+i, big.NewInt(100000), key1)); err != nil { 471 t.Fatalf("tx %d: failed to add transaction: %v", i, err) 472 } 473 } 474 // Add a batch of transactions to a pool in one bit batch 475 pool2, key2 := setupTxPool() 476 account2, _ := transaction(0, big.NewInt(0), key2).From() 477 state2, _ := pool2.currentState() 478 state2.AddBalance(account2, big.NewInt(1000000)) 479 480 txns := []*types.Transaction{} 481 for i := uint64(0); i < maxQueued+5; i++ { 482 txns = append(txns, transaction(origin+i, big.NewInt(100000), key2)) 483 } 484 pool2.AddTransactions(txns) 485 486 // Ensure the batch optimization honors the same pool mechanics 487 if len(pool1.pending) != len(pool2.pending) { 488 t.Errorf("pending transaction count mismatch: one-by-one algo: %d, batch algo: %d", len(pool1.pending), len(pool2.pending)) 489 } 490 if len(pool1.queue[account1]) != len(pool2.queue[account2]) { 491 t.Errorf("queued transaction count mismatch: one-by-one algo: %d, batch algo: %d", len(pool1.queue[account1]), len(pool2.queue[account2])) 492 } 493 } 494 495 // Benchmarks the speed of validating the contents of the pending queue of the 496 // transaction pool. 497 func BenchmarkValidatePool100(b *testing.B) { benchmarkValidatePool(b, 100) } 498 func BenchmarkValidatePool1000(b *testing.B) { benchmarkValidatePool(b, 1000) } 499 func BenchmarkValidatePool10000(b *testing.B) { benchmarkValidatePool(b, 10000) } 500 501 func benchmarkValidatePool(b *testing.B, size int) { 502 // Add a batch of transactions to a pool one by one 503 pool, key := setupTxPool() 504 account, _ := deriveSender(transaction(0, big.NewInt(0), key)) 505 state, _ := pool.currentState() 506 state.AddBalance(account, big.NewInt(1000000)) 507 508 for i := 0; i < size; i++ { 509 tx := transaction(uint64(i), big.NewInt(100000), key) 510 pool.addTx(tx.Hash(), account, tx) 511 } 512 // Benchmark the speed of pool validation 513 b.ResetTimer() 514 for i := 0; i < b.N; i++ { 515 pool.validatePool() 516 } 517 } 518 519 // Benchmarks the speed of scheduling the contents of the future queue of the 520 // transaction pool. 521 func BenchmarkCheckQueue100(b *testing.B) { benchmarkCheckQueue(b, 100) } 522 func BenchmarkCheckQueue1000(b *testing.B) { benchmarkCheckQueue(b, 1000) } 523 func BenchmarkCheckQueue10000(b *testing.B) { benchmarkCheckQueue(b, 10000) } 524 525 func benchmarkCheckQueue(b *testing.B, size int) { 526 // Add a batch of transactions to a pool one by one 527 pool, key := setupTxPool() 528 account, _ := deriveSender(transaction(0, big.NewInt(0), key)) 529 state, _ := pool.currentState() 530 state.AddBalance(account, big.NewInt(1000000)) 531 532 for i := 0; i < size; i++ { 533 tx := transaction(uint64(1+i), big.NewInt(100000), key) 534 pool.queueTx(tx.Hash(), tx) 535 } 536 // Benchmark the speed of pool validation 537 b.ResetTimer() 538 for i := 0; i < b.N; i++ { 539 pool.checkQueue() 540 } 541 }