From 182d9cb752ffe08fc5e40718031bc8a497311ff5 Mon Sep 17 00:00:00 2001 From: Péter Szilágyi Date: Fri, 14 Oct 2016 15:32:06 +0300 Subject: core: add global (soft) limits on the pending transactions --- core/tx_pool_test.go | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) (limited to 'core/tx_pool_test.go') diff --git a/core/tx_pool_test.go b/core/tx_pool_test.go index 4bc5aed38..dbe6fa635 100644 --- a/core/tx_pool_test.go +++ b/core/tx_pool_test.go @@ -618,6 +618,96 @@ func testTransactionLimitingEquivalency(t *testing.T, origin uint64) { } } +// Tests that if the transaction count belonging to multiple accounts go above +// some hard threshold, the higher transactions are dropped to prevent DOS +// attacks. +func TestTransactionPendingGlobalLimiting(t *testing.T) { + // Reduce the queue limits to shorten test time + defer func(old uint64) { maxPendingTotal = old }(maxPendingTotal) + maxPendingTotal = minPendingPerAccount * 10 + + // Create the pool to test the limit enforcement with + db, _ := ethdb.NewMemDatabase() + statedb, _ := state.New(common.Hash{}, db) + + pool := NewTxPool(testChainConfig(), new(event.TypeMux), func() (*state.StateDB, error) { return statedb, nil }, func() *big.Int { return big.NewInt(1000000) }) + pool.resetState() + + // Create a number of test accounts and fund them + state, _ := pool.currentState() + + keys := make([]*ecdsa.PrivateKey, 5) + for i := 0; i < len(keys); i++ { + keys[i], _ = crypto.GenerateKey() + state.AddBalance(crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(1000000)) + } + // Generate and queue a batch of transactions + nonces := make(map[common.Address]uint64) + + txs := types.Transactions{} + for _, key := range keys { + addr := crypto.PubkeyToAddress(key.PublicKey) + for j := 0; j < int(maxPendingTotal)/len(keys)*2; j++ { + txs = append(txs, transaction(nonces[addr], big.NewInt(100000), key)) + nonces[addr]++ + } + } + // Import the batch and verify that limits have been enforced + pool.AddBatch(txs) + + pending := 0 + for _, list := range pool.pending { + pending += list.Len() + } + if pending > int(maxPendingTotal) { + t.Fatalf("total pending transactions overflow allowance: %d > %d", pending, maxPendingTotal) + } +} + +// Tests that if the transaction count belonging to multiple accounts go above +// some hard threshold, if they are under the minimum guaranteed slot count then +// the transactions are still kept. +func TestTransactionPendingMinimumAllowance(t *testing.T) { + // Reduce the queue limits to shorten test time + defer func(old uint64) { maxPendingTotal = old }(maxPendingTotal) + maxPendingTotal = 0 + + // Create the pool to test the limit enforcement with + db, _ := ethdb.NewMemDatabase() + statedb, _ := state.New(common.Hash{}, db) + + pool := NewTxPool(testChainConfig(), new(event.TypeMux), func() (*state.StateDB, error) { return statedb, nil }, func() *big.Int { return big.NewInt(1000000) }) + pool.resetState() + + // Create a number of test accounts and fund them + state, _ := pool.currentState() + + keys := make([]*ecdsa.PrivateKey, 5) + for i := 0; i < len(keys); i++ { + keys[i], _ = crypto.GenerateKey() + state.AddBalance(crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(1000000)) + } + // Generate and queue a batch of transactions + nonces := make(map[common.Address]uint64) + + txs := types.Transactions{} + for _, key := range keys { + addr := crypto.PubkeyToAddress(key.PublicKey) + for j := 0; j < int(minPendingPerAccount)*2; j++ { + txs = append(txs, transaction(nonces[addr], big.NewInt(100000), key)) + nonces[addr]++ + } + } + // Import the batch and verify that limits have been enforced + pool.AddBatch(txs) + + for addr, list := range pool.pending { + if list.Len() != int(minPendingPerAccount) { + t.Errorf("addr %x: total pending transactions mismatch: have %d, want %d", addr, list.Len(), minPendingPerAccount) + } + } +} + // Benchmarks the speed of validating the contents of the pending queue of the // transaction pool. func BenchmarkPendingDemotion100(b *testing.B) { benchmarkPendingDemotion(b, 100) } -- cgit