github.1485827954.workers.dev/ethereum/go-ethereum@v1.14.3/triedb/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 triedb 18 19 import ( 20 "errors" 21 22 "github.com/ethereum/go-ethereum/common" 23 "github.com/ethereum/go-ethereum/core/rawdb" 24 "github.com/ethereum/go-ethereum/ethdb" 25 "github.com/ethereum/go-ethereum/log" 26 "github.com/ethereum/go-ethereum/trie" 27 "github.com/ethereum/go-ethereum/trie/trienode" 28 "github.com/ethereum/go-ethereum/trie/triestate" 29 "github.com/ethereum/go-ethereum/triedb/database" 30 "github.com/ethereum/go-ethereum/triedb/hashdb" 31 "github.com/ethereum/go-ethereum/triedb/pathdb" 32 ) 33 34 // Config defines all necessary options for database. 35 type Config struct { 36 Preimages bool // Flag whether the preimage of node key is recorded 37 IsVerkle bool // Flag whether the db is holding a verkle tree 38 HashDB *hashdb.Config // Configs for hash-based scheme 39 PathDB *pathdb.Config // Configs for experimental path-based scheme 40 } 41 42 // HashDefaults represents a config for using hash-based scheme with 43 // default settings. 44 var HashDefaults = &Config{ 45 Preimages: false, 46 HashDB: hashdb.Defaults, 47 } 48 49 // backend defines the methods needed to access/update trie nodes in different 50 // state scheme. 51 type backend interface { 52 // Initialized returns an indicator if the state data is already initialized 53 // according to the state scheme. 54 Initialized(genesisRoot common.Hash) bool 55 56 // Size returns the current storage size of the diff layers on top of the 57 // disk layer and the storage size of the nodes cached in the disk layer. 58 // 59 // For hash scheme, there is no differentiation between diff layer nodes 60 // and dirty disk layer nodes, so both are merged into the second return. 61 Size() (common.StorageSize, common.StorageSize) 62 63 // Update performs a state transition by committing dirty nodes contained 64 // in the given set in order to update state from the specified parent to 65 // the specified root. 66 // 67 // The passed in maps(nodes, states) will be retained to avoid copying 68 // everything. Therefore, these maps must not be changed afterwards. 69 Update(root common.Hash, parent common.Hash, block uint64, nodes *trienode.MergedNodeSet, states *triestate.Set) error 70 71 // Commit writes all relevant trie nodes belonging to the specified state 72 // to disk. Report specifies whether logs will be displayed in info level. 73 Commit(root common.Hash, report bool) error 74 75 // Close closes the trie database backend and releases all held resources. 76 Close() error 77 } 78 79 // Database is the wrapper of the underlying backend which is shared by different 80 // types of node backend as an entrypoint. It's responsible for all interactions 81 // relevant with trie nodes and node preimages. 82 type Database struct { 83 config *Config // Configuration for trie database 84 diskdb ethdb.Database // Persistent database to store the snapshot 85 preimages *preimageStore // The store for caching preimages 86 backend backend // The backend for managing trie nodes 87 } 88 89 // NewDatabase initializes the trie database with default settings, note 90 // the legacy hash-based scheme is used by default. 91 func NewDatabase(diskdb ethdb.Database, config *Config) *Database { 92 // Sanitize the config and use the default one if it's not specified. 93 if config == nil { 94 config = HashDefaults 95 } 96 var preimages *preimageStore 97 if config.Preimages { 98 preimages = newPreimageStore(diskdb) 99 } 100 db := &Database{ 101 config: config, 102 diskdb: diskdb, 103 preimages: preimages, 104 } 105 if config.HashDB != nil && config.PathDB != nil { 106 log.Crit("Both 'hash' and 'path' mode are configured") 107 } 108 if config.PathDB != nil { 109 db.backend = pathdb.New(diskdb, config.PathDB, config.IsVerkle) 110 } else { 111 var resolver hashdb.ChildResolver 112 if config.IsVerkle { 113 // TODO define verkle resolver 114 log.Crit("verkle does not use a hash db") 115 } else { 116 resolver = trie.MerkleResolver{} 117 } 118 db.backend = hashdb.New(diskdb, config.HashDB, resolver) 119 } 120 return db 121 } 122 123 // Reader returns a reader for accessing all trie nodes with provided state root. 124 // An error will be returned if the requested state is not available. 125 func (db *Database) Reader(blockRoot common.Hash) (database.Reader, error) { 126 switch b := db.backend.(type) { 127 case *hashdb.Database: 128 return b.Reader(blockRoot) 129 case *pathdb.Database: 130 return b.Reader(blockRoot) 131 } 132 return nil, errors.New("unknown backend") 133 } 134 135 // Update performs a state transition by committing dirty nodes contained in the 136 // given set in order to update state from the specified parent to the specified 137 // root. The held pre-images accumulated up to this point will be flushed in case 138 // the size exceeds the threshold. 139 // 140 // The passed in maps(nodes, states) will be retained to avoid copying everything. 141 // Therefore, these maps must not be changed afterwards. 142 func (db *Database) Update(root common.Hash, parent common.Hash, block uint64, nodes *trienode.MergedNodeSet, states *triestate.Set) error { 143 if db.preimages != nil { 144 db.preimages.commit(false) 145 } 146 return db.backend.Update(root, parent, block, nodes, states) 147 } 148 149 // Commit iterates over all the children of a particular node, writes them out 150 // to disk. As a side effect, all pre-images accumulated up to this point are 151 // also written. 152 func (db *Database) Commit(root common.Hash, report bool) error { 153 if db.preimages != nil { 154 db.preimages.commit(true) 155 } 156 return db.backend.Commit(root, report) 157 } 158 159 // Size returns the storage size of diff layer nodes above the persistent disk 160 // layer, the dirty nodes buffered within the disk layer, and the size of cached 161 // preimages. 162 func (db *Database) Size() (common.StorageSize, common.StorageSize, common.StorageSize) { 163 var ( 164 diffs, nodes common.StorageSize 165 preimages common.StorageSize 166 ) 167 diffs, nodes = db.backend.Size() 168 if db.preimages != nil { 169 preimages = db.preimages.size() 170 } 171 return diffs, nodes, preimages 172 } 173 174 // Initialized returns an indicator if the state data is already initialized 175 // according to the state scheme. 176 func (db *Database) Initialized(genesisRoot common.Hash) bool { 177 return db.backend.Initialized(genesisRoot) 178 } 179 180 // Scheme returns the node scheme used in the database. 181 func (db *Database) Scheme() string { 182 if db.config.PathDB != nil { 183 return rawdb.PathScheme 184 } 185 return rawdb.HashScheme 186 } 187 188 // Close flushes the dangling preimages to disk and closes the trie database. 189 // It is meant to be called when closing the blockchain object, so that all 190 // resources held can be released correctly. 191 func (db *Database) Close() error { 192 db.WritePreimages() 193 return db.backend.Close() 194 } 195 196 // WritePreimages flushes all accumulated preimages to disk forcibly. 197 func (db *Database) WritePreimages() { 198 if db.preimages != nil { 199 db.preimages.commit(true) 200 } 201 } 202 203 // Preimage retrieves a cached trie node pre-image from preimage store. 204 func (db *Database) Preimage(hash common.Hash) []byte { 205 if db.preimages == nil { 206 return nil 207 } 208 return db.preimages.preimage(hash) 209 } 210 211 // InsertPreimage writes pre-images of trie node to the preimage store. 212 func (db *Database) InsertPreimage(preimages map[common.Hash][]byte) { 213 if db.preimages == nil { 214 return 215 } 216 db.preimages.insertPreimage(preimages) 217 } 218 219 // Cap iteratively flushes old but still referenced trie nodes until the total 220 // memory usage goes below the given threshold. The held pre-images accumulated 221 // up to this point will be flushed in case the size exceeds the threshold. 222 // 223 // It's only supported by hash-based database and will return an error for others. 224 func (db *Database) Cap(limit common.StorageSize) error { 225 hdb, ok := db.backend.(*hashdb.Database) 226 if !ok { 227 return errors.New("not supported") 228 } 229 if db.preimages != nil { 230 db.preimages.commit(false) 231 } 232 return hdb.Cap(limit) 233 } 234 235 // Reference adds a new reference from a parent node to a child node. This function 236 // is used to add reference between internal trie node and external node(e.g. storage 237 // trie root), all internal trie nodes are referenced together by database itself. 238 // 239 // It's only supported by hash-based database and will return an error for others. 240 func (db *Database) Reference(root common.Hash, parent common.Hash) error { 241 hdb, ok := db.backend.(*hashdb.Database) 242 if !ok { 243 return errors.New("not supported") 244 } 245 hdb.Reference(root, parent) 246 return nil 247 } 248 249 // Dereference removes an existing reference from a root node. It's only 250 // supported by hash-based database and will return an error for others. 251 func (db *Database) Dereference(root common.Hash) error { 252 hdb, ok := db.backend.(*hashdb.Database) 253 if !ok { 254 return errors.New("not supported") 255 } 256 hdb.Dereference(root) 257 return nil 258 } 259 260 // Recover rollbacks the database to a specified historical point. The state is 261 // supported as the rollback destination only if it's canonical state and the 262 // corresponding trie histories are existent. It's only supported by path-based 263 // database and will return an error for others. 264 func (db *Database) Recover(target common.Hash) error { 265 pdb, ok := db.backend.(*pathdb.Database) 266 if !ok { 267 return errors.New("not supported") 268 } 269 var loader triestate.TrieLoader 270 if db.config.IsVerkle { 271 // TODO define verkle loader 272 log.Crit("Verkle loader is not defined") 273 } else { 274 loader = trie.NewMerkleLoader(db) 275 } 276 return pdb.Recover(target, loader) 277 } 278 279 // Recoverable returns the indicator if the specified state is enabled to be 280 // recovered. It's only supported by path-based database and will return an 281 // error for others. 282 func (db *Database) Recoverable(root common.Hash) (bool, error) { 283 pdb, ok := db.backend.(*pathdb.Database) 284 if !ok { 285 return false, errors.New("not supported") 286 } 287 return pdb.Recoverable(root), nil 288 } 289 290 // Disable deactivates the database and invalidates all available state layers 291 // as stale to prevent access to the persistent state, which is in the syncing 292 // stage. 293 // 294 // It's only supported by path-based database and will return an error for others. 295 func (db *Database) Disable() error { 296 pdb, ok := db.backend.(*pathdb.Database) 297 if !ok { 298 return errors.New("not supported") 299 } 300 return pdb.Disable() 301 } 302 303 // Enable activates database and resets the state tree with the provided persistent 304 // state root once the state sync is finished. 305 func (db *Database) Enable(root common.Hash) error { 306 pdb, ok := db.backend.(*pathdb.Database) 307 if !ok { 308 return errors.New("not supported") 309 } 310 return pdb.Enable(root) 311 } 312 313 // Journal commits an entire diff hierarchy to disk into a single journal entry. 314 // This is meant to be used during shutdown to persist the snapshot without 315 // flattening everything down (bad for reorgs). It's only supported by path-based 316 // database and will return an error for others. 317 func (db *Database) Journal(root common.Hash) error { 318 pdb, ok := db.backend.(*pathdb.Database) 319 if !ok { 320 return errors.New("not supported") 321 } 322 return pdb.Journal(root) 323 } 324 325 // SetBufferSize sets the node buffer size to the provided value(in bytes). 326 // It's only supported by path-based database and will return an error for 327 // others. 328 func (db *Database) SetBufferSize(size int) error { 329 pdb, ok := db.backend.(*pathdb.Database) 330 if !ok { 331 return errors.New("not supported") 332 } 333 return pdb.SetBufferSize(size) 334 } 335 336 // IsVerkle returns the indicator if the database is holding a verkle tree. 337 func (db *Database) IsVerkle() bool { 338 return db.config.IsVerkle 339 }