From 47fd824ebd0295fd07835fd3600fdca545fd0e84 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Mon, 16 Sep 2019 15:08:45 +0200 Subject: [PATCH 1/2] txpool: smaller lock portion --- core/tx_pool.go | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/core/tx_pool.go b/core/tx_pool.go index 161489cc5a99..db63efbc981b 100644 --- a/core/tx_pool.go +++ b/core/tx_pool.go @@ -803,18 +803,17 @@ func (pool *TxPool) addTxsLocked(txs []*types.Transaction, local bool) ([]error, // Status returns the status (unknown/pending/queued) of a batch of transactions // identified by their hashes. func (pool *TxPool) Status(hashes []common.Hash) []TxStatus { - pool.mu.RLock() - defer pool.mu.RUnlock() - status := make([]TxStatus, len(hashes)) for i, hash := range hashes { - if tx := pool.all.Get(hash); tx != nil { + if tx := pool.Get(hash); tx != nil { from, _ := types.Sender(pool.signer, tx) // already validated - if pool.pending[from] != nil && pool.pending[from].txs.items[tx.Nonce()] != nil { + pool.mu.RLock() + if txList := pool.pending[from]; txList != nil && txList.txs.items[tx.Nonce()] != nil { status[i] = TxStatusPending } else { status[i] = TxStatusQueued } + pool.mu.RUnlock() } } return status From aab6a0b0ab4212098b3e61b8b90fef39f1ea1c7c Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Mon, 16 Sep 2019 15:38:45 +0200 Subject: [PATCH 2/2] core/tx_pool: fix data race --- core/tx_pool.go | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/core/tx_pool.go b/core/tx_pool.go index db63efbc981b..e25877a1aa56 100644 --- a/core/tx_pool.go +++ b/core/tx_pool.go @@ -805,16 +805,20 @@ func (pool *TxPool) addTxsLocked(txs []*types.Transaction, local bool) ([]error, func (pool *TxPool) Status(hashes []common.Hash) []TxStatus { status := make([]TxStatus, len(hashes)) for i, hash := range hashes { - if tx := pool.Get(hash); tx != nil { - from, _ := types.Sender(pool.signer, tx) // already validated - pool.mu.RLock() - if txList := pool.pending[from]; txList != nil && txList.txs.items[tx.Nonce()] != nil { - status[i] = TxStatusPending - } else { - status[i] = TxStatusQueued - } - pool.mu.RUnlock() + tx := pool.Get(hash) + if tx == nil { + continue + } + from, _ := types.Sender(pool.signer, tx) // already validated + pool.mu.RLock() + if txList := pool.pending[from]; txList != nil && txList.txs.items[tx.Nonce()] != nil { + status[i] = TxStatusPending + } else if txList := pool.queue[from]; txList != nil && txList.txs.items[tx.Nonce()] != nil { + status[i] = TxStatusQueued } + // implicit else: the tx may have been included into a block between + // checking pool.Get and obtaining the lock. In that case, TxStatusUnknown is correct + pool.mu.RUnlock() } return status }