Skip to content

Commit edaed4f

Browse files
committed
core: fix write concurrency in txpool (ethereum#19835)
1 parent 6338a41 commit edaed4f

File tree

2 files changed

+29
-9
lines changed

2 files changed

+29
-9
lines changed

core/tx_noncer.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
package core
1818

1919
import (
20+
"sync"
21+
2022
"github.com/XinFinOrg/XDPoSChain/common"
2123
"github.com/XinFinOrg/XDPoSChain/core/state"
2224
)
@@ -27,6 +29,7 @@ import (
2729
type txNoncer struct {
2830
fallback *state.StateDB
2931
nonces map[common.Address]uint64
32+
lock sync.Mutex
3033
}
3134

3235
// newTxNoncer creates a new virtual state database to track the pool nonces.
@@ -40,6 +43,11 @@ func newTxNoncer(statedb *state.StateDB) *txNoncer {
4043
// get returns the current nonce of an account, falling back to a real state
4144
// database if the account is unknown.
4245
func (txn *txNoncer) get(addr common.Address) uint64 {
46+
// We use mutex for get operation is the underlying
47+
// state will mutate db even for read access.
48+
txn.lock.Lock()
49+
defer txn.lock.Unlock()
50+
4351
if _, ok := txn.nonces[addr]; !ok {
4452
txn.nonces[addr] = txn.fallback.GetNonce(addr)
4553
}
@@ -49,5 +57,23 @@ func (txn *txNoncer) get(addr common.Address) uint64 {
4957
// set inserts a new virtual nonce into the virtual state database to be returned
5058
// whenever the pool requests it instead of reaching into the real state database.
5159
func (txn *txNoncer) set(addr common.Address, nonce uint64) {
60+
txn.lock.Lock()
61+
defer txn.lock.Unlock()
62+
63+
txn.nonces[addr] = nonce
64+
}
65+
66+
// setIfLower updates a new virtual nonce into the virtual state database if the
67+
// the new one is lower.
68+
func (txn *txNoncer) setIfLower(addr common.Address, nonce uint64) {
69+
txn.lock.Lock()
70+
defer txn.lock.Unlock()
71+
72+
if _, ok := txn.nonces[addr]; !ok {
73+
txn.nonces[addr] = txn.fallback.GetNonce(addr)
74+
}
75+
if txn.nonces[addr] <= nonce {
76+
return
77+
}
5278
txn.nonces[addr] = nonce
5379
}

core/tx_pool.go

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -993,9 +993,7 @@ func (pool *TxPool) removeTx(hash common.Hash, outofbound bool) {
993993
pool.enqueueTx(tx.Hash(), tx)
994994
}
995995
// Update the account nonce if needed
996-
if nonce := tx.Nonce(); pool.pendingNonces.get(addr) > nonce {
997-
pool.pendingNonces.set(addr, nonce)
998-
}
996+
pool.pendingNonces.setIfLower(addr, tx.Nonce())
999997
// Reduce the pending counter
1000998
pendingCounter.Dec(int64(1 + len(invalids)))
1001999
return
@@ -1381,9 +1379,7 @@ func (pool *TxPool) truncatePending() {
13811379
pool.all.Remove(hash)
13821380

13831381
// Update the account nonce to the dropped transaction
1384-
if nonce := tx.Nonce(); pool.pendingNonces.get(offenders[i]) > nonce {
1385-
pool.pendingNonces.set(offenders[i], nonce)
1386-
}
1382+
pool.pendingNonces.setIfLower(offenders[i], tx.Nonce())
13871383
log.Trace("Removed fairness-exceeding pending transaction", "hash", hash)
13881384
}
13891385
pool.priced.Removed(len(caps))
@@ -1410,9 +1406,7 @@ func (pool *TxPool) truncatePending() {
14101406
pool.all.Remove(hash)
14111407

14121408
// Update the account nonce to the dropped transaction
1413-
if nonce := tx.Nonce(); pool.pendingNonces.get(addr) > nonce {
1414-
pool.pendingNonces.set(addr, nonce)
1415-
}
1409+
pool.pendingNonces.setIfLower(addr, tx.Nonce())
14161410
log.Trace("Removed fairness-exceeding pending transaction", "hash", hash)
14171411
}
14181412
pool.priced.Removed(len(caps))

0 commit comments

Comments
 (0)