github.com/klaytn/klaytn@v1.12.1/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, opts *statedb.TrieOpts) (Trie, error) 48 49 // OpenStorageTrie opens the storage trie of an account. 50 OpenStorageTrie(root common.ExtHash, opts *statedb.TrieOpts) (Trie, error) 51 52 // CopyTrie returns an independent copy of the given trie. 53 CopyTrie(Trie) Trie 54 55 // ContractCode retrieves a particular contract's code. 56 ContractCode(codeHash common.Hash) ([]byte, error) 57 58 // DeleteCode deletes a particular contract's code. 59 DeleteCode(codeHash common.Hash) 60 61 // ContractCodeSize retrieves a particular contracts code's size. 62 ContractCodeSize(codeHash common.Hash) (int, error) 63 64 // TrieDB retrieves the low level trie database used for data storage. 65 TrieDB() *statedb.Database 66 67 // RLockGCCachedNode locks the GC lock of CachedNode. 68 RLockGCCachedNode() 69 70 // RUnlockGCCachedNode unlocks the GC lock of CachedNode. 71 RUnlockGCCachedNode() 72 } 73 74 // Trie is a Klaytn Merkle Patricia trie. 75 type Trie interface { 76 // GetKey returns the sha3 preimage of a hashed key that was previously used 77 // to store a value. 78 // 79 // TODO(fjl): remove this when SecureTrie is removed 80 GetKey([]byte) []byte 81 // TryGet returns the value for key stored in the trie. The value bytes must 82 // not be modified by the caller. If a node was not found in the database, a 83 // trie.MissingNodeError is returned. 84 TryGet(key []byte) ([]byte, error) 85 // TryUpdate associates key with value in the trie. If value has length zero, any 86 // existing value is deleted from the trie. The value bytes must not be modified 87 // by the caller while they are stored in the trie. If a node was not found in the 88 // database, a trie.MissingNodeError is returned. 89 TryUpdate(key, value []byte) error 90 TryUpdateWithKeys(key, hashKey, hexKey, value []byte) error 91 // TryDelete removes any existing value for key from the trie. If a node was not 92 // found in the database, a trie.MissingNodeError is returned. 93 TryDelete(key []byte) error 94 // Hash returns the root hash of the trie. It does not write to the database and 95 // can be used even if the trie doesn't have one. 96 Hash() common.Hash 97 HashExt() common.ExtHash 98 // Commit writes all nodes to the trie's memory database, tracking the internal 99 // and external (for account tries) references. 100 Commit(onleaf statedb.LeafCallback) (common.Hash, error) 101 CommitExt(onleaf statedb.LeafCallback) (common.ExtHash, 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, opts *statedb.TrieOpts) (Trie, error) { 168 return statedb.NewSecureTrie(root, db.db, opts) 169 } 170 171 // OpenStorageTrie opens the storage trie of an account. 172 func (db *cachingDB) OpenStorageTrie(root common.ExtHash, opts *statedb.TrieOpts) (Trie, error) { 173 return statedb.NewSecureStorageTrie(root, db.db, opts) 174 } 175 176 // CopyTrie returns an independent copy of the given trie. 177 func (db *cachingDB) CopyTrie(t Trie) Trie { 178 switch t := t.(type) { 179 case *statedb.SecureTrie: 180 return t.Copy() 181 default: 182 panic(fmt.Errorf("unknown trie type %T", t)) 183 } 184 } 185 186 // ContractCode retrieves a particular contract's code. 187 func (db *cachingDB) ContractCode(codeHash common.Hash) ([]byte, error) { 188 if code := db.codeCache.Get(nil, codeHash.Bytes()); len(code) > 0 { 189 return code, nil 190 } 191 code := db.db.DiskDB().ReadCode(codeHash) 192 if len(code) > 0 { 193 db.codeCache.Set(codeHash.Bytes(), code) 194 db.codeSizeCache.Add(codeHash, len(code)) 195 return code, nil 196 } 197 return nil, errors.New("not found") 198 } 199 200 // DeleteCode deletes a particular contract's code. 201 func (db *cachingDB) DeleteCode(codeHash common.Hash) { 202 db.codeCache.Del(codeHash.Bytes()) 203 db.db.DiskDB().DeleteCode(codeHash) 204 } 205 206 // ContractCodeWithPrefix retrieves a particular contract's code. If the 207 // code can't be found in the cache, then check the existence with **new** 208 // db scheme. 209 func (db *cachingDB) ContractCodeWithPrefix(codeHash common.Hash) ([]byte, error) { 210 if code := db.codeCache.Get(nil, codeHash.Bytes()); len(code) > 0 { 211 return code, nil 212 } 213 code := db.db.DiskDB().ReadCodeWithPrefix(codeHash) 214 if len(code) > 0 { 215 db.codeCache.Set(codeHash.Bytes(), code) 216 db.codeSizeCache.Add(codeHash, len(code)) 217 return code, nil 218 } 219 return nil, errors.New("not found") 220 } 221 222 // ContractCodeSize retrieves a particular contracts code's size. 223 func (db *cachingDB) ContractCodeSize(codeHash common.Hash) (int, error) { 224 if cached, ok := db.codeSizeCache.Get(codeHash); ok { 225 return cached.(int), nil 226 } 227 code, err := db.ContractCode(codeHash) 228 return len(code), err 229 } 230 231 // TrieDB retrieves the low level trie database used for data storage. 232 func (db *cachingDB) TrieDB() *statedb.Database { 233 return db.db 234 } 235 236 // RLockGCCachedNode locks the GC lock of CachedNode. 237 func (db *cachingDB) RLockGCCachedNode() { 238 db.db.RLockGCCachedNode() 239 } 240 241 // RUnlockGCCachedNode unlocks the GC lock of CachedNode. 242 func (db *cachingDB) RUnlockGCCachedNode() { 243 db.db.RUnlockGCCachedNode() 244 }