@@ -43,10 +43,11 @@ import (
43
43
// (v) Geth restarts normally, but it's requested to be rewound to a lower point via SetHead
44
44
// (vi) Geth restarts normally with a stale snapshot
45
45
type snapshotTest struct {
46
- legacy bool // Flag whether the loaded snapshot is in legacy format
47
- crash bool // Flag whether the Geth restarts from the previous crash
48
- gapped int // Number of blocks to insert without enabling snapshot
49
- setHead uint64 // Block number to set head back to
46
+ legacy bool // Flag whether the loaded snapshot is in legacy format
47
+ crash bool // Flag whether the Geth restarts from the previous crash
48
+ restartCrash int // Number of blocks to insert after the normal stop, then the crash happens
49
+ gapped int // Number of blocks to insert without enabling snapshot
50
+ setHead uint64 // Block number to set head back to
50
51
51
52
chainBlocks int // Number of blocks to generate for the canonical chain
52
53
snapshotBlock uint64 // Block number of the relevant snapshot disk layer
@@ -565,10 +566,50 @@ func TestSetHeadWithLegacySnapshot(t *testing.T) {
565
566
})
566
567
}
567
568
569
+ // Tests the Geth was running with snapshot(legacy-format) enabled and upgrades
570
+ // the disk layer journal(journal generator) to latest format. After that the Geth
571
+ // is restarted from a crash. In this case Geth will find the new-format disk layer
572
+ // journal but with legacy-format diff journal(the new-format is never committed),
573
+ // and the invalid diff journal is expected to be dropped.
574
+ func TestRecoverSnapshotFromCrashWithLegacyDiffJournal (t * testing.T ) {
575
+ // Chain:
576
+ // G->C1->C2->C3->C4->C5->C6->C7->C8 (HEAD)
577
+ //
578
+ // Commit: G
579
+ // Snapshot: G
580
+ //
581
+ // SetHead(0)
582
+ //
583
+ // ------------------------------
584
+ //
585
+ // Expected in leveldb:
586
+ // G->C1->C2->C3->C4->C5->C6->C7->C8->C9->C10
587
+ //
588
+ // Expected head header : C10
589
+ // Expected head fast block: C10
590
+ // Expected head block : C8
591
+ // Expected snapshot disk : C10
592
+ testSnapshot (t , & snapshotTest {
593
+ legacy : true ,
594
+ crash : false ,
595
+ restartCrash : 2 ,
596
+ gapped : 0 ,
597
+ setHead : 0 ,
598
+ chainBlocks : 8 ,
599
+ snapshotBlock : 0 ,
600
+ commitBlock : 0 ,
601
+ expCanonicalBlocks : 10 ,
602
+ expHeadHeader : 10 ,
603
+ expHeadFastBlock : 10 ,
604
+ expHeadBlock : 8 , // The persisted state in the first running
605
+ expSnapshotBottom : 10 , // The persisted disk layer in the second running
606
+ })
607
+ }
608
+
568
609
func testSnapshot (t * testing.T , tt * snapshotTest ) {
569
610
// It's hard to follow the test case, visualize the input
570
- //log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true))))
571
- //fmt.Println(tt.dump())
611
+ // log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true))))
612
+ // fmt.Println(tt.dump())
572
613
573
614
// Create a temporary persistent database
574
615
datadir , err := ioutil .TempDir ("" , "" )
@@ -694,6 +735,30 @@ func testSnapshot(t *testing.T, tt *snapshotTest) {
694
735
chain .SetHead (tt .setHead )
695
736
chain .Stop ()
696
737
738
+ chain , err = NewBlockChain (db , nil , params .AllEthashProtocolChanges , engine , vm.Config {}, nil , nil )
739
+ if err != nil {
740
+ t .Fatalf ("Failed to recreate chain: %v" , err )
741
+ }
742
+ defer chain .Stop ()
743
+ } else if tt .restartCrash != 0 {
744
+ // Firstly, stop the chain properly, with all snapshot journal
745
+ // and state committed.
746
+ chain .Stop ()
747
+
748
+ // Restart chain, forcibly flush the disk layer journal with new format
749
+ newBlocks , _ := GenerateChain (params .TestChainConfig , blocks [len (blocks )- 1 ], engine , gendb , tt .restartCrash , func (i int , b * BlockGen ) {})
750
+ chain , err = NewBlockChain (db , cacheConfig , params .AllEthashProtocolChanges , engine , vm.Config {}, nil , nil )
751
+ if err != nil {
752
+ t .Fatalf ("Failed to recreate chain: %v" , err )
753
+ }
754
+ chain .InsertChain (newBlocks )
755
+ chain .Snapshot ().Cap (newBlocks [len (newBlocks )- 1 ].Root (), 0 )
756
+
757
+ // Simulate the blockchain crash
758
+ // Don't call chain.Stop here, so that no snapshot
759
+ // journal and latest state will be committed
760
+
761
+ // Restart the chain after the crash
697
762
chain , err = NewBlockChain (db , nil , params .AllEthashProtocolChanges , engine , vm.Config {}, nil , nil )
698
763
if err != nil {
699
764
t .Fatalf ("Failed to recreate chain: %v" , err )
0 commit comments