Skip to content

Commit 5e1581c

Browse files
authored
core: fix panic when stat-ing a tx from a queue-only account (ethereum#15714)
1 parent 50df2b7 commit 5e1581c

File tree

2 files changed

+58
-1
lines changed

2 files changed

+58
-1
lines changed

core/tx_pool.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -838,7 +838,7 @@ func (pool *TxPool) Status(hashes []common.Hash) []TxStatus {
838838
for i, hash := range hashes {
839839
if tx := pool.all[hash]; tx != nil {
840840
from, _ := types.Sender(pool.signer, tx) // already validated
841-
if pool.pending[from].txs.items[tx.Nonce()] != nil {
841+
if pool.pending[from] != nil && pool.pending[from].txs.items[tx.Nonce()] != nil {
842842
status[i] = TxStatusPending
843843
} else {
844844
status[i] = TxStatusQueued

core/tx_pool_test.go

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1563,6 +1563,63 @@ func testTransactionJournaling(t *testing.T, nolocals bool) {
15631563
pool.Stop()
15641564
}
15651565

1566+
// TestTransactionStatusCheck tests that the pool can correctly retrieve the
1567+
// pending status of individual transactions.
1568+
func TestTransactionStatusCheck(t *testing.T) {
1569+
t.Parallel()
1570+
1571+
// Create the pool to test the status retrievals with
1572+
db, _ := ethdb.NewMemDatabase()
1573+
statedb, _ := state.New(common.Hash{}, state.NewDatabase(db))
1574+
blockchain := &testBlockChain{statedb, big.NewInt(1000000), new(event.Feed)}
1575+
1576+
pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain)
1577+
defer pool.Stop()
1578+
1579+
// Create the test accounts to check various transaction statuses with
1580+
keys := make([]*ecdsa.PrivateKey, 3)
1581+
for i := 0; i < len(keys); i++ {
1582+
keys[i], _ = crypto.GenerateKey()
1583+
pool.currentState.AddBalance(crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(1000000))
1584+
}
1585+
// Generate and queue a batch of transactions, both pending and queued
1586+
txs := types.Transactions{}
1587+
1588+
txs = append(txs, pricedTransaction(0, big.NewInt(100000), big.NewInt(1), keys[0])) // Pending only
1589+
txs = append(txs, pricedTransaction(0, big.NewInt(100000), big.NewInt(1), keys[1])) // Pending and queued
1590+
txs = append(txs, pricedTransaction(2, big.NewInt(100000), big.NewInt(1), keys[1]))
1591+
txs = append(txs, pricedTransaction(2, big.NewInt(100000), big.NewInt(1), keys[2])) // Queued only
1592+
1593+
// Import the transaction and ensure they are correctly added
1594+
pool.AddRemotes(txs)
1595+
1596+
pending, queued := pool.Stats()
1597+
if pending != 2 {
1598+
t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 2)
1599+
}
1600+
if queued != 2 {
1601+
t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 2)
1602+
}
1603+
if err := validateTxPoolInternals(pool); err != nil {
1604+
t.Fatalf("pool internal state corrupted: %v", err)
1605+
}
1606+
// Retrieve the status of each transaction and validate them
1607+
hashes := make([]common.Hash, len(txs))
1608+
for i, tx := range txs {
1609+
hashes[i] = tx.Hash()
1610+
}
1611+
hashes = append(hashes, common.Hash{})
1612+
1613+
statuses := pool.Status(hashes)
1614+
expect := []TxStatus{TxStatusPending, TxStatusPending, TxStatusQueued, TxStatusQueued, TxStatusUnknown}
1615+
1616+
for i := 0; i < len(statuses); i++ {
1617+
if statuses[i] != expect[i] {
1618+
t.Errorf("transaction %d: status mismatch: have %v, want %v", i, statuses[i], expect[i])
1619+
}
1620+
}
1621+
}
1622+
15661623
// Benchmarks the speed of validating the contents of the pending queue of the
15671624
// transaction pool.
15681625
func BenchmarkPendingDemotion100(b *testing.B) { benchmarkPendingDemotion(b, 100) }

0 commit comments

Comments
 (0)