github.com/MetalBlockchain/subnet-evm@v0.4.9/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/MetalBlockchain/subnet-evm/core/rawdb" 36 "github.com/MetalBlockchain/subnet-evm/ethdb" 37 "github.com/MetalBlockchain/subnet-evm/trie" 38 "github.com/ethereum/go-ethereum/common" 39 "github.com/ethereum/go-ethereum/log" 40 "github.com/ethereum/go-ethereum/rlp" 41 ) 42 43 // journalGenerator is a disk layer entry containing the generator progress marker. 44 type journalGenerator struct { 45 // Indicator that whether the database was in progress of being wiped. 46 // It's deprecated but keep it here for background compatibility. 47 Wiping bool 48 49 Done bool // Whether the generator finished creating the snapshot 50 Marker []byte 51 Accounts uint64 52 Slots uint64 53 Storage uint64 54 } 55 56 // loadSnapshot loads a pre-existing state snapshot backed by a key-value 57 // store. If loading the snapshot from disk is successful, this function also 58 // returns a boolean indicating whether or not the snapshot is fully generated. 59 func loadSnapshot(diskdb ethdb.KeyValueStore, triedb *trie.Database, cache int, blockHash, root common.Hash) (snapshot, bool, error) { 60 // Retrieve the block number and hash of the snapshot, failing if no snapshot 61 // is present in the database (or crashed mid-update). 62 baseBlockHash := rawdb.ReadSnapshotBlockHash(diskdb) 63 if baseBlockHash == (common.Hash{}) { 64 return nil, false, fmt.Errorf("missing or corrupted snapshot, no snapshot block hash") 65 } 66 if baseBlockHash != blockHash { 67 return nil, false, fmt.Errorf("block hash stored on disk (%#x) does not match last accepted (%#x)", baseBlockHash, blockHash) 68 } 69 baseRoot := rawdb.ReadSnapshotRoot(diskdb) 70 if baseRoot == (common.Hash{}) { 71 return nil, false, errors.New("missing or corrupted snapshot, no snapshot root") 72 } 73 if baseRoot != root { 74 return nil, false, fmt.Errorf("root stored on disk (%#x) does not match last accepted (%#x)", baseRoot, root) 75 } 76 77 // Retrieve the disk layer generator. It must exist, no matter the 78 // snapshot is fully generated or not. Otherwise the entire disk 79 // layer is invalid. 80 generatorBlob := rawdb.ReadSnapshotGenerator(diskdb) 81 if len(generatorBlob) == 0 { 82 return nil, false, errors.New("missing snapshot generator") 83 } 84 var generator journalGenerator 85 if err := rlp.DecodeBytes(generatorBlob, &generator); err != nil { 86 return nil, false, fmt.Errorf("failed to decode snapshot generator: %v", err) 87 } 88 89 // Instantiate snapshot as disk layer with last recorded block hash and root 90 snapshot := &diskLayer{ 91 diskdb: diskdb, 92 triedb: triedb, 93 cache: newMeteredSnapshotCache(cache * 1024 * 1024), 94 root: baseRoot, 95 blockHash: baseBlockHash, 96 created: time.Now(), 97 } 98 99 // Everything loaded correctly, resume any suspended operations 100 if !generator.Done { 101 // If the generator was still wiping, restart one from scratch (fine for 102 // now as it's rare and the wiper deletes the stuff it touches anyway, so 103 // restarting won't incur a lot of extra database hops. 104 var wiper chan struct{} 105 if generator.Wiping { 106 log.Info("Resuming previous snapshot wipe") 107 wiper = WipeSnapshot(diskdb, false) 108 } 109 // Whether or not wiping was in progress, load any generator progress too 110 snapshot.genMarker = generator.Marker 111 if snapshot.genMarker == nil { 112 snapshot.genMarker = []byte{} 113 } 114 snapshot.genPending = make(chan struct{}) 115 snapshot.genAbort = make(chan chan struct{}) 116 117 var origin uint64 118 if len(generator.Marker) >= 8 { 119 origin = binary.BigEndian.Uint64(generator.Marker) 120 } 121 go snapshot.generate(&generatorStats{ 122 wiping: wiper, 123 origin: origin, 124 start: time.Now(), 125 accounts: generator.Accounts, 126 slots: generator.Slots, 127 storage: common.StorageSize(generator.Storage), 128 }) 129 } 130 131 return snapshot, generator.Done, nil 132 } 133 134 // ResetSnapshotGeneration writes a clean snapshot generator marker to [db] 135 // so no re-generation is performed after. 136 func ResetSnapshotGeneration(db ethdb.KeyValueWriter) { 137 journalProgress(db, nil, nil) 138 }