|
|
|
@ -39,7 +39,6 @@ import ( |
|
|
|
|
|
|
|
|
|
// snapshotTestBasic wraps the common testing fields in the snapshot tests.
|
|
|
|
|
type snapshotTestBasic struct { |
|
|
|
|
legacy bool // Wether write the snapshot journal in legacy format
|
|
|
|
|
chainBlocks int // Number of blocks to generate for the canonical chain
|
|
|
|
|
snapshotBlock uint64 // Block number of the relevant snapshot disk layer
|
|
|
|
|
commitBlock uint64 // Block number for which to commit the state to disk
|
|
|
|
@ -104,19 +103,13 @@ func (basic *snapshotTestBasic) prepare(t *testing.T) (*BlockChain, []*types.Blo |
|
|
|
|
chain.stateCache.TrieDB().Commit(blocks[point-1].Root(), true, nil) |
|
|
|
|
} |
|
|
|
|
if basic.snapshotBlock > 0 && basic.snapshotBlock == point { |
|
|
|
|
if basic.legacy { |
|
|
|
|
// Here we commit the snapshot disk root to simulate
|
|
|
|
|
// committing the legacy snapshot.
|
|
|
|
|
rawdb.WriteSnapshotRoot(db, blocks[point-1].Root()) |
|
|
|
|
} else { |
|
|
|
|
// Flushing the entire snap tree into the disk, the
|
|
|
|
|
// relavant (a) snapshot root and (b) snapshot generator
|
|
|
|
|
// will be persisted atomically.
|
|
|
|
|
chain.snaps.Cap(blocks[point-1].Root(), 0) |
|
|
|
|
diskRoot, blockRoot := chain.snaps.DiskRoot(), blocks[point-1].Root() |
|
|
|
|
if !bytes.Equal(diskRoot.Bytes(), blockRoot.Bytes()) { |
|
|
|
|
t.Fatalf("Failed to flush disk layer change, want %x, got %x", blockRoot, diskRoot) |
|
|
|
|
} |
|
|
|
|
// Flushing the entire snap tree into the disk, the
|
|
|
|
|
// relavant (a) snapshot root and (b) snapshot generator
|
|
|
|
|
// will be persisted atomically.
|
|
|
|
|
chain.snaps.Cap(blocks[point-1].Root(), 0) |
|
|
|
|
diskRoot, blockRoot := chain.snaps.DiskRoot(), blocks[point-1].Root() |
|
|
|
|
if !bytes.Equal(diskRoot.Bytes(), blockRoot.Bytes()) { |
|
|
|
|
t.Fatalf("Failed to flush disk layer change, want %x, got %x", blockRoot, diskRoot) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -129,12 +122,6 @@ func (basic *snapshotTestBasic) prepare(t *testing.T) (*BlockChain, []*types.Blo |
|
|
|
|
basic.db = db |
|
|
|
|
basic.gendb = gendb |
|
|
|
|
basic.engine = engine |
|
|
|
|
|
|
|
|
|
// Ugly hack, notify the chain to flush the journal in legacy format
|
|
|
|
|
// if it's requested.
|
|
|
|
|
if basic.legacy { |
|
|
|
|
chain.writeLegacyJournal = true |
|
|
|
|
} |
|
|
|
|
return chain, blocks |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -484,46 +471,6 @@ func TestRestartWithNewSnapshot(t *testing.T) { |
|
|
|
|
// Expected snapshot disk : G
|
|
|
|
|
test := &snapshotTest{ |
|
|
|
|
snapshotTestBasic{ |
|
|
|
|
legacy: false, |
|
|
|
|
chainBlocks: 8, |
|
|
|
|
snapshotBlock: 0, |
|
|
|
|
commitBlock: 0, |
|
|
|
|
expCanonicalBlocks: 8, |
|
|
|
|
expHeadHeader: 8, |
|
|
|
|
expHeadFastBlock: 8, |
|
|
|
|
expHeadBlock: 8, |
|
|
|
|
expSnapshotBottom: 0, // Initial disk layer built from genesis
|
|
|
|
|
}, |
|
|
|
|
} |
|
|
|
|
test.test(t) |
|
|
|
|
test.teardown() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Tests a Geth restart with valid but "legacy" snapshot. Before the shutdown,
|
|
|
|
|
// all snapshot journal will be persisted correctly. In this case no snapshot
|
|
|
|
|
// recovery is required.
|
|
|
|
|
func TestRestartWithLegacySnapshot(t *testing.T) { |
|
|
|
|
// Chain:
|
|
|
|
|
// G->C1->C2->C3->C4->C5->C6->C7->C8 (HEAD)
|
|
|
|
|
//
|
|
|
|
|
// Commit: G
|
|
|
|
|
// Snapshot: G
|
|
|
|
|
//
|
|
|
|
|
// SetHead(0)
|
|
|
|
|
//
|
|
|
|
|
// ------------------------------
|
|
|
|
|
//
|
|
|
|
|
// Expected in leveldb:
|
|
|
|
|
// G->C1->C2->C3->C4->C5->C6->C7->C8
|
|
|
|
|
//
|
|
|
|
|
// Expected head header : C8
|
|
|
|
|
// Expected head fast block: C8
|
|
|
|
|
// Expected head block : C8
|
|
|
|
|
// Expected snapshot disk : G
|
|
|
|
|
t.Skip("Legacy format testing is not supported") |
|
|
|
|
test := &snapshotTest{ |
|
|
|
|
snapshotTestBasic{ |
|
|
|
|
legacy: true, |
|
|
|
|
chainBlocks: 8, |
|
|
|
|
snapshotBlock: 0, |
|
|
|
|
commitBlock: 0, |
|
|
|
@ -563,7 +510,6 @@ func TestNoCommitCrashWithNewSnapshot(t *testing.T) { |
|
|
|
|
// Expected snapshot disk : C4
|
|
|
|
|
test := &crashSnapshotTest{ |
|
|
|
|
snapshotTestBasic{ |
|
|
|
|
legacy: false, |
|
|
|
|
chainBlocks: 8, |
|
|
|
|
snapshotBlock: 4, |
|
|
|
|
commitBlock: 0, |
|
|
|
@ -603,7 +549,6 @@ func TestLowCommitCrashWithNewSnapshot(t *testing.T) { |
|
|
|
|
// Expected snapshot disk : C4
|
|
|
|
|
test := &crashSnapshotTest{ |
|
|
|
|
snapshotTestBasic{ |
|
|
|
|
legacy: false, |
|
|
|
|
chainBlocks: 8, |
|
|
|
|
snapshotBlock: 4, |
|
|
|
|
commitBlock: 2, |
|
|
|
@ -643,7 +588,6 @@ func TestHighCommitCrashWithNewSnapshot(t *testing.T) { |
|
|
|
|
// Expected snapshot disk : C4
|
|
|
|
|
test := &crashSnapshotTest{ |
|
|
|
|
snapshotTestBasic{ |
|
|
|
|
legacy: false, |
|
|
|
|
chainBlocks: 8, |
|
|
|
|
snapshotBlock: 4, |
|
|
|
|
commitBlock: 6, |
|
|
|
@ -658,131 +602,6 @@ func TestHighCommitCrashWithNewSnapshot(t *testing.T) { |
|
|
|
|
test.teardown() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Tests a Geth was crashed and restarts with a broken and "legacy format"
|
|
|
|
|
// snapshot. In this case the entire legacy snapshot should be discared
|
|
|
|
|
// and rebuild from the new chain head. The new head here refers to the
|
|
|
|
|
// genesis because there is no committed point.
|
|
|
|
|
func TestNoCommitCrashWithLegacySnapshot(t *testing.T) { |
|
|
|
|
// Chain:
|
|
|
|
|
// G->C1->C2->C3->C4->C5->C6->C7->C8 (HEAD)
|
|
|
|
|
//
|
|
|
|
|
// Commit: G
|
|
|
|
|
// Snapshot: G, C4
|
|
|
|
|
//
|
|
|
|
|
// CRASH
|
|
|
|
|
//
|
|
|
|
|
// ------------------------------
|
|
|
|
|
//
|
|
|
|
|
// Expected in leveldb:
|
|
|
|
|
// G->C1->C2->C3->C4->C5->C6->C7->C8
|
|
|
|
|
//
|
|
|
|
|
// Expected head header : C8
|
|
|
|
|
// Expected head fast block: C8
|
|
|
|
|
// Expected head block : G
|
|
|
|
|
// Expected snapshot disk : G
|
|
|
|
|
t.Skip("Legacy format testing is not supported") |
|
|
|
|
test := &crashSnapshotTest{ |
|
|
|
|
snapshotTestBasic{ |
|
|
|
|
legacy: true, |
|
|
|
|
chainBlocks: 8, |
|
|
|
|
snapshotBlock: 4, |
|
|
|
|
commitBlock: 0, |
|
|
|
|
expCanonicalBlocks: 8, |
|
|
|
|
expHeadHeader: 8, |
|
|
|
|
expHeadFastBlock: 8, |
|
|
|
|
expHeadBlock: 0, |
|
|
|
|
expSnapshotBottom: 0, // Rebuilt snapshot from the latest HEAD(genesis)
|
|
|
|
|
}, |
|
|
|
|
} |
|
|
|
|
test.test(t) |
|
|
|
|
test.teardown() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Tests a Geth was crashed and restarts with a broken and "legacy format"
|
|
|
|
|
// snapshot. In this case the entire legacy snapshot should be discared
|
|
|
|
|
// and rebuild from the new chain head. The new head here refers to the
|
|
|
|
|
// block-2 because it's committed into the disk.
|
|
|
|
|
func TestLowCommitCrashWithLegacySnapshot(t *testing.T) { |
|
|
|
|
// Chain:
|
|
|
|
|
// G->C1->C2->C3->C4->C5->C6->C7->C8 (HEAD)
|
|
|
|
|
//
|
|
|
|
|
// Commit: G, C2
|
|
|
|
|
// Snapshot: G, C4
|
|
|
|
|
//
|
|
|
|
|
// CRASH
|
|
|
|
|
//
|
|
|
|
|
// ------------------------------
|
|
|
|
|
//
|
|
|
|
|
// Expected in leveldb:
|
|
|
|
|
// G->C1->C2->C3->C4->C5->C6->C7->C8
|
|
|
|
|
//
|
|
|
|
|
// Expected head header : C8
|
|
|
|
|
// Expected head fast block: C8
|
|
|
|
|
// Expected head block : C2
|
|
|
|
|
// Expected snapshot disk : C2
|
|
|
|
|
t.Skip("Legacy format testing is not supported") |
|
|
|
|
test := &crashSnapshotTest{ |
|
|
|
|
snapshotTestBasic{ |
|
|
|
|
legacy: true, |
|
|
|
|
chainBlocks: 8, |
|
|
|
|
snapshotBlock: 4, |
|
|
|
|
commitBlock: 2, |
|
|
|
|
expCanonicalBlocks: 8, |
|
|
|
|
expHeadHeader: 8, |
|
|
|
|
expHeadFastBlock: 8, |
|
|
|
|
expHeadBlock: 2, |
|
|
|
|
expSnapshotBottom: 2, // Rebuilt snapshot from the latest HEAD
|
|
|
|
|
}, |
|
|
|
|
} |
|
|
|
|
test.test(t) |
|
|
|
|
test.teardown() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Tests a Geth was crashed and restarts with a broken and "legacy format"
|
|
|
|
|
// snapshot. In this case the entire legacy snapshot should be discared
|
|
|
|
|
// and rebuild from the new chain head.
|
|
|
|
|
//
|
|
|
|
|
// The new head here refers to the the genesis, the reason is:
|
|
|
|
|
// - the state of block-6 is committed into the disk
|
|
|
|
|
// - the legacy disk layer of block-4 is committed into the disk
|
|
|
|
|
// - the head is rewound the genesis in order to find an available
|
|
|
|
|
// state lower than disk layer
|
|
|
|
|
func TestHighCommitCrashWithLegacySnapshot(t *testing.T) { |
|
|
|
|
// Chain:
|
|
|
|
|
// G->C1->C2->C3->C4->C5->C6->C7->C8 (HEAD)
|
|
|
|
|
//
|
|
|
|
|
// Commit: G, C6
|
|
|
|
|
// Snapshot: G, C4
|
|
|
|
|
//
|
|
|
|
|
// CRASH
|
|
|
|
|
//
|
|
|
|
|
// ------------------------------
|
|
|
|
|
//
|
|
|
|
|
// Expected in leveldb:
|
|
|
|
|
// G->C1->C2->C3->C4->C5->C6->C7->C8
|
|
|
|
|
//
|
|
|
|
|
// Expected head header : C8
|
|
|
|
|
// Expected head fast block: C8
|
|
|
|
|
// Expected head block : G
|
|
|
|
|
// Expected snapshot disk : G
|
|
|
|
|
t.Skip("Legacy format testing is not supported") |
|
|
|
|
test := &crashSnapshotTest{ |
|
|
|
|
snapshotTestBasic{ |
|
|
|
|
legacy: true, |
|
|
|
|
chainBlocks: 8, |
|
|
|
|
snapshotBlock: 4, |
|
|
|
|
commitBlock: 6, |
|
|
|
|
expCanonicalBlocks: 8, |
|
|
|
|
expHeadHeader: 8, |
|
|
|
|
expHeadFastBlock: 8, |
|
|
|
|
expHeadBlock: 0, |
|
|
|
|
expSnapshotBottom: 0, // Rebuilt snapshot from the latest HEAD(genesis)
|
|
|
|
|
}, |
|
|
|
|
} |
|
|
|
|
test.test(t) |
|
|
|
|
test.teardown() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Tests a Geth was running with snapshot enabled. Then restarts without
|
|
|
|
|
// enabling snapshot and after that re-enable the snapshot again. In this
|
|
|
|
|
// case the snapshot should be rebuilt with latest chain head.
|
|
|
|
@ -806,47 +625,6 @@ func TestGappedNewSnapshot(t *testing.T) { |
|
|
|
|
// Expected snapshot disk : C10
|
|
|
|
|
test := &gappedSnapshotTest{ |
|
|
|
|
snapshotTestBasic: snapshotTestBasic{ |
|
|
|
|
legacy: false, |
|
|
|
|
chainBlocks: 8, |
|
|
|
|
snapshotBlock: 0, |
|
|
|
|
commitBlock: 0, |
|
|
|
|
expCanonicalBlocks: 10, |
|
|
|
|
expHeadHeader: 10, |
|
|
|
|
expHeadFastBlock: 10, |
|
|
|
|
expHeadBlock: 10, |
|
|
|
|
expSnapshotBottom: 10, // Rebuilt snapshot from the latest HEAD
|
|
|
|
|
}, |
|
|
|
|
gapped: 2, |
|
|
|
|
} |
|
|
|
|
test.test(t) |
|
|
|
|
test.teardown() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Tests a Geth was running with leagcy snapshot enabled. Then restarts
|
|
|
|
|
// without enabling snapshot and after that re-enable the snapshot again.
|
|
|
|
|
// In this case the snapshot should be rebuilt with latest chain head.
|
|
|
|
|
func TestGappedLegacySnapshot(t *testing.T) { |
|
|
|
|
// Chain:
|
|
|
|
|
// G->C1->C2->C3->C4->C5->C6->C7->C8 (HEAD)
|
|
|
|
|
//
|
|
|
|
|
// Commit: G
|
|
|
|
|
// Snapshot: G
|
|
|
|
|
//
|
|
|
|
|
// SetHead(0)
|
|
|
|
|
//
|
|
|
|
|
// ------------------------------
|
|
|
|
|
//
|
|
|
|
|
// Expected in leveldb:
|
|
|
|
|
// G->C1->C2->C3->C4->C5->C6->C7->C8->C9->C10
|
|
|
|
|
//
|
|
|
|
|
// Expected head header : C10
|
|
|
|
|
// Expected head fast block: C10
|
|
|
|
|
// Expected head block : C10
|
|
|
|
|
// Expected snapshot disk : C10
|
|
|
|
|
t.Skip("Legacy format testing is not supported") |
|
|
|
|
test := &gappedSnapshotTest{ |
|
|
|
|
snapshotTestBasic: snapshotTestBasic{ |
|
|
|
|
legacy: true, |
|
|
|
|
chainBlocks: 8, |
|
|
|
|
snapshotBlock: 0, |
|
|
|
|
commitBlock: 0, |
|
|
|
@ -885,7 +663,6 @@ func TestSetHeadWithNewSnapshot(t *testing.T) { |
|
|
|
|
// Expected snapshot disk : G
|
|
|
|
|
test := &setHeadSnapshotTest{ |
|
|
|
|
snapshotTestBasic: snapshotTestBasic{ |
|
|
|
|
legacy: false, |
|
|
|
|
chainBlocks: 8, |
|
|
|
|
snapshotBlock: 0, |
|
|
|
|
commitBlock: 0, |
|
|
|
@ -901,88 +678,6 @@ func TestSetHeadWithNewSnapshot(t *testing.T) { |
|
|
|
|
test.teardown() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Tests the Geth was running with snapshot(legacy-format) enabled and resetHead
|
|
|
|
|
// is applied. In this case the head is rewound to the target(with state available).
|
|
|
|
|
// After that the chain is restarted and the original disk layer is kept.
|
|
|
|
|
func TestSetHeadWithLegacySnapshot(t *testing.T) { |
|
|
|
|
// Chain:
|
|
|
|
|
// G->C1->C2->C3->C4->C5->C6->C7->C8 (HEAD)
|
|
|
|
|
//
|
|
|
|
|
// Commit: G
|
|
|
|
|
// Snapshot: G
|
|
|
|
|
//
|
|
|
|
|
// SetHead(4)
|
|
|
|
|
//
|
|
|
|
|
// ------------------------------
|
|
|
|
|
//
|
|
|
|
|
// Expected in leveldb:
|
|
|
|
|
// G->C1->C2->C3->C4
|
|
|
|
|
//
|
|
|
|
|
// Expected head header : C4
|
|
|
|
|
// Expected head fast block: C4
|
|
|
|
|
// Expected head block : C4
|
|
|
|
|
// Expected snapshot disk : G
|
|
|
|
|
t.Skip("Legacy format testing is not supported") |
|
|
|
|
test := &setHeadSnapshotTest{ |
|
|
|
|
snapshotTestBasic: snapshotTestBasic{ |
|
|
|
|
legacy: true, |
|
|
|
|
chainBlocks: 8, |
|
|
|
|
snapshotBlock: 0, |
|
|
|
|
commitBlock: 0, |
|
|
|
|
expCanonicalBlocks: 4, |
|
|
|
|
expHeadHeader: 4, |
|
|
|
|
expHeadFastBlock: 4, |
|
|
|
|
expHeadBlock: 4, |
|
|
|
|
expSnapshotBottom: 0, // The initial disk layer is built from the genesis
|
|
|
|
|
}, |
|
|
|
|
setHead: 4, |
|
|
|
|
} |
|
|
|
|
test.test(t) |
|
|
|
|
test.teardown() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Tests the Geth was running with snapshot(legacy-format) enabled and upgrades
|
|
|
|
|
// the disk layer journal(journal generator) to latest format. After that the Geth
|
|
|
|
|
// is restarted from a crash. In this case Geth will find the new-format disk layer
|
|
|
|
|
// journal but with legacy-format diff journal(the new-format is never committed),
|
|
|
|
|
// and the invalid diff journal is expected to be dropped.
|
|
|
|
|
func TestRecoverSnapshotFromCrashWithLegacyDiffJournal(t *testing.T) { |
|
|
|
|
// Chain:
|
|
|
|
|
// G->C1->C2->C3->C4->C5->C6->C7->C8 (HEAD)
|
|
|
|
|
//
|
|
|
|
|
// Commit: G
|
|
|
|
|
// Snapshot: G
|
|
|
|
|
//
|
|
|
|
|
// SetHead(0)
|
|
|
|
|
//
|
|
|
|
|
// ------------------------------
|
|
|
|
|
//
|
|
|
|
|
// Expected in leveldb:
|
|
|
|
|
// G->C1->C2->C3->C4->C5->C6->C7->C8->C9->C10
|
|
|
|
|
//
|
|
|
|
|
// Expected head header : C10
|
|
|
|
|
// Expected head fast block: C10
|
|
|
|
|
// Expected head block : C8
|
|
|
|
|
// Expected snapshot disk : C10
|
|
|
|
|
t.Skip("Legacy format testing is not supported") |
|
|
|
|
test := &restartCrashSnapshotTest{ |
|
|
|
|
snapshotTestBasic: snapshotTestBasic{ |
|
|
|
|
legacy: true, |
|
|
|
|
chainBlocks: 8, |
|
|
|
|
snapshotBlock: 0, |
|
|
|
|
commitBlock: 0, |
|
|
|
|
expCanonicalBlocks: 10, |
|
|
|
|
expHeadHeader: 10, |
|
|
|
|
expHeadFastBlock: 10, |
|
|
|
|
expHeadBlock: 8, // The persisted state in the first running
|
|
|
|
|
expSnapshotBottom: 10, // The persisted disk layer in the second running
|
|
|
|
|
}, |
|
|
|
|
newBlocks: 2, |
|
|
|
|
} |
|
|
|
|
test.test(t) |
|
|
|
|
test.teardown() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Tests the Geth was running with a complete snapshot and then imports a few
|
|
|
|
|
// more new blocks on top without enabling the snapshot. After the restart,
|
|
|
|
|
// crash happens. Check everything is ok after the restart.
|
|
|
|
@ -1006,7 +701,6 @@ func TestRecoverSnapshotFromWipingCrash(t *testing.T) { |
|
|
|
|
// Expected snapshot disk : C10
|
|
|
|
|
test := &wipeCrashSnapshotTest{ |
|
|
|
|
snapshotTestBasic: snapshotTestBasic{ |
|
|
|
|
legacy: false, |
|
|
|
|
chainBlocks: 8, |
|
|
|
|
snapshotBlock: 4, |
|
|
|
|
commitBlock: 0, |
|
|
|
|