|
|
|
@ -77,9 +77,17 @@ func pricedTransaction(nonce uint64, gaslimit uint64, gasprice *big.Int, key *ec |
|
|
|
|
return tx |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func pricedDataTransaction(nonce uint64, gaslimit uint64, gasprice *big.Int, key *ecdsa.PrivateKey, bytes uint64) *types.Transaction { |
|
|
|
|
data := make([]byte, bytes) |
|
|
|
|
rand.Read(data) |
|
|
|
|
|
|
|
|
|
tx, _ := types.SignTx(types.NewTransaction(nonce, common.Address{}, big.NewInt(0), gaslimit, gasprice, data), types.HomesteadSigner{}, key) |
|
|
|
|
return tx |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func setupTxPool() (*TxPool, *ecdsa.PrivateKey) { |
|
|
|
|
statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase())) |
|
|
|
|
blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} |
|
|
|
|
blockchain := &testBlockChain{statedb, 10000000, new(event.Feed)} |
|
|
|
|
|
|
|
|
|
key, _ := crypto.GenerateKey() |
|
|
|
|
pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain) |
|
|
|
@ -465,7 +473,7 @@ func TestTransactionDropping(t *testing.T) { |
|
|
|
|
pool, key := setupTxPool() |
|
|
|
|
defer pool.Stop() |
|
|
|
|
|
|
|
|
|
account, _ := deriveSender(transaction(0, 0, key)) |
|
|
|
|
account := crypto.PubkeyToAddress(key.PublicKey) |
|
|
|
|
pool.currentState.AddBalance(account, big.NewInt(1000)) |
|
|
|
|
|
|
|
|
|
// Add some pending and some queued transactions
|
|
|
|
@ -674,7 +682,7 @@ func TestTransactionGapFilling(t *testing.T) { |
|
|
|
|
pool, key := setupTxPool() |
|
|
|
|
defer pool.Stop() |
|
|
|
|
|
|
|
|
|
account, _ := deriveSender(transaction(0, 0, key)) |
|
|
|
|
account := crypto.PubkeyToAddress(key.PublicKey) |
|
|
|
|
pool.currentState.AddBalance(account, big.NewInt(1000000)) |
|
|
|
|
|
|
|
|
|
// Keep track of transaction events to ensure all executables get announced
|
|
|
|
@ -728,7 +736,7 @@ func TestTransactionQueueAccountLimiting(t *testing.T) { |
|
|
|
|
pool, key := setupTxPool() |
|
|
|
|
defer pool.Stop() |
|
|
|
|
|
|
|
|
|
account, _ := deriveSender(transaction(0, 0, key)) |
|
|
|
|
account := crypto.PubkeyToAddress(key.PublicKey) |
|
|
|
|
pool.currentState.AddBalance(account, big.NewInt(1000000)) |
|
|
|
|
|
|
|
|
|
// Keep queuing up transactions and make sure all above a limit are dropped
|
|
|
|
@ -923,7 +931,7 @@ func TestTransactionPendingLimiting(t *testing.T) { |
|
|
|
|
pool, key := setupTxPool() |
|
|
|
|
defer pool.Stop() |
|
|
|
|
|
|
|
|
|
account, _ := deriveSender(transaction(0, 0, key)) |
|
|
|
|
account := crypto.PubkeyToAddress(key.PublicKey) |
|
|
|
|
pool.currentState.AddBalance(account, big.NewInt(1000000)) |
|
|
|
|
|
|
|
|
|
// Keep track of transaction events to ensure all executables get announced
|
|
|
|
@ -1002,6 +1010,62 @@ func TestTransactionPendingGlobalLimiting(t *testing.T) { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Test the limit on transaction size is enforced correctly.
|
|
|
|
|
// This test verifies every transaction having allowed size
|
|
|
|
|
// is added to the pool, and longer transactions are rejected.
|
|
|
|
|
func TestTransactionAllowedTxSize(t *testing.T) { |
|
|
|
|
t.Parallel() |
|
|
|
|
|
|
|
|
|
// Create a test account and fund it
|
|
|
|
|
pool, key := setupTxPool() |
|
|
|
|
defer pool.Stop() |
|
|
|
|
|
|
|
|
|
account := crypto.PubkeyToAddress(key.PublicKey) |
|
|
|
|
pool.currentState.AddBalance(account, big.NewInt(1000000000)) |
|
|
|
|
|
|
|
|
|
// Compute maximal data size for transactions (lower bound).
|
|
|
|
|
//
|
|
|
|
|
// It is assumed the fields in the transaction (except of the data) are:
|
|
|
|
|
// - nonce <= 32 bytes
|
|
|
|
|
// - gasPrice <= 32 bytes
|
|
|
|
|
// - gasLimit <= 32 bytes
|
|
|
|
|
// - recipient == 20 bytes
|
|
|
|
|
// - value <= 32 bytes
|
|
|
|
|
// - signature == 65 bytes
|
|
|
|
|
// All those fields are summed up to at most 213 bytes.
|
|
|
|
|
baseSize := uint64(213) |
|
|
|
|
dataSize := txMaxSize - baseSize |
|
|
|
|
|
|
|
|
|
// Try adding a transaction with maximal allowed size
|
|
|
|
|
tx := pricedDataTransaction(0, pool.currentMaxGas, big.NewInt(1), key, dataSize) |
|
|
|
|
if err := pool.addRemoteSync(tx); err != nil { |
|
|
|
|
t.Fatalf("failed to add transaction of size %d, close to maximal: %v", int(tx.Size()), err) |
|
|
|
|
} |
|
|
|
|
// Try adding a transaction with random allowed size
|
|
|
|
|
if err := pool.addRemoteSync(pricedDataTransaction(1, pool.currentMaxGas, big.NewInt(1), key, uint64(rand.Intn(int(dataSize))))); err != nil { |
|
|
|
|
t.Fatalf("failed to add transaction of random allowed size: %v", err) |
|
|
|
|
} |
|
|
|
|
// Try adding a transaction of minimal not allowed size
|
|
|
|
|
if err := pool.addRemoteSync(pricedDataTransaction(2, pool.currentMaxGas, big.NewInt(1), key, txMaxSize)); err == nil { |
|
|
|
|
t.Fatalf("expected rejection on slightly oversize transaction") |
|
|
|
|
} |
|
|
|
|
// Try adding a transaction of random not allowed size
|
|
|
|
|
if err := pool.addRemoteSync(pricedDataTransaction(2, pool.currentMaxGas, big.NewInt(1), key, dataSize+1+uint64(rand.Intn(int(10*txMaxSize))))); err == nil { |
|
|
|
|
t.Fatalf("expected rejection on oversize transaction") |
|
|
|
|
} |
|
|
|
|
// Run some sanity checks on the pool internals
|
|
|
|
|
pending, queued := pool.Stats() |
|
|
|
|
if pending != 2 { |
|
|
|
|
t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 2) |
|
|
|
|
} |
|
|
|
|
if queued != 0 { |
|
|
|
|
t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 0) |
|
|
|
|
} |
|
|
|
|
if err := validateTxPoolInternals(pool); err != nil { |
|
|
|
|
t.Fatalf("pool internal state corrupted: %v", err) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Tests that if transactions start being capped, transactions are also removed from 'all'
|
|
|
|
|
func TestTransactionCapClearsFromAll(t *testing.T) { |
|
|
|
|
t.Parallel() |
|
|
|
@ -1752,6 +1816,24 @@ func TestTransactionStatusCheck(t *testing.T) { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Test the transaction slots consumption is computed correctly
|
|
|
|
|
func TestTransactionSlotCount(t *testing.T) { |
|
|
|
|
t.Parallel() |
|
|
|
|
|
|
|
|
|
key, _ := crypto.GenerateKey() |
|
|
|
|
|
|
|
|
|
// Check that an empty transaction consumes a single slot
|
|
|
|
|
smallTx := pricedDataTransaction(0, 0, big.NewInt(0), key, 0) |
|
|
|
|
if slots := numSlots(smallTx); slots != 1 { |
|
|
|
|
t.Fatalf("small transactions slot count mismatch: have %d want %d", slots, 1) |
|
|
|
|
} |
|
|
|
|
// Check that a large transaction consumes the correct number of slots
|
|
|
|
|
bigTx := pricedDataTransaction(0, 0, big.NewInt(0), key, uint64(10*txSlotSize)) |
|
|
|
|
if slots := numSlots(bigTx); slots != 11 { |
|
|
|
|
t.Fatalf("big transactions slot count mismatch: have %d want %d", slots, 11) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Benchmarks the speed of validating the contents of the pending queue of the
|
|
|
|
|
// transaction pool.
|
|
|
|
|
func BenchmarkPendingDemotion100(b *testing.B) { benchmarkPendingDemotion(b, 100) } |
|
|
|
@ -1763,7 +1845,7 @@ func benchmarkPendingDemotion(b *testing.B, size int) { |
|
|
|
|
pool, key := setupTxPool() |
|
|
|
|
defer pool.Stop() |
|
|
|
|
|
|
|
|
|
account, _ := deriveSender(transaction(0, 0, key)) |
|
|
|
|
account := crypto.PubkeyToAddress(key.PublicKey) |
|
|
|
|
pool.currentState.AddBalance(account, big.NewInt(1000000)) |
|
|
|
|
|
|
|
|
|
for i := 0; i < size; i++ { |
|
|
|
@ -1788,7 +1870,7 @@ func benchmarkFuturePromotion(b *testing.B, size int) { |
|
|
|
|
pool, key := setupTxPool() |
|
|
|
|
defer pool.Stop() |
|
|
|
|
|
|
|
|
|
account, _ := deriveSender(transaction(0, 0, key)) |
|
|
|
|
account := crypto.PubkeyToAddress(key.PublicKey) |
|
|
|
|
pool.currentState.AddBalance(account, big.NewInt(1000000)) |
|
|
|
|
|
|
|
|
|
for i := 0; i < size; i++ { |
|
|
|
@ -1812,7 +1894,7 @@ func benchmarkPoolBatchInsert(b *testing.B, size int) { |
|
|
|
|
pool, key := setupTxPool() |
|
|
|
|
defer pool.Stop() |
|
|
|
|
|
|
|
|
|
account, _ := deriveSender(transaction(0, 0, key)) |
|
|
|
|
account := crypto.PubkeyToAddress(key.PublicKey) |
|
|
|
|
pool.currentState.AddBalance(account, big.NewInt(1000000)) |
|
|
|
|
|
|
|
|
|
batches := make([]types.Transactions, b.N) |
|
|
|
|