github.com/annchain/OG@v0.0.9/arefactor_core/core/state/statedb_database.go (about) 1 // Copyright 2017 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 state 18 19 import ( 20 "fmt" 21 og_types "github.com/annchain/OG/arefactor/og_interface" 22 "sync" 23 24 "github.com/annchain/OG/ogdb" 25 "github.com/annchain/OG/trie" 26 27 lru "github.com/hashicorp/golang-lru" 28 ) 29 30 // MaxTrieCacheGen is trie cache generation limit after which to evict trie nodes from memory. 31 var MaxTrieCacheGen = uint16(120) 32 33 const ( 34 // Number of past tries to keep. This value is chosen such that 35 // reasonable chain reorg depths will hit an existing trie. 36 maxPastTries = 12 37 38 // Number of codehash->size associations to keep. 39 codeSizeCacheSize = 100000 40 ) 41 42 // Database wraps access to tries and contract code. 43 type Database interface { 44 // OpenTrie opens the main account trie. 45 OpenTrie(root og_types.Hash) (Trie, error) 46 47 // OpenStorageTrie opens the storage trie of an account. 48 OpenStorageTrie(addrHash, root og_types.Hash) (Trie, error) 49 50 // CopyTrie returns an independent copy of the given trie. 51 CopyTrie(Trie) Trie 52 53 // ContractCode retrieves a particular contract's code. 54 ContractCode(addrHash, codeHash og_types.Hash) ([]byte, error) 55 56 // ContractCodeSize retrieves a particular contracts code's size. 57 ContractCodeSize(addrHash, codeHash og_types.Hash) (int, error) 58 59 // TrieDB retrieves the low level trie database used for data storage. 60 TrieDB() *trie.Database 61 } 62 63 // Trie is a Ethereum Merkle Trie. 64 type Trie interface { 65 TryGet(key []byte) ([]byte, error) 66 TryUpdate(key, value []byte) error 67 TryDelete(key []byte) error 68 // preCommit is a flag for pre confirming sequencer. Because pre confirm uses the 69 // same trie db in real sequencer confirm and the db will be modified during db commit. 70 // To avoid this, add a flag to let pre confirm process not modify trie db anymore. 71 Commit(onleaf trie.LeafCallback, preCommit bool) (og_types.Hash, error) 72 Hash() og_types.Hash 73 NodeIterator(startKey []byte) trie.NodeIterator 74 GetKey([]byte) []byte // TODO(fjl): remove this when SecureTrie is removed 75 Prove(key []byte, fromLevel uint, proofDb ogdb.Putter) error 76 } 77 78 // NewDatabase creates a backing store for state. The returned database is safe for 79 // concurrent use and retains cached trie nodes in memory. The pool is an optional 80 // intermediate trie-node memory pool between the low level storage layer and the 81 // high level trie abstraction. 82 func NewDatabase(db ogdb.Database) Database { 83 csc, _ := lru.New(codeSizeCacheSize) 84 return &cachingDB{ 85 db: trie.NewDatabase(db), 86 codeSizeCache: csc, 87 } 88 } 89 90 type cachingDB struct { 91 db *trie.Database 92 mu sync.Mutex 93 pastTries []*trie.SecureTrie 94 codeSizeCache *lru.Cache 95 } 96 97 // OpenTrie opens the main account trie. 98 func (db *cachingDB) OpenTrie(root og_types.Hash) (Trie, error) { 99 db.mu.Lock() 100 defer db.mu.Unlock() 101 102 for i := len(db.pastTries) - 1; i >= 0; i-- { 103 if db.pastTries[i].Hash() == root { 104 return cachedTrie{db.pastTries[i].Copy(), db}, nil 105 } 106 } 107 tr, err := trie.NewSecure(root, db.db, MaxTrieCacheGen) 108 if err != nil { 109 return nil, err 110 } 111 return cachedTrie{tr, db}, nil 112 } 113 114 func (db *cachingDB) pushTrie(t *trie.SecureTrie) { 115 db.mu.Lock() 116 defer db.mu.Unlock() 117 118 if len(db.pastTries) >= maxPastTries { 119 copy(db.pastTries, db.pastTries[1:]) 120 db.pastTries[len(db.pastTries)-1] = t 121 } else { 122 db.pastTries = append(db.pastTries, t) 123 } 124 } 125 126 // OpenStorageTrie opens the storage trie of an account. 127 func (db *cachingDB) OpenStorageTrie(addrHash, root og_types.Hash) (Trie, error) { 128 return trie.NewSecure(root, db.db, 0) 129 } 130 131 // CopyTrie returns an independent copy of the given trie. 132 func (db *cachingDB) CopyTrie(t Trie) Trie { 133 switch t := t.(type) { 134 case cachedTrie: 135 return cachedTrie{t.SecureTrie.Copy(), db} 136 case *trie.SecureTrie: 137 return t.Copy() 138 default: 139 panic(fmt.Errorf("unknown trie type %T", t)) 140 } 141 } 142 143 // ContractCode retrieves a particular contract's code. 144 func (db *cachingDB) ContractCode(addrHash, codeHash og_types.Hash) ([]byte, error) { 145 code, err := db.db.Node(codeHash) 146 if err == nil { 147 db.codeSizeCache.Add(codeHash, len(code)) 148 } 149 return code, err 150 } 151 152 // ContractCodeSize retrieves a particular contracts code's size. 153 func (db *cachingDB) ContractCodeSize(addrHash, codeHash og_types.Hash) (int, error) { 154 if cached, ok := db.codeSizeCache.Get(codeHash); ok { 155 return cached.(int), nil 156 } 157 code, err := db.ContractCode(addrHash, codeHash) 158 return len(code), err 159 } 160 161 // TrieDB retrieves any intermediate trie-node caching layer. 162 func (db *cachingDB) TrieDB() *trie.Database { 163 return db.db 164 } 165 166 // cachedTrie inserts its trie into a cachingDB on commit. 167 type cachedTrie struct { 168 *trie.SecureTrie 169 db *cachingDB 170 } 171 172 func (m cachedTrie) Commit(onleaf trie.LeafCallback, preCommit bool) (og_types.Hash, error) { 173 root, err := m.SecureTrie.Commit(onleaf, preCommit) 174 if err == nil { 175 m.db.pushTrie(m.SecureTrie) 176 } 177 return root, err 178 } 179 180 func (m cachedTrie) Prove(key []byte, fromLevel uint, proofDb ogdb.Putter) error { 181 return m.SecureTrie.Prove(key, fromLevel, proofDb) 182 }