github.com/iotexproject/iotex-core@v1.14.1-rc1/state/factory/workingsetstore.go (about) 1 // Copyright (c) 2022 IoTeX Foundation 2 // This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability 3 // or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed. 4 // This source code is governed by Apache License 2.0 that can be found in the LICENSE file. 5 6 package factory 7 8 import ( 9 "context" 10 "fmt" 11 12 "github.com/iotexproject/go-pkgs/hash" 13 "go.uber.org/zap" 14 15 "github.com/pkg/errors" 16 17 "github.com/iotexproject/iotex-core/action/protocol" 18 "github.com/iotexproject/iotex-core/db" 19 "github.com/iotexproject/iotex-core/db/trie" 20 "github.com/iotexproject/iotex-core/db/trie/mptrie" 21 "github.com/iotexproject/iotex-core/pkg/log" 22 "github.com/iotexproject/iotex-core/pkg/util/byteutil" 23 "github.com/iotexproject/iotex-core/state" 24 ) 25 26 type ( 27 workingSetStore interface { 28 db.KVStoreBasic 29 Commit() error 30 States(string, [][]byte) ([][]byte, error) 31 Digest() hash.Hash256 32 Finalize(uint64) error 33 Snapshot() int 34 RevertSnapshot(int) error 35 ResetSnapshots() 36 ReadView(string) (interface{}, error) 37 WriteView(string, interface{}) error 38 } 39 stateDBWorkingSetStore struct { 40 view protocol.View 41 flusher db.KVStoreFlusher 42 readBuffer bool 43 } 44 factoryWorkingSetStore struct { 45 view protocol.View 46 flusher db.KVStoreFlusher 47 tlt trie.TwoLayerTrie 48 trieRoots map[int][]byte 49 } 50 ) 51 52 func newStateDBWorkingSetStore(view protocol.View, flusher db.KVStoreFlusher, readBuffer bool) workingSetStore { 53 return &stateDBWorkingSetStore{ 54 flusher: flusher, 55 view: view, 56 readBuffer: readBuffer, 57 } 58 } 59 60 func newFactoryWorkingSetStore(view protocol.View, flusher db.KVStoreFlusher) (workingSetStore, error) { 61 tlt, err := newTwoLayerTrie(ArchiveTrieNamespace, flusher.KVStoreWithBuffer(), ArchiveTrieRootKey, true) 62 if err != nil { 63 return nil, err 64 } 65 66 return &factoryWorkingSetStore{ 67 flusher: flusher, 68 view: view, 69 tlt: tlt, 70 trieRoots: make(map[int][]byte), 71 }, nil 72 } 73 74 func (store *stateDBWorkingSetStore) Start(context.Context) error { 75 return nil 76 } 77 78 func (store *stateDBWorkingSetStore) Stop(context.Context) error { 79 return nil 80 } 81 82 func (store *stateDBWorkingSetStore) ReadView(name string) (interface{}, error) { 83 return store.view.Read(name) 84 } 85 86 func (store *stateDBWorkingSetStore) WriteView(name string, value interface{}) error { 87 return store.view.Write(name, value) 88 } 89 90 func (store *stateDBWorkingSetStore) Get(ns string, key []byte) ([]byte, error) { 91 data, err := store.flusher.KVStoreWithBuffer().Get(ns, key) 92 if err != nil { 93 if errors.Cause(err) == db.ErrNotExist { 94 return nil, errors.Wrapf(state.ErrStateNotExist, "failed to get state of ns = %x and key = %x", ns, key) 95 } 96 return nil, err 97 } 98 return data, nil 99 } 100 101 func (store *stateDBWorkingSetStore) Put(ns string, key []byte, value []byte) error { 102 store.flusher.KVStoreWithBuffer().MustPut(ns, key, value) 103 return nil 104 } 105 106 func (store *stateDBWorkingSetStore) Delete(ns string, key []byte) error { 107 store.flusher.KVStoreWithBuffer().MustDelete(ns, key) 108 return nil 109 } 110 111 func (store *stateDBWorkingSetStore) States(ns string, keys [][]byte) ([][]byte, error) { 112 if store.readBuffer { 113 return readStates(store.flusher.KVStoreWithBuffer(), ns, keys) 114 } 115 return readStates(store.flusher.BaseKVStore(), ns, keys) 116 } 117 118 func (store *stateDBWorkingSetStore) Digest() hash.Hash256 { 119 return hash.Hash256b(store.flusher.SerializeQueue()) 120 } 121 122 func (store *stateDBWorkingSetStore) Finalize(height uint64) error { 123 // Persist current chain Height 124 store.flusher.KVStoreWithBuffer().MustPut( 125 AccountKVNamespace, 126 []byte(CurrentHeightKey), 127 byteutil.Uint64ToBytes(height), 128 ) 129 return nil 130 } 131 132 func (store *stateDBWorkingSetStore) Commit() error { 133 return store.flusher.Flush() 134 } 135 136 func (store *stateDBWorkingSetStore) Snapshot() int { 137 return store.flusher.KVStoreWithBuffer().Snapshot() 138 } 139 140 func (store *stateDBWorkingSetStore) RevertSnapshot(snapshot int) error { 141 return store.flusher.KVStoreWithBuffer().RevertSnapshot(snapshot) 142 } 143 144 func (store *stateDBWorkingSetStore) ResetSnapshots() { 145 store.flusher.KVStoreWithBuffer().ResetSnapshots() 146 } 147 148 func (store *factoryWorkingSetStore) Start(ctx context.Context) error { 149 return store.tlt.Start(ctx) 150 } 151 152 func (store *factoryWorkingSetStore) Stop(ctx context.Context) error { 153 return store.tlt.Stop(ctx) 154 } 155 156 func (store *factoryWorkingSetStore) ReadView(name string) (interface{}, error) { 157 return store.view.Read(name) 158 } 159 160 func (store *factoryWorkingSetStore) WriteView(name string, value interface{}) error { 161 return store.view.Write(name, value) 162 } 163 164 func (store *factoryWorkingSetStore) Get(ns string, key []byte) ([]byte, error) { 165 return readState(store.tlt, ns, key) 166 } 167 168 func (store *factoryWorkingSetStore) Put(ns string, key []byte, value []byte) error { 169 store.flusher.KVStoreWithBuffer().MustPut(ns, key, value) 170 nsHash := hash.Hash160b([]byte(ns)) 171 172 return store.tlt.Upsert(nsHash[:], toLegacyKey(key), value) 173 } 174 175 func (store *factoryWorkingSetStore) Delete(ns string, key []byte) error { 176 store.flusher.KVStoreWithBuffer().MustDelete(ns, key) 177 nsHash := hash.Hash160b([]byte(ns)) 178 179 err := store.tlt.Delete(nsHash[:], toLegacyKey(key)) 180 if errors.Cause(err) == trie.ErrNotExist { 181 return errors.Wrapf(state.ErrStateNotExist, "key %x doesn't exist in namespace %x", key, nsHash) 182 } 183 return err 184 } 185 186 func (store *factoryWorkingSetStore) States(ns string, keys [][]byte) ([][]byte, error) { 187 values := [][]byte{} 188 if keys == nil { 189 iter, err := mptrie.NewLayerTwoLeafIterator(store.tlt, namespaceKey(ns), legacyKeyLen()) 190 if err != nil { 191 return nil, err 192 } 193 for { 194 _, value, err := iter.Next() 195 if err == trie.ErrEndOfIterator { 196 break 197 } 198 if err != nil { 199 return nil, err 200 } 201 values = append(values, value) 202 } 203 } else { 204 for _, key := range keys { 205 value, err := readState(store.tlt, ns, key) 206 switch errors.Cause(err) { 207 case state.ErrStateNotExist: 208 values = append(values, nil) 209 case nil: 210 values = append(values, value) 211 default: 212 return nil, err 213 } 214 } 215 } 216 return values, nil 217 } 218 func (store *factoryWorkingSetStore) Digest() hash.Hash256 { 219 return hash.Hash256b(store.flusher.SerializeQueue()) 220 } 221 222 func (store *factoryWorkingSetStore) Finalize(h uint64) error { 223 rootHash, err := store.tlt.RootHash() 224 if err != nil { 225 return err 226 } 227 store.flusher.KVStoreWithBuffer().MustPut(AccountKVNamespace, []byte(CurrentHeightKey), byteutil.Uint64ToBytes(h)) 228 store.flusher.KVStoreWithBuffer().MustPut(ArchiveTrieNamespace, []byte(ArchiveTrieRootKey), rootHash) 229 // Persist the historical accountTrie's root hash 230 store.flusher.KVStoreWithBuffer().MustPut( 231 ArchiveTrieNamespace, 232 []byte(fmt.Sprintf("%s-%d", ArchiveTrieRootKey, h)), 233 rootHash, 234 ) 235 return nil 236 } 237 238 func (store *factoryWorkingSetStore) Commit() error { 239 _dbBatchSizelMtc.WithLabelValues().Set(float64(store.flusher.KVStoreWithBuffer().Size())) 240 return store.flusher.Flush() 241 } 242 243 func (store *factoryWorkingSetStore) Snapshot() int { 244 rh, err := store.tlt.RootHash() 245 if err != nil { 246 log.L().Panic("failed to do snapshot", zap.Error(err)) 247 } 248 s := store.flusher.KVStoreWithBuffer().Snapshot() 249 store.trieRoots[s] = rh 250 return s 251 } 252 253 func (store *factoryWorkingSetStore) RevertSnapshot(snapshot int) error { 254 if err := store.flusher.KVStoreWithBuffer().RevertSnapshot(snapshot); err != nil { 255 return err 256 } 257 root, ok := store.trieRoots[snapshot] 258 if !ok { 259 // this should not happen, b/c we save the trie root on a successful return of Snapshot(), but check anyway 260 return errors.Wrapf(trie.ErrInvalidTrie, "failed to get trie root for snapshot = %d", snapshot) 261 } 262 return store.tlt.SetRootHash(root[:]) 263 } 264 265 func (store *factoryWorkingSetStore) ResetSnapshots() { 266 store.flusher.KVStoreWithBuffer().ResetSnapshots() 267 store.trieRoots = make(map[int][]byte) 268 }