diff options
author | bas-vk <bas-vk@users.noreply.github.com> | 2016-12-11 06:54:58 +0800 |
---|---|---|
committer | Felix Lange <fjl@users.noreply.github.com> | 2016-12-11 06:54:58 +0800 |
commit | 4e36b1e3dadda62a53e309a1b6cf7aed97ea7a3a (patch) | |
tree | cf54f3d14e4ac9f177b6951f92f898d8c7c9a744 /eth | |
parent | 0fe35b907addf1c066cb4d7c717bb23f9f2e7be4 (diff) | |
download | dexon-4e36b1e3dadda62a53e309a1b6cf7aed97ea7a3a.tar.gz dexon-4e36b1e3dadda62a53e309a1b6cf7aed97ea7a3a.tar.zst dexon-4e36b1e3dadda62a53e309a1b6cf7aed97ea7a3a.zip |
core: bugfix state change race condition in txpool (#3412)
The transaction pool keeps track of the current nonce in its local pendingState. When a
new block comes in the pendingState is reset. During the reset it fetches multiple times
the current state through the use of the currentState callback. When a second block comes
in during the reset its possible that the state changes during the reset. If that block
holds transactions that are currently in the pool the local pendingState that is used to
determine nonces can get out of sync.
Diffstat (limited to 'eth')
-rw-r--r-- | eth/api_backend.go | 11 | ||||
-rw-r--r-- | eth/helper_test.go | 8 | ||||
-rw-r--r-- | eth/protocol.go | 4 | ||||
-rw-r--r-- | eth/sync.go | 3 |
4 files changed, 17 insertions, 9 deletions
diff --git a/eth/api_backend.go b/eth/api_backend.go index b95ef79c5..f33b6f7e1 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -131,15 +131,20 @@ func (b *EthApiBackend) RemoveTx(txHash common.Hash) { b.eth.txPool.Remove(txHash) } -func (b *EthApiBackend) GetPoolTransactions() types.Transactions { +func (b *EthApiBackend) GetPoolTransactions() (types.Transactions, error) { b.eth.txMu.Lock() defer b.eth.txMu.Unlock() + pending, err := b.eth.txPool.Pending() + if err != nil { + return nil, err + } + var txs types.Transactions - for _, batch := range b.eth.txPool.Pending() { + for _, batch := range pending { txs = append(txs, batch...) } - return txs + return txs, nil } func (b *EthApiBackend) GetPoolTransaction(hash common.Hash) *types.Transaction { diff --git a/eth/helper_test.go b/eth/helper_test.go index f23976785..bd6b2d0da 100644 --- a/eth/helper_test.go +++ b/eth/helper_test.go @@ -93,7 +93,7 @@ type testTxPool struct { // AddBatch appends a batch of transactions to the pool, and notifies any // listeners if the addition channel is non nil -func (p *testTxPool) AddBatch(txs []*types.Transaction) { +func (p *testTxPool) AddBatch(txs []*types.Transaction) error { p.lock.Lock() defer p.lock.Unlock() @@ -101,10 +101,12 @@ func (p *testTxPool) AddBatch(txs []*types.Transaction) { if p.added != nil { p.added <- txs } + + return nil } // Pending returns all the transactions known to the pool -func (p *testTxPool) Pending() map[common.Address]types.Transactions { +func (p *testTxPool) Pending() (map[common.Address]types.Transactions, error) { p.lock.RLock() defer p.lock.RUnlock() @@ -116,7 +118,7 @@ func (p *testTxPool) Pending() map[common.Address]types.Transactions { for _, batch := range batches { sort.Sort(types.TxByNonce(batch)) } - return batches + return batches, nil } // newTestTransaction create a new dummy transaction. diff --git a/eth/protocol.go b/eth/protocol.go index 3f65c204b..7d22b33de 100644 --- a/eth/protocol.go +++ b/eth/protocol.go @@ -98,11 +98,11 @@ var errorToString = map[int]string{ type txPool interface { // AddBatch should add the given transactions to the pool. - AddBatch([]*types.Transaction) + AddBatch([]*types.Transaction) error // Pending should return pending transactions. // The slice should be modifiable by the caller. - Pending() map[common.Address]types.Transactions + Pending() (map[common.Address]types.Transactions, error) } // statusData is the network packet for the status message. diff --git a/eth/sync.go b/eth/sync.go index 6584bb1e2..373cc2054 100644 --- a/eth/sync.go +++ b/eth/sync.go @@ -46,7 +46,8 @@ type txsync struct { // syncTransactions starts sending all currently pending transactions to the given peer. func (pm *ProtocolManager) syncTransactions(p *peer) { var txs types.Transactions - for _, batch := range pm.txpool.Pending() { + pending, _ := pm.txpool.Pending() + for _, batch := range pending { txs = append(txs, batch...) } if len(txs) == 0 { |