github.com/klaytn/klaytn@v1.10.2/blockchain/state/database.go (about) 1 // Modifications Copyright 2018 The klaytn Authors 2 // Copyright 2017 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 core/state/database.go (2018/06/04). 19 // Modified and improved for the klaytn development. 20 21 package state 22 23 import ( 24 "errors" 25 "fmt" 26 27 "github.com/VictoriaMetrics/fastcache" 28 "github.com/klaytn/klaytn/common" 29 "github.com/klaytn/klaytn/storage/database" 30 "github.com/klaytn/klaytn/storage/statedb" 31 ) 32 33 const ( 34 // Number of codehash->size associations to keep 35 codeSizeCacheSize = 100000 36 37 // Cache size granted for caching clean code. 38 codeCacheSize = 64 * 1024 * 1024 39 40 // Number of shards in cache 41 shardsCodeSizeCache = 4096 42 ) 43 44 // Database wraps access to tries and contract code. 45 type Database interface { 46 // OpenTrie opens the main account trie. 47 OpenTrie(root common.Hash) (Trie, error) 48 OpenTrieForPrefetching(root common.Hash) (Trie, error) 49 50 // OpenStorageTrie opens the storage trie of an account. 51 OpenStorageTrie(root common.Hash) (Trie, error) 52 OpenStorageTrieForPrefetching(root common.Hash) (Trie, error) 53 54 // CopyTrie returns an independent copy of the given trie. 55 CopyTrie(Trie) Trie 56 57 // ContractCode retrieves a particular contract's code. 58 ContractCode(codeHash common.Hash) ([]byte, error) 59 60 // DeleteCode deletes a particular contract's code. 61 DeleteCode(codeHash common.Hash) 62 63 // ContractCodeSize retrieves a particular contracts code's size. 64 ContractCodeSize(codeHash common.Hash) (int, error) 65 66 // TrieDB retrieves the low level trie database used for data storage. 67 TrieDB() *statedb.Database 68 69 // RLockGCCachedNode locks the GC lock of CachedNode. 70 RLockGCCachedNode() 71 72 // RUnlockGCCachedNode unlocks the GC lock of CachedNode. 73 RUnlockGCCachedNode() 74 } 75 76 // Trie is a Klaytn Merkle Patricia trie. 77 type Trie interface { 78 // GetKey returns the sha3 preimage of a hashed key that was previously used 79 // to store a value. 80 // 81 // TODO(fjl): remove this when SecureTrie is removed 82 GetKey([]byte) []byte 83 // TryGet returns the value for key stored in the trie. The value bytes must 84 // not be modified by the caller. If a node was not found in the database, a 85 // trie.MissingNodeError is returned. 86 TryGet(key []byte) ([]byte, error) 87 // TryUpdate associates key with value in the trie. If value has length zero, any 88 // existing value is deleted from the trie. The value bytes must not be modified 89 // by the caller while they are stored in the trie. If a node was not found in the 90 // database, a trie.MissingNodeError is returned. 91 TryUpdate(key, value []byte) error 92 TryUpdateWithKeys(key, hashKey, hexKey, value []byte) error 93 // TryDelete removes any existing value for key from the trie. If a node was not 94 // found in the database, a trie.MissingNodeError is returned. 95 TryDelete(key []byte) error 96 // Hash returns the root hash of the trie. It does not write to the database and 97 // can be used even if the trie doesn't have one. 98 Hash() common.Hash 99 // Commit writes all nodes to the trie's memory database, tracking the internal 100 // and external (for account tries) references. 101 Commit(onleaf statedb.LeafCallback) (common.Hash, error) 102 // NodeIterator returns an iterator that returns nodes of the trie. Iteration 103 // starts at the key after the given start key. 104 NodeIterator(startKey []byte) statedb.NodeIterator 105 // Prove constructs a Merkle proof for key. The result contains all encoded nodes 106 // on the path to the value at key. The value itself is also included in the last 107 // node and can be retrieved by verifying the proof. 108 // 109 // If the trie does not contain a value for key, the returned proof contains all 110 // nodes of the longest existing prefix of the key (at least the root), ending 111 // with the node that proves the absence of the key. 112 Prove(key []byte, fromLevel uint, proofDb database.DBManager) error 113 } 114 115 // NewDatabase creates a backing store for state. The returned database is safe for 116 // concurrent use, but does not retain any recent trie nodes in memory. To keep some 117 // historical state in memory, use the NewDatabaseWithNewCache constructor. 118 func NewDatabase(db database.DBManager) Database { 119 return NewDatabaseWithNewCache(db, statedb.GetEmptyTrieNodeCacheConfig()) 120 } 121 122 func getCodeSizeCache() common.Cache { 123 var cacheConfig common.CacheConfiger 124 switch common.DefaultCacheType { 125 case common.LRUShardCacheType: 126 cacheConfig = common.LRUShardConfig{CacheSize: codeSizeCacheSize, NumShards: shardsCodeSizeCache} 127 case common.LRUCacheType: 128 cacheConfig = common.LRUConfig{CacheSize: codeSizeCacheSize} 129 case common.FIFOCacheType: 130 cacheConfig = common.FIFOCacheConfig{CacheSize: codeSizeCacheSize} 131 default: 132 cacheConfig = common.FIFOCacheConfig{CacheSize: codeSizeCacheSize} 133 } 134 135 return common.NewCache(cacheConfig) 136 } 137 138 // NewDatabaseWithNewCache creates a backing store for state. The returned database 139 // is safe for concurrent use and retains a lot of collapsed RLP trie nodes in a 140 // large memory cache. 141 func NewDatabaseWithNewCache(db database.DBManager, cacheConfig *statedb.TrieNodeCacheConfig) Database { 142 return &cachingDB{ 143 db: statedb.NewDatabaseWithNewCache(db, cacheConfig), 144 codeSizeCache: getCodeSizeCache(), 145 codeCache: fastcache.New(codeCacheSize), 146 } 147 } 148 149 // NewDatabaseWithExistingCache creates a backing store for state with given cache. The returned database 150 // is safe for concurrent use and retains a lot of collapsed RLP trie nodes in a 151 // large memory cache. 152 func NewDatabaseWithExistingCache(db database.DBManager, cache statedb.TrieNodeCache) Database { 153 return &cachingDB{ 154 db: statedb.NewDatabaseWithExistingCache(db, cache), 155 codeSizeCache: getCodeSizeCache(), 156 codeCache: fastcache.New(codeCacheSize), 157 } 158 } 159 160 type cachingDB struct { 161 db *statedb.Database 162 codeSizeCache common.Cache 163 codeCache *fastcache.Cache 164 } 165 166 // OpenTrie opens the main account trie at a specific root hash. 167 func (db *cachingDB) OpenTrie(root common.Hash) (Trie, error) { 168 return statedb.NewSecureTrie(root, db.db) 169 } 170 171 // OpenTrieForPrefetching opens the main account trie at a specific root hash. 172 func (db *cachingDB) OpenTrieForPrefetching(root common.Hash) (Trie, error) { 173 return statedb.NewSecureTrieForPrefetching(root, db.db) 174 } 175 176 // OpenStorageTrie opens the storage trie of an account. 177 func (db *cachingDB) OpenStorageTrie(root common.Hash) (Trie, error) { 178 return statedb.NewSecureTrie(root, db.db) 179 } 180 181 // OpenStorageTrieForPrefetching opens the storage trie of an account. 182 func (db *cachingDB) OpenStorageTrieForPrefetching(root common.Hash) (Trie, error) { 183 return statedb.NewSecureTrieForPrefetching(root, db.db) 184 } 185 186 // CopyTrie returns an independent copy of the given trie. 187 func (db *cachingDB) CopyTrie(t Trie) Trie { 188 switch t := t.(type) { 189 case *statedb.SecureTrie: 190 return t.Copy() 191 default: 192 panic(fmt.Errorf("unknown trie type %T", t)) 193 } 194 } 195 196 // ContractCode retrieves a particular contract's code. 197 func (db *cachingDB) ContractCode(codeHash common.Hash) ([]byte, error) { 198 if code := db.codeCache.Get(nil, codeHash.Bytes()); len(code) > 0 { 199 return code, nil 200 } 201 code := db.db.DiskDB().ReadCode(codeHash) 202 if len(code) > 0 { 203 db.codeCache.Set(codeHash.Bytes(), code) 204 db.codeSizeCache.Add(codeHash, len(code)) 205 return code, nil 206 } 207 return nil, errors.New("not found") 208 } 209 210 // DeleteCode deletes a particular contract's code. 211 func (db *cachingDB) DeleteCode(codeHash common.Hash) { 212 db.codeCache.Del(codeHash.Bytes()) 213 db.db.DiskDB().DeleteCode(codeHash) 214 } 215 216 // ContractCodeWithPrefix retrieves a particular contract's code. If the 217 // code can't be found in the cache, then check the existence with **new** 218 // db scheme. 219 func (db *cachingDB) ContractCodeWithPrefix(codeHash common.Hash) ([]byte, error) { 220 if code := db.codeCache.Get(nil, codeHash.Bytes()); len(code) > 0 { 221 return code, nil 222 } 223 code := db.db.DiskDB().ReadCodeWithPrefix(codeHash) 224 if len(code) > 0 { 225 db.codeCache.Set(codeHash.Bytes(), code) 226 db.codeSizeCache.Add(codeHash, len(code)) 227 return code, nil 228 } 229 return nil, errors.New("not found") 230 } 231 232 // ContractCodeSize retrieves a particular contracts code's size. 233 func (db *cachingDB) ContractCodeSize(codeHash common.Hash) (int, error) { 234 if cached, ok := db.codeSizeCache.Get(codeHash); ok { 235 return cached.(int), nil 236 } 237 code, err := db.ContractCode(codeHash) 238 return len(code), err 239 } 240 241 // TrieDB retrieves the low level trie database used for data storage. 242 func (db *cachingDB) TrieDB() *statedb.Database { 243 return db.db 244 } 245 246 // RLockGCCachedNode locks the GC lock of CachedNode. 247 func (db *cachingDB) RLockGCCachedNode() { 248 db.db.RLockGCCachedNode() 249 } 250 251 // RUnlockGCCachedNode unlocks the GC lock of CachedNode. 252 func (db *cachingDB) RUnlockGCCachedNode() { 253 db.db.RUnlockGCCachedNode() 254 }