github.com/theQRL/go-zond@v0.1.1/core/rawdb/accessors_trie.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 rawdb 18 19 import ( 20 "fmt" 21 "sync" 22 23 "github.com/theQRL/go-zond/common" 24 "github.com/theQRL/go-zond/crypto" 25 "github.com/theQRL/go-zond/log" 26 "github.com/theQRL/go-zond/zonddb" 27 "golang.org/x/crypto/sha3" 28 ) 29 30 // HashScheme is the legacy hash-based state scheme with which trie nodes are 31 // stored in the disk with node hash as the database key. The advantage of this 32 // scheme is that different versions of trie nodes can be stored in disk, which 33 // is very beneficial for constructing archive nodes. The drawback is it will 34 // store different trie nodes on the same path to different locations on the disk 35 // with no data locality, and it's unfriendly for designing state pruning. 36 // 37 // Now this scheme is still kept for backward compatibility, and it will be used 38 // for archive node and some other tries(e.g. light trie). 39 const HashScheme = "hash" 40 41 // PathScheme is the new path-based state scheme with which trie nodes are stored 42 // in the disk with node path as the database key. This scheme will only store one 43 // version of state data in the disk, which means that the state pruning operation 44 // is native. At the same time, this scheme will put adjacent trie nodes in the same 45 // area of the disk with good data locality property. But this scheme needs to rely 46 // on extra state diffs to survive deep reorg. 47 const PathScheme = "path" 48 49 // hasher is used to compute the sha256 hash of the provided data. 50 type hasher struct{ sha crypto.KeccakState } 51 52 var hasherPool = sync.Pool{ 53 New: func() interface{} { return &hasher{sha: sha3.NewLegacyKeccak256().(crypto.KeccakState)} }, 54 } 55 56 func newHasher() *hasher { 57 return hasherPool.Get().(*hasher) 58 } 59 60 func (h *hasher) hash(data []byte) common.Hash { 61 return crypto.HashData(h.sha, data) 62 } 63 64 func (h *hasher) release() { 65 hasherPool.Put(h) 66 } 67 68 // ReadAccountTrieNode retrieves the account trie node and the associated node 69 // hash with the specified node path. 70 func ReadAccountTrieNode(db zonddb.KeyValueReader, path []byte) ([]byte, common.Hash) { 71 data, err := db.Get(accountTrieNodeKey(path)) 72 if err != nil { 73 return nil, common.Hash{} 74 } 75 h := newHasher() 76 defer h.release() 77 return data, h.hash(data) 78 } 79 80 // HasAccountTrieNode checks the account trie node presence with the specified 81 // node path and the associated node hash. 82 func HasAccountTrieNode(db zonddb.KeyValueReader, path []byte, hash common.Hash) bool { 83 data, err := db.Get(accountTrieNodeKey(path)) 84 if err != nil { 85 return false 86 } 87 h := newHasher() 88 defer h.release() 89 return h.hash(data) == hash 90 } 91 92 // WriteAccountTrieNode writes the provided account trie node into database. 93 func WriteAccountTrieNode(db zonddb.KeyValueWriter, path []byte, node []byte) { 94 if err := db.Put(accountTrieNodeKey(path), node); err != nil { 95 log.Crit("Failed to store account trie node", "err", err) 96 } 97 } 98 99 // DeleteAccountTrieNode deletes the specified account trie node from the database. 100 func DeleteAccountTrieNode(db zonddb.KeyValueWriter, path []byte) { 101 if err := db.Delete(accountTrieNodeKey(path)); err != nil { 102 log.Crit("Failed to delete account trie node", "err", err) 103 } 104 } 105 106 // ReadStorageTrieNode retrieves the storage trie node and the associated node 107 // hash with the specified node path. 108 func ReadStorageTrieNode(db zonddb.KeyValueReader, accountHash common.Hash, path []byte) ([]byte, common.Hash) { 109 data, err := db.Get(storageTrieNodeKey(accountHash, path)) 110 if err != nil { 111 return nil, common.Hash{} 112 } 113 h := newHasher() 114 defer h.release() 115 return data, h.hash(data) 116 } 117 118 // HasStorageTrieNode checks the storage trie node presence with the provided 119 // node path and the associated node hash. 120 func HasStorageTrieNode(db zonddb.KeyValueReader, accountHash common.Hash, path []byte, hash common.Hash) bool { 121 data, err := db.Get(storageTrieNodeKey(accountHash, path)) 122 if err != nil { 123 return false 124 } 125 h := newHasher() 126 defer h.release() 127 return h.hash(data) == hash 128 } 129 130 // WriteStorageTrieNode writes the provided storage trie node into database. 131 func WriteStorageTrieNode(db zonddb.KeyValueWriter, accountHash common.Hash, path []byte, node []byte) { 132 if err := db.Put(storageTrieNodeKey(accountHash, path), node); err != nil { 133 log.Crit("Failed to store storage trie node", "err", err) 134 } 135 } 136 137 // DeleteStorageTrieNode deletes the specified storage trie node from the database. 138 func DeleteStorageTrieNode(db zonddb.KeyValueWriter, accountHash common.Hash, path []byte) { 139 if err := db.Delete(storageTrieNodeKey(accountHash, path)); err != nil { 140 log.Crit("Failed to delete storage trie node", "err", err) 141 } 142 } 143 144 // ReadLegacyTrieNode retrieves the legacy trie node with the given 145 // associated node hash. 146 func ReadLegacyTrieNode(db zonddb.KeyValueReader, hash common.Hash) []byte { 147 data, err := db.Get(hash.Bytes()) 148 if err != nil { 149 return nil 150 } 151 return data 152 } 153 154 // HasLegacyTrieNode checks if the trie node with the provided hash is present in db. 155 func HasLegacyTrieNode(db zonddb.KeyValueReader, hash common.Hash) bool { 156 ok, _ := db.Has(hash.Bytes()) 157 return ok 158 } 159 160 // WriteLegacyTrieNode writes the provided legacy trie node to database. 161 func WriteLegacyTrieNode(db zonddb.KeyValueWriter, hash common.Hash, node []byte) { 162 if err := db.Put(hash.Bytes(), node); err != nil { 163 log.Crit("Failed to store legacy trie node", "err", err) 164 } 165 } 166 167 // DeleteLegacyTrieNode deletes the specified legacy trie node from database. 168 func DeleteLegacyTrieNode(db zonddb.KeyValueWriter, hash common.Hash) { 169 if err := db.Delete(hash.Bytes()); err != nil { 170 log.Crit("Failed to delete legacy trie node", "err", err) 171 } 172 } 173 174 // HasTrieNode checks the trie node presence with the provided node info and 175 // the associated node hash. 176 func HasTrieNode(db zonddb.KeyValueReader, owner common.Hash, path []byte, hash common.Hash, scheme string) bool { 177 switch scheme { 178 case HashScheme: 179 return HasLegacyTrieNode(db, hash) 180 case PathScheme: 181 if owner == (common.Hash{}) { 182 return HasAccountTrieNode(db, path, hash) 183 } 184 return HasStorageTrieNode(db, owner, path, hash) 185 default: 186 panic(fmt.Sprintf("Unknown scheme %v", scheme)) 187 } 188 } 189 190 // ReadTrieNode retrieves the trie node from database with the provided node info 191 // and associated node hash. 192 // hashScheme-based lookup requires the following: 193 // - hash 194 // 195 // pathScheme-based lookup requires the following: 196 // - owner 197 // - path 198 func ReadTrieNode(db zonddb.KeyValueReader, owner common.Hash, path []byte, hash common.Hash, scheme string) []byte { 199 switch scheme { 200 case HashScheme: 201 return ReadLegacyTrieNode(db, hash) 202 case PathScheme: 203 var ( 204 blob []byte 205 nHash common.Hash 206 ) 207 if owner == (common.Hash{}) { 208 blob, nHash = ReadAccountTrieNode(db, path) 209 } else { 210 blob, nHash = ReadStorageTrieNode(db, owner, path) 211 } 212 if nHash != hash { 213 return nil 214 } 215 return blob 216 default: 217 panic(fmt.Sprintf("Unknown scheme %v", scheme)) 218 } 219 } 220 221 // WriteTrieNode writes the trie node into database with the provided node info 222 // and associated node hash. 223 // hashScheme-based lookup requires the following: 224 // - hash 225 // 226 // pathScheme-based lookup requires the following: 227 // - owner 228 // - path 229 func WriteTrieNode(db zonddb.KeyValueWriter, owner common.Hash, path []byte, hash common.Hash, node []byte, scheme string) { 230 switch scheme { 231 case HashScheme: 232 WriteLegacyTrieNode(db, hash, node) 233 case PathScheme: 234 if owner == (common.Hash{}) { 235 WriteAccountTrieNode(db, path, node) 236 } else { 237 WriteStorageTrieNode(db, owner, path, node) 238 } 239 default: 240 panic(fmt.Sprintf("Unknown scheme %v", scheme)) 241 } 242 } 243 244 // DeleteTrieNode deletes the trie node from database with the provided node info 245 // and associated node hash. 246 // hashScheme-based lookup requires the following: 247 // - hash 248 // 249 // pathScheme-based lookup requires the following: 250 // - owner 251 // - path 252 func DeleteTrieNode(db zonddb.KeyValueWriter, owner common.Hash, path []byte, hash common.Hash, scheme string) { 253 switch scheme { 254 case HashScheme: 255 DeleteLegacyTrieNode(db, hash) 256 case PathScheme: 257 if owner == (common.Hash{}) { 258 DeleteAccountTrieNode(db, path) 259 } else { 260 DeleteStorageTrieNode(db, owner, path) 261 } 262 default: 263 panic(fmt.Sprintf("Unknown scheme %v", scheme)) 264 } 265 } 266 267 // ReadStateScheme reads the state scheme of persistent state, or none 268 // if the state is not present in database. 269 func ReadStateScheme(db zonddb.Reader) string { 270 // Check if state in path-based scheme is present 271 blob, _ := ReadAccountTrieNode(db, nil) 272 if len(blob) != 0 { 273 return PathScheme 274 } 275 // In a hash-based scheme, the genesis state is consistently stored 276 // on the disk. To assess the scheme of the persistent state, it 277 // suffices to inspect the scheme of the genesis state. 278 header := ReadHeader(db, ReadCanonicalHash(db, 0), 0) 279 if header == nil { 280 return "" // empty datadir 281 } 282 blob = ReadLegacyTrieNode(db, header.Root) 283 if len(blob) == 0 { 284 return "" // no state in disk 285 } 286 return HashScheme 287 }