@ -745,11 +745,11 @@ func (pool *TxPool) add(tx *types.Transaction, local bool) (replaced bool, err e
}
}
// If the new transaction is a future transaction it should never churn pending transactions
// If the new transaction is a future transaction it should never churn pending transactions
if ! isLocal && pool . isFuture ( from , tx ) {
if ! isLocal && pool . isGapped ( from , tx ) {
var replacesPending bool
var replacesPending bool
for _ , dropTx := range drop {
for _ , dropTx := range drop {
dropSender , _ := types . Sender ( pool . signer , dropTx )
dropSender , _ := types . Sender ( pool . signer , dropTx )
if list := pool . pending [ dropSender ] ; list != nil && list . Overlap s( dropTx ) {
if list := pool . pending [ dropSender ] ; list != nil && list . Contain s( dropTx . Nonce ( ) ) {
replacesPending = true
replacesPending = true
break
break
}
}
@ -774,7 +774,7 @@ func (pool *TxPool) add(tx *types.Transaction, local bool) (replaced bool, err e
}
}
// Try to replace an existing transaction in the pending pool
// Try to replace an existing transaction in the pending pool
if list := pool . pending [ from ] ; list != nil && list . Overlap s( tx ) {
if list := pool . pending [ from ] ; list != nil && list . Contain s( tx . Nonce ( ) ) {
// Nonce already pending, check if required price bump is met
// Nonce already pending, check if required price bump is met
inserted , old := list . Add ( tx , pool . config . PriceBump )
inserted , old := list . Add ( tx , pool . config . PriceBump )
if ! inserted {
if ! inserted {
@ -817,18 +817,26 @@ func (pool *TxPool) add(tx *types.Transaction, local bool) (replaced bool, err e
return replaced , nil
return replaced , nil
}
}
// isFuture reports whether the given transaction is immediately executable.
// isGapped reports whether the given transaction is immediately executable.
func ( pool * TxPool ) isFuture ( from common . Address , tx * types . Transaction ) bool {
func ( pool * TxPool ) isGapped ( from common . Address , tx * types . Transaction ) bool {
list := pool . pending [ from ]
// Short circuit if transaction matches pending nonce and can be promoted
if list == nil {
// to pending list as an executable transaction.
return pool . pendingNonces . get ( from ) != tx . Nonce ( )
next := pool . pendingNonces . get ( from )
if tx . Nonce ( ) == next {
return false
}
// The transaction has a nonce gap with pending list, it's only considered
// as executable if transactions in queue can fill up the nonce gap.
queue , ok := pool . queue [ from ]
if ! ok {
return true
}
}
// Sender has pending transactions.
for nonce := next ; nonce < tx . Nonce ( ) ; nonce ++ {
if old := list . txs . Get ( tx . Nonce ( ) ) ; old != nil {
if ! queue . Contains ( nonce ) {
return false // It replaces a pending transaction.
return true // txs in queue can't fill up the nonce gap
}
}
// Not replacing, check if parent nonce exists in pending.
}
return list . txs . Get ( tx . Nonce ( ) - 1 ) == nil
return false
}
}
// enqueueTx inserts a new transaction into the non-executable transaction queue.
// enqueueTx inserts a new transaction into the non-executable transaction queue.