github.com/theQRL/go-zond@v0.1.1/trie/database.go (about) 1 // Copyright 2022 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package trie 18 19 import ( 20 "errors" 21 22 "github.com/theQRL/go-zond/common" 23 "github.com/theQRL/go-zond/log" 24 "github.com/theQRL/go-zond/trie/triedb/hashdb" 25 "github.com/theQRL/go-zond/trie/triedb/pathdb" 26 "github.com/theQRL/go-zond/trie/trienode" 27 "github.com/theQRL/go-zond/trie/triestate" 28 "github.com/theQRL/go-zond/zonddb" 29 ) 30 31 // Config defines all necessary options for database. 32 type Config struct { 33 Preimages bool // Flag whether the preimage of node key is recorded 34 HashDB *hashdb.Config // Configs for hash-based scheme 35 PathDB *pathdb.Config // Configs for experimental path-based scheme 36 } 37 38 // HashDefaults represents a config for using hash-based scheme with 39 // default settings. 40 var HashDefaults = &Config{ 41 Preimages: false, 42 HashDB: hashdb.Defaults, 43 } 44 45 // backend defines the methods needed to access/update trie nodes in different 46 // state scheme. 47 type backend interface { 48 // Scheme returns the identifier of used storage scheme. 49 Scheme() string 50 51 // Initialized returns an indicator if the state data is already initialized 52 // according to the state scheme. 53 Initialized(genesisRoot common.Hash) bool 54 55 // Size returns the current storage size of the diff layers on top of the 56 // disk layer and the storage size of the nodes cached in the disk layer. 57 // 58 // For hash scheme, there is no differentiation between diff layer nodes 59 // and dirty disk layer nodes, so both are merged into the second return. 60 Size() (common.StorageSize, common.StorageSize) 61 62 // Update performs a state transition by committing dirty nodes contained 63 // in the given set in order to update state from the specified parent to 64 // the specified root. 65 // 66 // The passed in maps(nodes, states) will be retained to avoid copying 67 // everything. Therefore, these maps must not be changed afterwards. 68 Update(root common.Hash, parent common.Hash, block uint64, nodes *trienode.MergedNodeSet, states *triestate.Set) error 69 70 // Commit writes all relevant trie nodes belonging to the specified state 71 // to disk. Report specifies whether logs will be displayed in info level. 72 Commit(root common.Hash, report bool) error 73 74 // Close closes the trie database backend and releases all held resources. 75 Close() error 76 } 77 78 // Database is the wrapper of the underlying backend which is shared by different 79 // types of node backend as an entrypoint. It's responsible for all interactions 80 // relevant with trie nodes and node preimages. 81 type Database struct { 82 config *Config // Configuration for trie database 83 diskdb zonddb.Database // Persistent database to store the snapshot 84 preimages *preimageStore // The store for caching preimages 85 backend backend // The backend for managing trie nodes 86 } 87 88 // NewDatabase initializes the trie database with default settings, note 89 // the legacy hash-based scheme is used by default. 90 func NewDatabase(diskdb zonddb.Database, config *Config) *Database { 91 // Sanitize the config and use the default one if it's not specified. 92 if config == nil { 93 config = HashDefaults 94 } 95 var preimages *preimageStore 96 if config.Preimages { 97 preimages = newPreimageStore(diskdb) 98 } 99 db := &Database{ 100 config: config, 101 diskdb: diskdb, 102 preimages: preimages, 103 } 104 if config.HashDB != nil && config.PathDB != nil { 105 log.Crit("Both 'hash' and 'path' mode are configured") 106 } 107 if config.PathDB != nil { 108 db.backend = pathdb.New(diskdb, config.PathDB) 109 } else { 110 db.backend = hashdb.New(diskdb, config.HashDB, mptResolver{}) 111 } 112 return db 113 } 114 115 // Reader returns a reader for accessing all trie nodes with provided state root. 116 // An error will be returned if the requested state is not available. 117 func (db *Database) Reader(blockRoot common.Hash) (Reader, error) { 118 switch b := db.backend.(type) { 119 case *hashdb.Database: 120 return b.Reader(blockRoot) 121 case *pathdb.Database: 122 return b.Reader(blockRoot) 123 } 124 return nil, errors.New("unknown backend") 125 } 126 127 // Update performs a state transition by committing dirty nodes contained in the 128 // given set in order to update state from the specified parent to the specified 129 // root. The held pre-images accumulated up to this point will be flushed in case 130 // the size exceeds the threshold. 131 // 132 // The passed in maps(nodes, states) will be retained to avoid copying everything. 133 // Therefore, these maps must not be changed afterwards. 134 func (db *Database) Update(root common.Hash, parent common.Hash, block uint64, nodes *trienode.MergedNodeSet, states *triestate.Set) error { 135 if db.preimages != nil { 136 db.preimages.commit(false) 137 } 138 return db.backend.Update(root, parent, block, nodes, states) 139 } 140 141 // Commit iterates over all the children of a particular node, writes them out 142 // to disk. As a side effect, all pre-images accumulated up to this point are 143 // also written. 144 func (db *Database) Commit(root common.Hash, report bool) error { 145 if db.preimages != nil { 146 db.preimages.commit(true) 147 } 148 return db.backend.Commit(root, report) 149 } 150 151 // Size returns the storage size of diff layer nodes above the persistent disk 152 // layer, the dirty nodes buffered within the disk layer, and the size of cached 153 // preimages. 154 func (db *Database) Size() (common.StorageSize, common.StorageSize, common.StorageSize) { 155 var ( 156 diffs, nodes common.StorageSize 157 preimages common.StorageSize 158 ) 159 diffs, nodes = db.backend.Size() 160 if db.preimages != nil { 161 preimages = db.preimages.size() 162 } 163 return diffs, nodes, preimages 164 } 165 166 // Initialized returns an indicator if the state data is already initialized 167 // according to the state scheme. 168 func (db *Database) Initialized(genesisRoot common.Hash) bool { 169 return db.backend.Initialized(genesisRoot) 170 } 171 172 // Scheme returns the node scheme used in the database. 173 func (db *Database) Scheme() string { 174 return db.backend.Scheme() 175 } 176 177 // Close flushes the dangling preimages to disk and closes the trie database. 178 // It is meant to be called when closing the blockchain object, so that all 179 // resources held can be released correctly. 180 func (db *Database) Close() error { 181 db.WritePreimages() 182 return db.backend.Close() 183 } 184 185 // WritePreimages flushes all accumulated preimages to disk forcibly. 186 func (db *Database) WritePreimages() { 187 if db.preimages != nil { 188 db.preimages.commit(true) 189 } 190 } 191 192 // Cap iteratively flushes old but still referenced trie nodes until the total 193 // memory usage goes below the given threshold. The held pre-images accumulated 194 // up to this point will be flushed in case the size exceeds the threshold. 195 // 196 // It's only supported by hash-based database and will return an error for others. 197 func (db *Database) Cap(limit common.StorageSize) error { 198 hdb, ok := db.backend.(*hashdb.Database) 199 if !ok { 200 return errors.New("not supported") 201 } 202 if db.preimages != nil { 203 db.preimages.commit(false) 204 } 205 return hdb.Cap(limit) 206 } 207 208 // Reference adds a new reference from a parent node to a child node. This function 209 // is used to add reference between internal trie node and external node(e.g. storage 210 // trie root), all internal trie nodes are referenced together by database itself. 211 // 212 // It's only supported by hash-based database and will return an error for others. 213 func (db *Database) Reference(root common.Hash, parent common.Hash) error { 214 hdb, ok := db.backend.(*hashdb.Database) 215 if !ok { 216 return errors.New("not supported") 217 } 218 hdb.Reference(root, parent) 219 return nil 220 } 221 222 // Dereference removes an existing reference from a root node. It's only 223 // supported by hash-based database and will return an error for others. 224 func (db *Database) Dereference(root common.Hash) error { 225 hdb, ok := db.backend.(*hashdb.Database) 226 if !ok { 227 return errors.New("not supported") 228 } 229 hdb.Dereference(root) 230 return nil 231 } 232 233 // Node retrieves the rlp-encoded node blob with provided node hash. It's 234 // only supported by hash-based database and will return an error for others. 235 // Note, this function should be deprecated once ETH66 is deprecated. 236 func (db *Database) Node(hash common.Hash) ([]byte, error) { 237 hdb, ok := db.backend.(*hashdb.Database) 238 if !ok { 239 return nil, errors.New("not supported") 240 } 241 return hdb.Node(hash) 242 } 243 244 // Recover rollbacks the database to a specified historical point. The state is 245 // supported as the rollback destination only if it's canonical state and the 246 // corresponding trie histories are existent. It's only supported by path-based 247 // database and will return an error for others. 248 func (db *Database) Recover(target common.Hash) error { 249 pdb, ok := db.backend.(*pathdb.Database) 250 if !ok { 251 return errors.New("not supported") 252 } 253 return pdb.Recover(target, &trieLoader{db: db}) 254 } 255 256 // Recoverable returns the indicator if the specified state is enabled to be 257 // recovered. It's only supported by path-based database and will return an 258 // error for others. 259 func (db *Database) Recoverable(root common.Hash) (bool, error) { 260 pdb, ok := db.backend.(*pathdb.Database) 261 if !ok { 262 return false, errors.New("not supported") 263 } 264 return pdb.Recoverable(root), nil 265 } 266 267 // Reset wipes all available journal from the persistent database and discard 268 // all caches and diff layers. Using the given root to create a new disk layer. 269 // It's only supported by path-based database and will return an error for others. 270 func (db *Database) Reset(root common.Hash) error { 271 pdb, ok := db.backend.(*pathdb.Database) 272 if !ok { 273 return errors.New("not supported") 274 } 275 return pdb.Reset(root) 276 } 277 278 // Journal commits an entire diff hierarchy to disk into a single journal entry. 279 // This is meant to be used during shutdown to persist the snapshot without 280 // flattening everything down (bad for reorgs). It's only supported by path-based 281 // database and will return an error for others. 282 func (db *Database) Journal(root common.Hash) error { 283 pdb, ok := db.backend.(*pathdb.Database) 284 if !ok { 285 return errors.New("not supported") 286 } 287 return pdb.Journal(root) 288 } 289 290 // SetBufferSize sets the node buffer size to the provided value(in bytes). 291 // It's only supported by path-based database and will return an error for 292 // others. 293 func (db *Database) SetBufferSize(size int) error { 294 pdb, ok := db.backend.(*pathdb.Database) 295 if !ok { 296 return errors.New("not supported") 297 } 298 return pdb.SetBufferSize(size) 299 }