|
|
@ -209,15 +209,10 @@ func TestStateChangeDuringTransactionPoolReset(t *testing.T) { |
|
|
|
|
|
|
|
|
|
|
|
pool.lockedReset(nil, nil) |
|
|
|
pool.lockedReset(nil, nil) |
|
|
|
|
|
|
|
|
|
|
|
pendingTx, err := pool.Pending() |
|
|
|
_, err := pool.Pending() |
|
|
|
if err != nil { |
|
|
|
if err != nil { |
|
|
|
t.Fatalf("Could not fetch pending transactions: %v", err) |
|
|
|
t.Fatalf("Could not fetch pending transactions: %v", err) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
for addr, txs := range pendingTx { |
|
|
|
|
|
|
|
t.Logf("%0x: %d\n", addr, len(txs)) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
nonce = pool.State().GetNonce(address) |
|
|
|
nonce = pool.State().GetNonce(address) |
|
|
|
if nonce != 2 { |
|
|
|
if nonce != 2 { |
|
|
|
t.Fatalf("Invalid nonce, want 2, got %d", nonce) |
|
|
|
t.Fatalf("Invalid nonce, want 2, got %d", nonce) |
|
|
@ -350,7 +345,7 @@ func TestTransactionChainFork(t *testing.T) { |
|
|
|
if _, err := pool.add(tx, false); err != nil { |
|
|
|
if _, err := pool.add(tx, false); err != nil { |
|
|
|
t.Error("didn't expect error", err) |
|
|
|
t.Error("didn't expect error", err) |
|
|
|
} |
|
|
|
} |
|
|
|
pool.removeTx(tx.Hash()) |
|
|
|
pool.removeTx(tx.Hash(), true) |
|
|
|
|
|
|
|
|
|
|
|
// reset the pool's internal state
|
|
|
|
// reset the pool's internal state
|
|
|
|
resetState() |
|
|
|
resetState() |
|
|
@ -1388,13 +1383,13 @@ func TestTransactionPoolUnderpricing(t *testing.T) { |
|
|
|
t.Fatalf("adding underpriced pending transaction error mismatch: have %v, want %v", err, ErrUnderpriced) |
|
|
|
t.Fatalf("adding underpriced pending transaction error mismatch: have %v, want %v", err, ErrUnderpriced) |
|
|
|
} |
|
|
|
} |
|
|
|
// Ensure that adding high priced transactions drops cheap ones, but not own
|
|
|
|
// Ensure that adding high priced transactions drops cheap ones, but not own
|
|
|
|
if err := pool.AddRemote(pricedTransaction(0, 100000, big.NewInt(3), keys[1])); err != nil { |
|
|
|
if err := pool.AddRemote(pricedTransaction(0, 100000, big.NewInt(3), keys[1])); err != nil { // +K1:0 => -K1:1 => Pend K0:0, K0:1, K1:0, K2:0; Que -
|
|
|
|
t.Fatalf("failed to add well priced transaction: %v", err) |
|
|
|
t.Fatalf("failed to add well priced transaction: %v", err) |
|
|
|
} |
|
|
|
} |
|
|
|
if err := pool.AddRemote(pricedTransaction(2, 100000, big.NewInt(4), keys[1])); err != nil { |
|
|
|
if err := pool.AddRemote(pricedTransaction(2, 100000, big.NewInt(4), keys[1])); err != nil { // +K1:2 => -K0:0 => Pend K1:0, K2:0; Que K0:1 K1:2
|
|
|
|
t.Fatalf("failed to add well priced transaction: %v", err) |
|
|
|
t.Fatalf("failed to add well priced transaction: %v", err) |
|
|
|
} |
|
|
|
} |
|
|
|
if err := pool.AddRemote(pricedTransaction(3, 100000, big.NewInt(5), keys[1])); err != nil { |
|
|
|
if err := pool.AddRemote(pricedTransaction(3, 100000, big.NewInt(5), keys[1])); err != nil { // +K1:3 => -K0:1 => Pend K1:0, K2:0; Que K1:2 K1:3
|
|
|
|
t.Fatalf("failed to add well priced transaction: %v", err) |
|
|
|
t.Fatalf("failed to add well priced transaction: %v", err) |
|
|
|
} |
|
|
|
} |
|
|
|
pending, queued = pool.Stats() |
|
|
|
pending, queued = pool.Stats() |
|
|
@ -1404,7 +1399,7 @@ func TestTransactionPoolUnderpricing(t *testing.T) { |
|
|
|
if queued != 2 { |
|
|
|
if queued != 2 { |
|
|
|
t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 2) |
|
|
|
t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 2) |
|
|
|
} |
|
|
|
} |
|
|
|
if err := validateEvents(events, 2); err != nil { |
|
|
|
if err := validateEvents(events, 1); err != nil { |
|
|
|
t.Fatalf("additional event firing failed: %v", err) |
|
|
|
t.Fatalf("additional event firing failed: %v", err) |
|
|
|
} |
|
|
|
} |
|
|
|
if err := validateTxPoolInternals(pool); err != nil { |
|
|
|
if err := validateTxPoolInternals(pool); err != nil { |
|
|
@ -1430,6 +1425,74 @@ func TestTransactionPoolUnderpricing(t *testing.T) { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Tests that more expensive transactions push out cheap ones from the pool, but
|
|
|
|
|
|
|
|
// without producing instability by creating gaps that start jumping transactions
|
|
|
|
|
|
|
|
// back and forth between queued/pending.
|
|
|
|
|
|
|
|
func TestTransactionPoolStableUnderpricing(t *testing.T) { |
|
|
|
|
|
|
|
t.Parallel() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Create the pool to test the pricing enforcement with
|
|
|
|
|
|
|
|
db, _ := ethdb.NewMemDatabase() |
|
|
|
|
|
|
|
statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) |
|
|
|
|
|
|
|
blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
config := testTxPoolConfig |
|
|
|
|
|
|
|
config.GlobalSlots = 128 |
|
|
|
|
|
|
|
config.GlobalQueue = 0 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pool := NewTxPool(config, params.TestChainConfig, blockchain) |
|
|
|
|
|
|
|
defer pool.Stop() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Keep track of transaction events to ensure all executables get announced
|
|
|
|
|
|
|
|
events := make(chan TxPreEvent, 32) |
|
|
|
|
|
|
|
sub := pool.txFeed.Subscribe(events) |
|
|
|
|
|
|
|
defer sub.Unsubscribe() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Create a number of test accounts and fund them
|
|
|
|
|
|
|
|
keys := make([]*ecdsa.PrivateKey, 2) |
|
|
|
|
|
|
|
for i := 0; i < len(keys); i++ { |
|
|
|
|
|
|
|
keys[i], _ = crypto.GenerateKey() |
|
|
|
|
|
|
|
pool.currentState.AddBalance(crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(1000000)) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// Fill up the entire queue with the same transaction price points
|
|
|
|
|
|
|
|
txs := types.Transactions{} |
|
|
|
|
|
|
|
for i := uint64(0); i < config.GlobalSlots; i++ { |
|
|
|
|
|
|
|
txs = append(txs, pricedTransaction(i, 100000, big.NewInt(1), keys[0])) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
pool.AddRemotes(txs) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pending, queued := pool.Stats() |
|
|
|
|
|
|
|
if pending != int(config.GlobalSlots) { |
|
|
|
|
|
|
|
t.Fatalf("pending transactions mismatched: have %d, want %d", pending, config.GlobalSlots) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if queued != 0 { |
|
|
|
|
|
|
|
t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 0) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if err := validateEvents(events, int(config.GlobalSlots)); err != nil { |
|
|
|
|
|
|
|
t.Fatalf("original event firing failed: %v", err) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if err := validateTxPoolInternals(pool); err != nil { |
|
|
|
|
|
|
|
t.Fatalf("pool internal state corrupted: %v", err) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// Ensure that adding high priced transactions drops a cheap, but doesn't produce a gap
|
|
|
|
|
|
|
|
if err := pool.AddRemote(pricedTransaction(0, 100000, big.NewInt(3), keys[1])); err != nil { |
|
|
|
|
|
|
|
t.Fatalf("failed to add well priced transaction: %v", err) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
pending, queued = pool.Stats() |
|
|
|
|
|
|
|
if pending != int(config.GlobalSlots) { |
|
|
|
|
|
|
|
t.Fatalf("pending transactions mismatched: have %d, want %d", pending, config.GlobalSlots) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if queued != 0 { |
|
|
|
|
|
|
|
t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 0) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if err := validateEvents(events, 1); err != nil { |
|
|
|
|
|
|
|
t.Fatalf("additional event firing failed: %v", err) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if err := validateTxPoolInternals(pool); err != nil { |
|
|
|
|
|
|
|
t.Fatalf("pool internal state corrupted: %v", err) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Tests that the pool rejects replacement transactions that don't meet the minimum
|
|
|
|
// Tests that the pool rejects replacement transactions that don't meet the minimum
|
|
|
|
// price bump required.
|
|
|
|
// price bump required.
|
|
|
|
func TestTransactionReplacement(t *testing.T) { |
|
|
|
func TestTransactionReplacement(t *testing.T) { |
|
|
|