-
Notifications
You must be signed in to change notification settings - Fork 225
/
journal.go
143 lines (130 loc) · 5.13 KB
/
journal.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
// (c) 2019-2020, Ava Labs, Inc.
//
// This file is a derived work, based on the go-ethereum library whose original
// notices appear below.
//
// It is distributed under a license compatible with the licensing terms of the
// original code from which it is derived.
//
// Much love to the original authors for their work.
// **********
// Copyright 2019 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package snapshot
import (
"encoding/binary"
"errors"
"fmt"
"time"
"github.com/ava-labs/subnet-evm/core/rawdb"
"github.com/ava-labs/subnet-evm/ethdb"
"github.com/ava-labs/subnet-evm/trie"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rlp"
)
// journalGenerator is a disk layer entry containing the generator progress marker.
type journalGenerator struct {
// Indicator that whether the database was in progress of being wiped.
// It's deprecated but keep it here for background compatibility.
Wiping bool
Done bool // Whether the generator finished creating the snapshot
Marker []byte
Accounts uint64
Slots uint64
Storage uint64
}
// loadSnapshot loads a pre-existing state snapshot backed by a key-value
// store. If loading the snapshot from disk is successful, this function also
// returns a boolean indicating whether or not the snapshot is fully generated.
func loadSnapshot(diskdb ethdb.KeyValueStore, triedb *trie.Database, cache int, blockHash, root common.Hash, noBuild bool) (snapshot, bool, error) {
// Retrieve the block number and hash of the snapshot, failing if no snapshot
// is present in the database (or crashed mid-update).
baseBlockHash := rawdb.ReadSnapshotBlockHash(diskdb)
if baseBlockHash == (common.Hash{}) {
return nil, false, fmt.Errorf("missing or corrupted snapshot, no snapshot block hash")
}
if baseBlockHash != blockHash {
return nil, false, fmt.Errorf("block hash stored on disk (%#x) does not match last accepted (%#x)", baseBlockHash, blockHash)
}
baseRoot := rawdb.ReadSnapshotRoot(diskdb)
if baseRoot == (common.Hash{}) {
return nil, false, errors.New("missing or corrupted snapshot, no snapshot root")
}
if baseRoot != root {
return nil, false, fmt.Errorf("root stored on disk (%#x) does not match last accepted (%#x)", baseRoot, root)
}
// Retrieve the disk layer generator. It must exist, no matter the
// snapshot is fully generated or not. Otherwise the entire disk
// layer is invalid.
generatorBlob := rawdb.ReadSnapshotGenerator(diskdb)
if len(generatorBlob) == 0 {
return nil, false, errors.New("missing snapshot generator")
}
var generator journalGenerator
if err := rlp.DecodeBytes(generatorBlob, &generator); err != nil {
return nil, false, fmt.Errorf("failed to decode snapshot generator: %v", err)
}
// Instantiate snapshot as disk layer with last recorded block hash and root
snapshot := &diskLayer{
diskdb: diskdb,
triedb: triedb,
cache: newMeteredSnapshotCache(cache * 1024 * 1024),
root: baseRoot,
blockHash: baseBlockHash,
created: time.Now(),
}
var wiper chan struct{}
// Load the disk layer status from the generator if it's not complete
if !generator.Done {
// If the generator was still wiping, restart one from scratch (fine for
// now as it's rare and the wiper deletes the stuff it touches anyway, so
// restarting won't incur a lot of extra database hops.
if generator.Wiping {
log.Info("Resuming previous snapshot wipe")
wiper = WipeSnapshot(diskdb, false)
}
// Whether or not wiping was in progress, load any generator progress too
snapshot.genMarker = generator.Marker
if snapshot.genMarker == nil {
snapshot.genMarker = []byte{}
}
}
// Everything loaded correctly, resume any suspended operations
// if the background generation is allowed
if !generator.Done && !noBuild {
snapshot.genPending = make(chan struct{})
snapshot.genAbort = make(chan chan struct{})
var origin uint64
if len(generator.Marker) >= 8 {
origin = binary.BigEndian.Uint64(generator.Marker)
}
go snapshot.generate(&generatorStats{
wiping: wiper,
origin: origin,
start: time.Now(),
accounts: generator.Accounts,
slots: generator.Slots,
storage: common.StorageSize(generator.Storage),
})
}
return snapshot, generator.Done, nil
}
// ResetSnapshotGeneration writes a clean snapshot generator marker to [db]
// so no re-generation is performed after.
func ResetSnapshotGeneration(db ethdb.KeyValueWriter) {
journalProgress(db, nil, nil)
}