github.com/aergoio/aergo@v1.3.1/state/storage.go (about) 1 package state 2 3 import ( 4 "bytes" 5 "sync" 6 7 "github.com/aergoio/aergo-lib/db" 8 "github.com/aergoio/aergo/internal/common" 9 "github.com/aergoio/aergo/internal/enc" 10 "github.com/aergoio/aergo/pkg/trie" 11 "github.com/aergoio/aergo/types" 12 ) 13 14 var ( 15 checkpointKey = types.ToHashID([]byte("checkpoint")) 16 ) 17 18 type storageCache struct { 19 lock sync.RWMutex 20 storages map[types.AccountID]*bufferedStorage 21 } 22 23 func newStorageCache() *storageCache { 24 return &storageCache{ 25 storages: map[types.AccountID]*bufferedStorage{}, 26 } 27 } 28 29 func (cache *storageCache) get(key types.AccountID) *bufferedStorage { 30 cache.lock.RLock() 31 defer cache.lock.RUnlock() 32 if storage, ok := cache.storages[key]; ok && storage != nil { 33 return storage 34 } 35 return nil 36 } 37 func (cache *storageCache) put(key types.AccountID, storage *bufferedStorage) { 38 cache.lock.Lock() 39 defer cache.lock.Unlock() 40 cache.storages[key] = storage 41 } 42 43 type bufferedStorage struct { 44 buffer *stateBuffer 45 trie *trie.Trie 46 dirty bool 47 } 48 49 func newBufferedStorage(root []byte, store db.DB) *bufferedStorage { 50 return &bufferedStorage{ 51 buffer: newStateBuffer(), 52 trie: trie.NewTrie(root, common.Hasher, store), 53 dirty: false, 54 } 55 } 56 57 func (storage *bufferedStorage) has(key types.HashID, lookupTrie bool) bool { 58 if storage.buffer.has(key) { 59 return true 60 } 61 if lookupTrie { 62 if buf, _ := storage.trie.Get(key.Bytes()); buf != nil { 63 return true 64 } 65 } 66 return false 67 } 68 func (storage *bufferedStorage) get(key types.HashID) entry { 69 return storage.buffer.get(key) 70 } 71 func (storage *bufferedStorage) put(et entry) { 72 storage.buffer.put(et) 73 } 74 75 func (storage *bufferedStorage) checkpoint(revision int) { 76 storage.buffer.put(newMetaEntry(checkpointKey, revision)) 77 } 78 79 func (storage *bufferedStorage) rollback(revision int) { 80 checkpoints, ok := storage.buffer.indexes[checkpointKey] 81 if !ok { 82 // do nothing 83 return 84 } 85 it := checkpoints.iter() 86 for rev := it(); rev >= 0; rev = it() { 87 et := storage.buffer.entries[rev] 88 if et == nil { 89 continue 90 } 91 me, ok := et.(*metaEntry) 92 if !ok { 93 continue 94 } 95 val, ok := me.Value().(int) 96 if !ok { 97 continue 98 } 99 if val < revision { 100 break 101 } 102 storage.buffer.rollback(rev) 103 } 104 } 105 106 func (storage *bufferedStorage) update() error { 107 before := storage.trie.Root 108 if err := storage.buffer.updateTrie(storage.trie); err != nil { 109 return err 110 } 111 if !bytes.Equal(before, storage.trie.Root) { 112 logger.Debug().Str("before", enc.ToString(before)). 113 Str("after", enc.ToString(storage.trie.Root)).Msg("Changed storage trie root") 114 storage.dirty = true 115 } 116 return nil 117 } 118 119 func (storage *bufferedStorage) isDirty() bool { 120 return storage.dirty 121 } 122 123 func (storage *bufferedStorage) stage(txn trie.DbTx) error { 124 storage.trie.StageUpdates(txn) 125 if err := storage.buffer.stage(txn); err != nil { 126 return err 127 } 128 if err := storage.buffer.reset(); err != nil { 129 return err 130 } 131 return nil 132 }