core: define and test chain rewind corner cases (#21409)
* core: define and test chain reparation cornercases * core: write up a variety of set-head tests * core, eth: unify chain rollbacks, handle all the cases * core: make linter smile * core: remove commented out legacy code * core, eth/downloader: fix review comments * core: revert a removed recovery mechanism
This commit is contained in:
@ -731,12 +731,12 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) {
|
||||
return db, func() { os.RemoveAll(dir) }
|
||||
}
|
||||
// Configure a subchain to roll back
|
||||
remove := []common.Hash{}
|
||||
for _, block := range blocks[height/2:] {
|
||||
remove = append(remove, block.Hash())
|
||||
}
|
||||
remove := blocks[height/2].NumberU64()
|
||||
|
||||
// Create a small assertion method to check the three heads
|
||||
assert := func(t *testing.T, kind string, chain *BlockChain, header uint64, fast uint64, block uint64) {
|
||||
t.Helper()
|
||||
|
||||
if num := chain.CurrentBlock().NumberU64(); num != block {
|
||||
t.Errorf("%s head block mismatch: have #%v, want #%v", kind, num, block)
|
||||
}
|
||||
@ -750,14 +750,18 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) {
|
||||
// Import the chain as an archive node and ensure all pointers are updated
|
||||
archiveDb, delfn := makeDb()
|
||||
defer delfn()
|
||||
archive, _ := NewBlockChain(archiveDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil)
|
||||
|
||||
archiveCaching := *defaultCacheConfig
|
||||
archiveCaching.TrieDirtyDisabled = true
|
||||
|
||||
archive, _ := NewBlockChain(archiveDb, &archiveCaching, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil)
|
||||
if n, err := archive.InsertChain(blocks); err != nil {
|
||||
t.Fatalf("failed to process block %d: %v", n, err)
|
||||
}
|
||||
defer archive.Stop()
|
||||
|
||||
assert(t, "archive", archive, height, height, height)
|
||||
archive.Rollback(remove)
|
||||
archive.SetHead(remove - 1)
|
||||
assert(t, "archive", archive, height/2, height/2, height/2)
|
||||
|
||||
// Import the chain as a non-archive node and ensure all pointers are updated
|
||||
@ -777,7 +781,7 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) {
|
||||
t.Fatalf("failed to insert receipt %d: %v", n, err)
|
||||
}
|
||||
assert(t, "fast", fast, height, height, 0)
|
||||
fast.Rollback(remove)
|
||||
fast.SetHead(remove - 1)
|
||||
assert(t, "fast", fast, height/2, height/2, 0)
|
||||
|
||||
// Import the chain as a ancient-first node and ensure all pointers are updated
|
||||
@ -793,12 +797,12 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) {
|
||||
t.Fatalf("failed to insert receipt %d: %v", n, err)
|
||||
}
|
||||
assert(t, "ancient", ancient, height, height, 0)
|
||||
ancient.Rollback(remove)
|
||||
assert(t, "ancient", ancient, height/2, height/2, 0)
|
||||
if frozen, err := ancientDb.Ancients(); err != nil || frozen != height/2+1 {
|
||||
t.Fatalf("failed to truncate ancient store, want %v, have %v", height/2+1, frozen)
|
||||
}
|
||||
ancient.SetHead(remove - 1)
|
||||
assert(t, "ancient", ancient, 0, 0, 0)
|
||||
|
||||
if frozen, err := ancientDb.Ancients(); err != nil || frozen != 1 {
|
||||
t.Fatalf("failed to truncate ancient store, want %v, have %v", 1, frozen)
|
||||
}
|
||||
// Import the chain as a light node and ensure all pointers are updated
|
||||
lightDb, delfn := makeDb()
|
||||
defer delfn()
|
||||
@ -809,7 +813,7 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) {
|
||||
defer light.Stop()
|
||||
|
||||
assert(t, "light", light, height, 0, 0)
|
||||
light.Rollback(remove)
|
||||
light.SetHead(remove - 1)
|
||||
assert(t, "light", light, height/2, 0, 0)
|
||||
}
|
||||
|
||||
@ -1585,6 +1589,7 @@ func TestBlockchainRecovery(t *testing.T) {
|
||||
t.Fatalf("failed to create temp freezer dir: %v", err)
|
||||
}
|
||||
defer os.Remove(frdir)
|
||||
|
||||
ancientDb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "")
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create temp freezer db: %v", err)
|
||||
@ -1602,6 +1607,7 @@ func TestBlockchainRecovery(t *testing.T) {
|
||||
if n, err := ancient.InsertReceiptChain(blocks, receipts, uint64(3*len(blocks)/4)); err != nil {
|
||||
t.Fatalf("failed to insert receipt %d: %v", n, err)
|
||||
}
|
||||
rawdb.WriteLastPivotNumber(ancientDb, blocks[len(blocks)-1].NumberU64()) // Force fast sync behavior
|
||||
ancient.Stop()
|
||||
|
||||
// Destroy head fast block manually
|
||||
@ -1912,11 +1918,9 @@ func testInsertKnownChainData(t *testing.T, typ string) {
|
||||
asserter(t, blocks[len(blocks)-1])
|
||||
|
||||
// Import a long canonical chain with some known data as prefix.
|
||||
var rollback []common.Hash
|
||||
for i := len(blocks) / 2; i < len(blocks); i++ {
|
||||
rollback = append(rollback, blocks[i].Hash())
|
||||
}
|
||||
chain.Rollback(rollback)
|
||||
rollback := blocks[len(blocks)/2].NumberU64()
|
||||
|
||||
chain.SetHead(rollback - 1)
|
||||
if err := inserter(append(blocks, blocks2...), append(receipts, receipts2...)); err != nil {
|
||||
t.Fatalf("failed to insert chain data: %v", err)
|
||||
}
|
||||
@ -1936,11 +1940,7 @@ func testInsertKnownChainData(t *testing.T, typ string) {
|
||||
asserter(t, blocks3[len(blocks3)-1])
|
||||
|
||||
// Rollback the heavier chain and re-insert the longer chain again
|
||||
for i := 0; i < len(blocks3); i++ {
|
||||
rollback = append(rollback, blocks3[i].Hash())
|
||||
}
|
||||
chain.Rollback(rollback)
|
||||
|
||||
chain.SetHead(rollback - 1)
|
||||
if err := inserter(append(blocks, blocks2...), append(receipts, receipts2...)); err != nil {
|
||||
t.Fatalf("failed to insert chain data: %v", err)
|
||||
}
|
||||
|
Reference in New Issue
Block a user