diff --git a/core/transaction_pool.go b/core/transaction_pool.go index 462159fa7..27dc1b0d1 100644 --- a/core/transaction_pool.go +++ b/core/transaction_pool.go @@ -68,31 +68,37 @@ func (pool *TxPool) Start() { pool.events = pool.eventMux.Subscribe(ChainEvent{}) for _ = range pool.events.Chan() { pool.mu.Lock() - pool.state = state.ManageState(pool.currentState()) - // validate the pool of pending transactions, this will remove - // any transactions that have been included in the block or - // have been invalidated because of another transaction (e.g. - // higher gas price) - pool.validatePool() + pool.resetState() - // Loop over the pending transactions and base the nonce of the new - // pending transaction set. - for _, tx := range pool.pending { - if addr, err := tx.From(); err == nil { - // Set the nonce. Transaction nonce can never be lower - // than the state nonce; validatePool took care of that. - pool.state.SetNonce(addr, tx.Nonce()) - } - } - - // Check the queue and move transactions over to the pending if possible - // or remove those that have become invalid - pool.checkQueue() pool.mu.Unlock() } } +func (pool *TxPool) resetState() { + pool.state = state.ManageState(pool.currentState()) + + // validate the pool of pending transactions, this will remove + // any transactions that have been included in the block or + // have been invalidated because of another transaction (e.g. + // higher gas price) + pool.validatePool() + + // Loop over the pending transactions and base the nonce of the new + // pending transaction set. + for _, tx := range pool.pending { + if addr, err := tx.From(); err == nil { + // Set the nonce. Transaction nonce can never be lower + // than the state nonce; validatePool took care of that. + pool.state.SetNonce(addr, tx.Nonce()) + } + } + + // Check the queue and move transactions over to the pending if possible + // or remove those that have become invalid + pool.checkQueue() +} + func (pool *TxPool) Stop() { pool.pending = make(map[common.Hash]*types.Transaction) close(pool.quit) diff --git a/core/transaction_pool_test.go b/core/transaction_pool_test.go index bbd5ddad4..ac297d266 100644 --- a/core/transaction_pool_test.go +++ b/core/transaction_pool_test.go @@ -152,3 +152,52 @@ func TestNegativeValue(t *testing.T) { t.Error("expected", ErrNegativeValue, "got", err) } } + +func TestTransactionChainFork(t *testing.T) { + pool, key := setupTxPool() + addr := crypto.PubkeyToAddress(key.PublicKey) + pool.currentState().AddBalance(addr, big.NewInt(100000000000000)) + tx := transaction() + tx.GasLimit = big.NewInt(100000) + tx.SignECDSA(key) + + err := pool.add(tx) + if err != nil { + t.Error("didn't expect error", err) + } + pool.RemoveTransactions([]*types.Transaction{tx}) + + // reset the pool's internal state + pool.resetState() + err = pool.add(tx) + if err != nil { + t.Error("didn't expect error", err) + } +} + +func TestTransactionDoubleNonce(t *testing.T) { + pool, key := setupTxPool() + addr := crypto.PubkeyToAddress(key.PublicKey) + pool.currentState().AddBalance(addr, big.NewInt(100000000000000)) + tx := transaction() + tx.GasLimit = big.NewInt(100000) + tx.SignECDSA(key) + + err := pool.add(tx) + if err != nil { + t.Error("didn't expect error", err) + } + + tx2 := transaction() + tx2.GasLimit = big.NewInt(1000000) + tx2.SignECDSA(key) + + err = pool.add(tx2) + if err != nil { + t.Error("didn't expect error", err) + } + + if len(pool.pending) != 2 { + t.Error("expected 2 pending txs. Got", len(pool.pending)) + } +}