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