Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion core/blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -1075,10 +1075,14 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, time uint64, root common.Ha
// Remove the associated body and receipts from the key-value store.
// The header, hash-to-number mapping, and canonical hash will be
// removed by the hc.SetHead function.
if body := rawdb.ReadBody(bc.db, hash, num); body != nil {
for _, tx := range body.Transactions {
rawdb.DeleteTxLookupEntry(db, tx.Hash())
}
}
rawdb.DeleteBody(db, hash, num)
rawdb.DeleteReceipts(db, hash, num)
}
// Todo(rjl493456442) txlookup, log index, etc
}
// If SetHead was only called as a chain reparation method, try to skip
// touching the header chain altogether, unless the freezer is broken
Expand Down
38 changes: 38 additions & 0 deletions core/blockchain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4557,3 +4557,41 @@ func TestSetHeadBeyondRootFinalizedBug(t *testing.T) {
currentFinal.Number.Uint64())
}
}

// TestSetHeadTxLookupCleanup tests that rewinding the chain correctly cleans up
// transaction lookup entries (indices)
func TestSetHeadTxLookupCleanup(t *testing.T) {
// Create a clean blockchain with 100 blocks
_, _, blockchain, err := newCanonical(ethash.NewFaker(), 100, true, rawdb.PathScheme)
if err != nil {
t.Fatalf("failed to create pristine chain: %v", err)
}
defer blockchain.Stop()

// The default newCanonical blocks are empty (no txs).
// Manually overwrite Block 100's body to include a transaction.
headBlock := blockchain.CurrentBlock()
tx := types.NewTransaction(0, common.Address{0x01}, big.NewInt(0), 0, big.NewInt(0), nil)
txHash := tx.Hash()
body := &types.Body{Transactions: []*types.Transaction{tx}}

// Overwrite the body in the database
rawdb.WriteBody(blockchain.db, headBlock.Hash(), headBlock.Number.Uint64(), body)
txHashes := []common.Hash{txHash}
rawdb.WriteTxLookupEntries(blockchain.db, headBlock.Number.Uint64(), txHashes)

// Ensure the index actually exists
if entry := rawdb.ReadTxLookupEntry(blockchain.db, txHash); entry == nil {
t.Fatalf("Setup failed: TxLookup entry was not written to DB")
}

targetBlock := blockchain.GetBlockByNumber(50)
if _, err := blockchain.setHeadBeyondRoot(50, 0, targetBlock.Root(), false); err != nil {
t.Fatalf("Failed to rewind: %v", err)
}

// The TxLookup entry should be gone
if entry := rawdb.ReadTxLookupEntry(blockchain.db, txHash); entry != nil {
t.Errorf("FAIL: TxLookup entry still exists after rewind! Tx is still pointing to block %d", *entry)
}
}