github.com/klaytn/klaytn@v1.12.1/storage/statedb/secure_trie.go (about) 1 // Modifications Copyright 2018 The klaytn Authors 2 // Copyright 2015 The go-ethereum Authors 3 // This file is part of the go-ethereum library. 4 // 5 // The go-ethereum library is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Lesser General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // The go-ethereum library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Lesser General Public License for more details. 14 // 15 // You should have received a copy of the GNU Lesser General Public License 16 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 17 // 18 // This file is derived from trie/secure_trie.go (2018/06/04). 19 // Modified and improved for the klaytn development. 20 21 package statedb 22 23 import ( 24 "github.com/klaytn/klaytn/common" 25 ) 26 27 // SecureTrie wraps a trie with key hashing. In a secure trie, all 28 // access operations hash the key using keccak256. This prevents 29 // calling code from creating long chains of nodes that 30 // increase the access time. 31 // 32 // Contrary to a regular trie, a SecureTrie can only be created with 33 // NewTrie and must have an attached database. The database also stores 34 // the preimage of each key. 35 // 36 // SecureTrie is not safe for concurrent use. 37 type SecureTrie struct { 38 trie Trie 39 hashKeyBuf [common.HashLength]byte 40 secKeyCache map[string][]byte 41 secKeyCacheOwner *SecureTrie // Pointer to self, replace the key cache on mismatch 42 } 43 44 // NewSecureTrie creates a trie with an existing root node from a backing database 45 // and optional intermediate in-memory node pool. 46 // 47 // If root is the zero hash or the sha3 hash of an empty string, the 48 // trie is initially empty. Otherwise, NewTrie will panic if db is nil 49 // and returns MissingNodeError if the root node cannot be found. 50 // 51 // Accessing the trie loads nodes from the database or node pool on demand. 52 // Loaded nodes are kept around until their 'cache generation' expires. 53 // A new cache generation is created by each call to Commit. 54 // cachelimit sets the number of past cache generations to keep. 55 func NewSecureTrie(root common.Hash, db *Database, opts *TrieOpts) (*SecureTrie, error) { 56 trie, err := NewTrie(root, db, opts) 57 if err != nil { 58 return nil, err 59 } 60 return &SecureTrie{trie: *trie}, nil 61 } 62 63 func NewSecureStorageTrie(root common.ExtHash, db *Database, opts *TrieOpts) (*SecureTrie, error) { 64 trie, err := NewStorageTrie(root, db, opts) 65 if err != nil { 66 return nil, err 67 } 68 return &SecureTrie{trie: *trie}, nil 69 } 70 71 // Get returns the value for key stored in the trie. 72 // The value bytes must not be modified by the caller. 73 func (t *SecureTrie) Get(key []byte) []byte { 74 res, err := t.TryGet(key) 75 if err != nil { 76 logger.Error("Unhandled trie error in SecureTrie.Get", "err", err) 77 } 78 return res 79 } 80 81 // TryGet returns the value for key stored in the trie. 82 // The value bytes must not be modified by the caller. 83 // If a node was not found in the database, a MissingNodeError is returned. 84 func (t *SecureTrie) TryGet(key []byte) ([]byte, error) { 85 return t.trie.TryGet(t.hashKey(key)) 86 } 87 88 // TryGetNode attempts to retrieve a trie node by compact-encoded path. It is not 89 // possible to use keybyte-encoding as the path might contain odd nibbles. 90 func (t *SecureTrie) TryGetNode(path []byte) ([]byte, int, error) { 91 return t.trie.TryGetNode(path) 92 } 93 94 // Update associates key with value in the trie. Subsequent calls to 95 // Get will return value. If value has length zero, any existing value 96 // is deleted from the trie and calls to Get will return nil. 97 // 98 // The value bytes must not be modified by the caller while they are 99 // stored in the trie. 100 func (t *SecureTrie) Update(key, value []byte) { 101 if err := t.TryUpdate(key, value); err != nil { 102 logger.Error("Unhandled trie error in SecureTrie.Update", "err", err) 103 } 104 } 105 106 // TryUpdate associates key with value in the trie. Subsequent calls to 107 // Get will return value. If value has length zero, any existing value 108 // is deleted from the trie and calls to Get will return nil. 109 // 110 // The value bytes must not be modified by the caller while they are 111 // stored in the trie. 112 // 113 // If a node was not found in the database, a MissingNodeError is returned. 114 func (t *SecureTrie) TryUpdate(key, value []byte) error { 115 hk := t.hashKey(key) 116 err := t.trie.TryUpdate(hk, value) 117 if err != nil { 118 return err 119 } 120 t.getSecKeyCache()[string(hk)] = common.CopyBytes(key) 121 return nil 122 } 123 124 // TryUpdateWithKeys does basically same thing that TryUpdate does. 125 // Only difference is that it uses pre-encoded hashKey and hexKey. 126 func (t *SecureTrie) TryUpdateWithKeys(key, hashKey, hexKey, value []byte) error { 127 err := t.trie.TryUpdateWithHexKey(hexKey, value) 128 if err != nil { 129 return err 130 } 131 t.getSecKeyCache()[string(hashKey)] = common.CopyBytes(key) 132 return nil 133 } 134 135 // Delete removes any existing value for key from the trie. 136 func (t *SecureTrie) Delete(key []byte) { 137 if err := t.TryDelete(key); err != nil { 138 logger.Error("Unhandled trie error in SecureTrie.Delete", "err", err) 139 } 140 } 141 142 // TryDelete removes any existing value for key from the trie. 143 // If a node was not found in the database, a MissingNodeError is returned. 144 func (t *SecureTrie) TryDelete(key []byte) error { 145 hk := t.hashKey(key) 146 delete(t.getSecKeyCache(), string(hk)) 147 return t.trie.TryDelete(hk) 148 } 149 150 // GetKey returns the sha3 preimage of a hashed key that was 151 // previously used to store a value. 152 func (t *SecureTrie) GetKey(shaKey []byte) []byte { 153 if key, ok := t.getSecKeyCache()[string(shaKey)]; ok { 154 return key 155 } 156 key := t.trie.db.preimage(common.BytesToHash(shaKey)) 157 return key 158 } 159 160 // Commit writes all nodes and the secure hash pre-images to the trie's database. 161 // Nodes are stored with their sha3 hash as the key. 162 // 163 // Committing flushes nodes from memory. Subsequent Get calls will load nodes 164 // from the database. 165 func (t *SecureTrie) Commit(onleaf LeafCallback) (root common.Hash, err error) { 166 // Commit the trie to its intermediate node database 167 t.commitPreimages() 168 return t.trie.Commit(onleaf) 169 } 170 171 // CommitExt writes all nodes and the secure hash pre-images to the trie's database. 172 // Nodes are stored with their extended sha3 hash as the key. 173 // 174 // Committing flushes nodes from memory. Subsequent Get calls will load nodes 175 // from the database. 176 func (t *SecureTrie) CommitExt(onleaf LeafCallback) (root common.ExtHash, err error) { 177 // Commit the trie to its intermediate node database 178 t.commitPreimages() 179 return t.trie.CommitExt(onleaf) 180 } 181 182 // commitPreimages writes all the pre-images to the actual disk database 183 func (t *SecureTrie) commitPreimages() { 184 if len(t.getSecKeyCache()) > 0 { 185 t.trie.db.lock.Lock() 186 for hk, key := range t.secKeyCache { 187 t.trie.db.insertPreimage(common.BytesToHash([]byte(hk)), key) 188 } 189 t.trie.db.lock.Unlock() 190 191 t.secKeyCache = make(map[string][]byte) 192 } 193 } 194 195 func (t *SecureTrie) Hash() common.Hash { 196 return t.trie.Hash() 197 } 198 199 func (t *SecureTrie) HashExt() common.ExtHash { 200 return t.trie.HashExt() 201 } 202 203 func (t *SecureTrie) Copy() *SecureTrie { 204 cpy := *t 205 return &cpy 206 } 207 208 // NodeIterator returns an iterator that returns nodes of the underlying trie. Iteration 209 // starts at the key after the given start key. 210 func (t *SecureTrie) NodeIterator(start []byte) NodeIterator { 211 return t.trie.NodeIterator(start) 212 } 213 214 // hashKey returns the hash of key as an ephemeral buffer. 215 // The caller must not hold onto the return value because it will become 216 // invalid on the next call to hashKey or secKey. 217 func (t *SecureTrie) hashKey(key []byte) []byte { 218 h := newHasher(nil) 219 h.sha.Reset() 220 h.sha.Write(key) 221 buf := h.sha.Sum(t.hashKeyBuf[:0]) 222 returnHasherToPool(h) 223 return buf 224 } 225 226 // getSecKeyCache returns the current secure key cache, creating a new one if 227 // ownership changed (i.e. the current secure trie is a copy of another owning 228 // the actual cache). 229 func (t *SecureTrie) getSecKeyCache() map[string][]byte { 230 if t != t.secKeyCacheOwner { 231 t.secKeyCacheOwner = t 232 t.secKeyCache = make(map[string][]byte) 233 } 234 return t.secKeyCache 235 }