Skip to content

Commit 4aee0d1

Browse files
holimankaralabe
authored andcommitted
core: fix crash in chain reimport (#19986)
* blockchain: fix flaw in block import * core/blockchain: address review concerns * core/blockchain: go format with 's'
1 parent 039a9c3 commit 4aee0d1

File tree

2 files changed

+51
-0
lines changed

2 files changed

+51
-0
lines changed

core/blockchain.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1742,6 +1742,11 @@ func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator) (i
17421742
canonical := bc.GetBlockByNumber(number)
17431743
if canonical != nil && canonical.Hash() == block.Hash() {
17441744
// Not a sidechain block, this is a re-import of a canon block which has it's state pruned
1745+
1746+
// Collect the TD of the block. Since we know it's a canon one,
1747+
// we can get it directly, and not (like further below) use
1748+
// the parent and then add the block on top
1749+
externTd = bc.GetTd(block.Hash(), block.NumberU64())
17451750
continue
17461751
}
17471752
if canonical != nil && canonical.Root() == block.Root() {

core/blockchain_test.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2241,3 +2241,49 @@ func BenchmarkBlockChain_1x1000Executions(b *testing.B) {
22412241
}
22422242
benchmarkLargeNumberOfValueToNonexisting(b, numTxs, numBlocks, recipientFn, dataFn)
22432243
}
2244+
2245+
// Tests that importing a some old blocks, where all blocks are before the
2246+
// pruning point.
2247+
// This internally leads to a sidechain import, since the blocks trigger an
2248+
// ErrPrunedAncestor error.
2249+
// This may e.g. happen if
2250+
// 1. Downloader rollbacks a batch of inserted blocks and exits
2251+
// 2. Downloader starts to sync again
2252+
// 3. The blocks fetched are all known and canonical blocks
2253+
func TestSideImportPrunedBlocks(t *testing.T) {
2254+
// Generate a canonical chain to act as the main dataset
2255+
engine := ethash.NewFaker()
2256+
db := rawdb.NewMemoryDatabase()
2257+
genesis := new(Genesis).MustCommit(db)
2258+
2259+
// Generate and import the canonical chain
2260+
blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 2*TriesInMemory, nil)
2261+
diskdb := rawdb.NewMemoryDatabase()
2262+
new(Genesis).MustCommit(diskdb)
2263+
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil)
2264+
if err != nil {
2265+
t.Fatalf("failed to create tester chain: %v", err)
2266+
}
2267+
if n, err := chain.InsertChain(blocks); err != nil {
2268+
t.Fatalf("block %d: failed to insert into chain: %v", n, err)
2269+
}
2270+
2271+
lastPrunedIndex := len(blocks) - TriesInMemory - 1
2272+
lastPrunedBlock := blocks[lastPrunedIndex]
2273+
2274+
// Verify pruning of lastPrunedBlock
2275+
if chain.HasBlockAndState(lastPrunedBlock.Hash(), lastPrunedBlock.NumberU64()) {
2276+
t.Errorf("Block %d not pruned", lastPrunedBlock.NumberU64())
2277+
}
2278+
firstNonPrunedBlock := blocks[len(blocks)-TriesInMemory]
2279+
// Verify firstNonPrunedBlock is not pruned
2280+
if !chain.HasBlockAndState(firstNonPrunedBlock.Hash(), firstNonPrunedBlock.NumberU64()) {
2281+
t.Errorf("Block %d pruned", firstNonPrunedBlock.NumberU64())
2282+
}
2283+
// Now re-import some old blocks
2284+
blockToReimport := blocks[5:8]
2285+
_, err = chain.InsertChain(blockToReimport)
2286+
if err != nil {
2287+
t.Errorf("Got error, %v", err)
2288+
}
2289+
}

0 commit comments

Comments
 (0)