diff --git a/core/tx_pool_test.go b/core/tx_pool_test.go index 4db3e6deef..3bc09e9fa5 100644 --- a/core/tx_pool_test.go +++ b/core/tx_pool_test.go @@ -152,6 +152,55 @@ func validateEvents(events chan NewTxsEvent, count int) error { return nil } +// validateDroppedEvents checks that the correct number of transaction rejection +// and drop events were fired. +func validateDroppedEvents(reject chan RejectedTxEvent, rcount int, dropped chan DropTxsEvent, dcount int) error { + count := 0 + for count < rcount { + select { + case <-reject: + count++ + case <-time.After(time.Second): + return fmt.Errorf("reject event #%d not fired", count) + } + } + rloop: + for { + select { + case <-reject: + count++ + case <-time.After(50 * time.Millisecond): + break rloop + } + } + if count > rcount { + return fmt.Errorf("more than %v reject events fired: %v", rcount, count) + } + count = 0 + for count < dcount { + select { + case <-dropped: + count++ + case <-time.After(time.Second): + return fmt.Errorf("drop event #%d not fired", count) + } + } + dloop: + for { + select { + case <-dropped: + count++ + case <-time.After(50 * time.Millisecond): + break dloop + } + } + if count > dcount { + return fmt.Errorf("more than %v drop events fired: %v", dcount, count) + } + + return nil +} + func deriveSender(tx *types.Transaction) (common.Address, error) { return types.Sender(types.HomesteadSigner{}, tx) } @@ -689,6 +738,12 @@ func TestTransactionGapFilling(t *testing.T) { events := make(chan NewTxsEvent, testTxPoolConfig.AccountQueue+5) sub := pool.txFeed.Subscribe(events) defer sub.Unsubscribe() + revents := make(chan RejectedTxEvent, testTxPoolConfig.AccountQueue+5) + rsub := pool.rejectTxFeed.Subscribe(revents) + defer rsub.Unsubscribe() + devents := make(chan DropTxsEvent, testTxPoolConfig.AccountQueue+5) + dsub := pool.dropTxFeed.Subscribe(devents) + defer dsub.Unsubscribe() // Create a pending and a queued transaction with a nonce-gap in between pool.AddRemotesSync([]*types.Transaction{ @@ -722,6 +777,9 @@ func TestTransactionGapFilling(t *testing.T) { if err := validateEvents(events, 2); err != nil { t.Fatalf("gap-filling event firing failed: %v", err) } + if err := validateDroppedEvents(revents, 0, devents, 6); err != nil { + t.Errorf("gap-filling drop / reject event firing failed: %v", err) + } if err := validateTxPoolInternals(pool); err != nil { t.Fatalf("pool internal state corrupted: %v", err) } @@ -1201,6 +1259,12 @@ func TestTransactionPoolRepricing(t *testing.T) { if err := validateEvents(events, 7); err != nil { t.Fatalf("original event firing failed: %v", err) } + revents := make(chan RejectedTxEvent, testTxPoolConfig.AccountQueue+5) + rsub := pool.rejectTxFeed.Subscribe(revents) + defer rsub.Unsubscribe() + devents := make(chan DropTxsEvent, testTxPoolConfig.AccountQueue+5) + dsub := pool.dropTxFeed.Subscribe(devents) + defer dsub.Unsubscribe() if err := validateTxPoolInternals(pool); err != nil { t.Fatalf("pool internal state corrupted: %v", err) } @@ -1217,6 +1281,9 @@ func TestTransactionPoolRepricing(t *testing.T) { if err := validateEvents(events, 0); err != nil { t.Fatalf("reprice event firing failed: %v", err) } + if err := validateDroppedEvents(revents, 0, devents, 3); err != nil { + t.Errorf("gap-filling drop / reject event firing failed: %v", err) + } if err := validateTxPoolInternals(pool); err != nil { t.Fatalf("pool internal state corrupted: %v", err) } @@ -1233,6 +1300,9 @@ func TestTransactionPoolRepricing(t *testing.T) { if err := validateEvents(events, 0); err != nil { t.Fatalf("post-reprice event firing failed: %v", err) } + if err := validateDroppedEvents(revents, 3, devents, 0); err != nil { + t.Errorf("gap-filling drop / reject event firing failed: %v", err) + } if err := validateTxPoolInternals(pool); err != nil { t.Fatalf("pool internal state corrupted: %v", err) } @@ -1247,6 +1317,9 @@ func TestTransactionPoolRepricing(t *testing.T) { if err := validateEvents(events, 1); err != nil { t.Fatalf("post-reprice local event firing failed: %v", err) } + if err := validateDroppedEvents(revents, 0, devents, 2); err != nil { + t.Errorf("gap-filling drop / reject event firing failed: %v", err) + } if err := validateTxPoolInternals(pool); err != nil { t.Fatalf("pool internal state corrupted: %v", err) } @@ -1263,6 +1336,9 @@ func TestTransactionPoolRepricing(t *testing.T) { if err := validateEvents(events, 5); err != nil { t.Fatalf("post-reprice event firing failed: %v", err) } + if err := validateDroppedEvents(revents, 0, devents, 9); err != nil { + t.Errorf("gap-filling drop / reject event firing failed: %v", err) + } if err := validateTxPoolInternals(pool); err != nil { t.Fatalf("pool internal state corrupted: %v", err) } @@ -1350,6 +1426,12 @@ func TestTransactionPoolUnderpricing(t *testing.T) { events := make(chan NewTxsEvent, 32) sub := pool.txFeed.Subscribe(events) defer sub.Unsubscribe() + revents := make(chan RejectedTxEvent, testTxPoolConfig.AccountQueue+5) + rsub := pool.rejectTxFeed.Subscribe(revents) + defer rsub.Unsubscribe() + devents := make(chan DropTxsEvent, testTxPoolConfig.AccountQueue+5) + dsub := pool.dropTxFeed.Subscribe(devents) + defer dsub.Unsubscribe() // Create a number of test accounts and fund them keys := make([]*ecdsa.PrivateKey, 4) @@ -1381,6 +1463,9 @@ func TestTransactionPoolUnderpricing(t *testing.T) { if err := validateEvents(events, 3); err != nil { t.Fatalf("original event firing failed: %v", err) } + if err := validateDroppedEvents(revents, 0, devents, 8); err != nil { + t.Errorf("gap-filling drop / reject event firing failed: %v", err) + } if err := validateTxPoolInternals(pool); err != nil { t.Fatalf("pool internal state corrupted: %v", err) } @@ -1408,6 +1493,9 @@ func TestTransactionPoolUnderpricing(t *testing.T) { if err := validateEvents(events, 1); err != nil { t.Fatalf("additional event firing failed: %v", err) } + if err := validateDroppedEvents(revents, 1, devents, 13); err != nil { + t.Errorf("gap-filling drop / reject event firing failed: %v", err) + } if err := validateTxPoolInternals(pool); err != nil { t.Fatalf("pool internal state corrupted: %v", err) } @@ -1430,6 +1518,9 @@ func TestTransactionPoolUnderpricing(t *testing.T) { if err := validateEvents(events, 2); err != nil { t.Fatalf("local event firing failed: %v", err) } + if err := validateDroppedEvents(revents, 0, devents, 7); err != nil { + t.Errorf("gap-filling drop / reject event firing failed: %v", err) + } if err := validateTxPoolInternals(pool); err != nil { t.Fatalf("pool internal state corrupted: %v", err) } @@ -1456,6 +1547,12 @@ func TestTransactionPoolStableUnderpricing(t *testing.T) { events := make(chan NewTxsEvent, 32) sub := pool.txFeed.Subscribe(events) defer sub.Unsubscribe() + revents := make(chan RejectedTxEvent, testTxPoolConfig.AccountQueue+5) + rsub := pool.rejectTxFeed.Subscribe(revents) + defer rsub.Unsubscribe() + devents := make(chan DropTxsEvent, testTxPoolConfig.AccountQueue+5) + dsub := pool.dropTxFeed.Subscribe(devents) + defer dsub.Unsubscribe() // Create a number of test accounts and fund them keys := make([]*ecdsa.PrivateKey, 2) @@ -1480,6 +1577,9 @@ func TestTransactionPoolStableUnderpricing(t *testing.T) { if err := validateEvents(events, int(config.GlobalSlots)); err != nil { t.Fatalf("original event firing failed: %v", err) } + if err := validateDroppedEvents(revents, 0, devents, 3); err != nil { + t.Errorf("gap-filling drop / reject event firing failed: %v", err) + } if err := validateTxPoolInternals(pool); err != nil { t.Fatalf("pool internal state corrupted: %v", err) } @@ -1497,6 +1597,9 @@ func TestTransactionPoolStableUnderpricing(t *testing.T) { if err := validateEvents(events, 1); err != nil { t.Fatalf("additional event firing failed: %v", err) } + if err := validateDroppedEvents(revents, 0, devents, 4); err != nil { + t.Errorf("gap-filling drop / reject event firing failed: %v", err) + } if err := validateTxPoolInternals(pool); err != nil { t.Fatalf("pool internal state corrupted: %v", err) } @@ -1583,6 +1686,12 @@ func TestTransactionReplacement(t *testing.T) { events := make(chan NewTxsEvent, 32) sub := pool.txFeed.Subscribe(events) defer sub.Unsubscribe() + revents := make(chan RejectedTxEvent, testTxPoolConfig.AccountQueue+5) + rsub := pool.rejectTxFeed.Subscribe(revents) + defer rsub.Unsubscribe() + devents := make(chan DropTxsEvent, testTxPoolConfig.AccountQueue+5) + dsub := pool.dropTxFeed.Subscribe(devents) + defer dsub.Unsubscribe() // Create a test account to add transactions with key, _ := crypto.GenerateKey() @@ -1604,6 +1713,9 @@ func TestTransactionReplacement(t *testing.T) { if err := validateEvents(events, 2); err != nil { t.Fatalf("cheap replacement event firing failed: %v", err) } + if err := validateDroppedEvents(revents, 1, devents, 4); err != nil { + t.Errorf("gap-filling drop / reject event firing failed: %v", err) + } if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(price), key)); err != nil { t.Fatalf("failed to add original proper pending transaction: %v", err) @@ -1617,6 +1729,9 @@ func TestTransactionReplacement(t *testing.T) { if err := validateEvents(events, 2); err != nil { t.Fatalf("proper replacement event firing failed: %v", err) } + if err := validateDroppedEvents(revents, 1, devents, 2); err != nil { + t.Errorf("gap-filling drop / reject event firing failed: %v", err) + } // Add queued transactions, ensuring the minimum price bump is enforced for replacement (for ultra low prices too) if err := pool.AddRemote(pricedTransaction(2, 100000, big.NewInt(1), key)); err != nil { @@ -1642,6 +1757,9 @@ func TestTransactionReplacement(t *testing.T) { if err := validateEvents(events, 0); err != nil { t.Fatalf("queued replacement event firing failed: %v", err) } + if err := validateDroppedEvents(revents, 2, devents, 6); err != nil { + t.Errorf("gap-filling drop / reject event firing failed: %v", err) + } if err := validateTxPoolInternals(pool); err != nil { t.Fatalf("pool internal state corrupted: %v", err) }