@ -109,6 +109,10 @@ func validateTxPoolInternals(pool *TxPool) error {
if priced := pool . priced . items . Len ( ) - pool . priced . stales ; priced != pending + queued {
return fmt . Errorf ( "total priced transaction count %d != %d pending + %d queued" , priced , pending , queued )
}
if queued != len ( pool . queuedTs ) {
return fmt . Errorf ( "total queued transaction count %d != %d queuedTs length" , queued , len ( pool . queuedTs ) )
}
// Ensure the next nonce to assign is the correct one
for addr , txs := range pool . pending {
// Find the last transaction
@ -868,7 +872,7 @@ func TestTransactionQueueTimeLimitingNoLocals(t *testing.T) {
func testTransactionQueueTimeLimiting ( t * testing . T , nolocals bool ) {
// Reduce the eviction interval to a testable amount
defer func ( old time . Duration ) { evictionInterval = old } ( evictionInterval )
evictionInterval = time . Second
evictionInterval = time . Millisecond * 100
// Create the pool to test the non-expiration enforcement
statedb , _ := state . New ( common . Hash { } , state . NewDatabase ( rawdb . NewMemoryDatabase ( ) ) , nil )
@ -905,6 +909,22 @@ func testTransactionQueueTimeLimiting(t *testing.T, nolocals bool) {
if err := validateTxPoolInternals ( pool ) ; err != nil {
t . Fatalf ( "pool internal state corrupted: %v" , err )
}
// Allow the eviction interval to run
time . Sleep ( 2 * evictionInterval )
// Transactions should not be evicted from the queue yet since lifetime duration has not passed
pending , queued = pool . Stats ( )
if pending != 0 {
t . Fatalf ( "pending transactions mismatched: have %d, want %d" , pending , 0 )
}
if queued != 2 {
t . Fatalf ( "queued transactions mismatched: have %d, want %d" , queued , 2 )
}
if err := validateTxPoolInternals ( pool ) ; err != nil {
t . Fatalf ( "pool internal state corrupted: %v" , err )
}
// Wait a bit for eviction to run and clean up any leftovers, and ensure only the local remains
time . Sleep ( 2 * config . Lifetime )
@ -924,6 +944,117 @@ func testTransactionQueueTimeLimiting(t *testing.T, nolocals bool) {
if err := validateTxPoolInternals ( pool ) ; err != nil {
t . Fatalf ( "pool internal state corrupted: %v" , err )
}
// remove current transactions and increase nonce to prepare for a reset and cleanup
statedb . SetNonce ( crypto . PubkeyToAddress ( remote . PublicKey ) , 2 )
statedb . SetNonce ( crypto . PubkeyToAddress ( local . PublicKey ) , 2 )
<- pool . requestReset ( nil , nil )
// make sure queue, pending are cleared
pending , queued = pool . Stats ( )
if pending != 0 {
t . Fatalf ( "pending transactions mismatched: have %d, want %d" , pending , 0 )
}
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 )
}
if err := pool . AddLocal ( pricedTransaction ( 2 , 100000 , big . NewInt ( 1 ) , local ) ) ; err != nil {
t . Fatalf ( "failed to add remote transaction: %v" , err )
}
if err := pool . AddLocal ( pricedTransaction ( 4 , 100000 , big . NewInt ( 1 ) , local ) ) ; err != nil {
t . Fatalf ( "failed to add remote transaction: %v" , err )
}
if err := pool . addRemoteSync ( pricedTransaction ( 2 , 100000 , big . NewInt ( 1 ) , remote ) ) ; err != nil {
t . Fatalf ( "failed to add remote transaction: %v" , err )
}
if err := pool . addRemoteSync ( pricedTransaction ( 4 , 100000 , big . NewInt ( 1 ) , remote ) ) ; err != nil {
t . Fatalf ( "failed to add remote transaction: %v" , err )
}
// wait a short amount of time to add an additional future queued item to test proper eviction when
// pending is removed
time . Sleep ( 2 * evictionInterval )
if err := pool . addRemoteSync ( pricedTransaction ( 5 , 100000 , big . NewInt ( 1 ) , remote ) ) ; err != nil {
t . Fatalf ( "failed to add remote transaction: %v" , err )
}
// Make sure future queue and pending have transactions
pending , queued = pool . Stats ( )
if pending != 2 {
t . Fatalf ( "pending transactions mismatched: have %d, want %d" , pending , 2 )
}
if queued != 3 {
t . Fatalf ( "queued transactions mismatched: have %d, want %d" , queued , 3 )
}
if err := validateTxPoolInternals ( pool ) ; err != nil {
t . Fatalf ( "pool internal state corrupted: %v" , err )
}
// Trigger a reset to make sure queued items are not evicted
statedb . SetNonce ( crypto . PubkeyToAddress ( remote . PublicKey ) , 3 )
statedb . SetNonce ( crypto . PubkeyToAddress ( local . PublicKey ) , 3 )
<- pool . requestReset ( nil , nil )
// Wait for eviction to run
time . Sleep ( evictionInterval * 2 )
// a pool reset, empty pending list, or demotion of pending transactions should maintain
// queued transactions for non locals and locals alike if the lifetime duration has not passed yet
pending , queued = pool . Stats ( )
if pending != 0 {
t . Fatalf ( "pending transactions mismatched: have %d, want %d" , pending , 0 )
}
if queued != 3 {
t . Fatalf ( "queued transactions mismatched: have %d, want %d" , queued , 2 )
}
if err := validateTxPoolInternals ( pool ) ; err != nil {
t . Fatalf ( "pool internal state corrupted: %v" , err )
}
// Wait for the lifetime to run for all transactions except the one that was added later
time . Sleep ( evictionInterval * 7 )
pending , queued = pool . Stats ( )
if pending != 0 {
t . Fatalf ( "pending transactions mismatched: have %d, want %d" , pending , 0 )
}
if nolocals {
if queued != 1 {
t . Fatalf ( "queued transactions mismatched: have %d, want %d" , queued , 1 )
}
} else {
if queued != 2 {
t . Fatalf ( "queued transactions mismatched: have %d, want %d" , queued , 2 )
}
}
if err := validateTxPoolInternals ( pool ) ; err != nil {
t . Fatalf ( "pool internal state corrupted: %v" , err )
}
// lifetime should pass for the final transaction
time . Sleep ( evictionInterval * 2 )
pending , queued = pool . Stats ( )
if pending != 0 {
t . Fatalf ( "pending transactions mismatched: have %d, want %d" , pending , 0 )
}
if nolocals {
if queued != 0 {
t . Fatalf ( "queued transactions mismatched: have %d, want %d" , queued , 2 )
}
} else {
if queued != 1 {
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 even if the transaction count belonging to a single account goes