mirror of
https://github.com/fluencelabs/tendermint
synced 2025-07-06 16:11:40 +00:00
add dirty bit to BlockCache accounts and storages.
construct account’s storage lazily.
This commit is contained in:
@ -1,6 +1,7 @@
|
|||||||
package state
|
package state
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
ac "github.com/tendermint/tendermint/account"
|
ac "github.com/tendermint/tendermint/account"
|
||||||
@ -25,7 +26,7 @@ type BlockCache struct {
|
|||||||
db dbm.DB
|
db dbm.DB
|
||||||
backend *State
|
backend *State
|
||||||
accounts map[string]accountInfo
|
accounts map[string]accountInfo
|
||||||
storages map[Tuple256]Word256
|
storages map[Tuple256]storageInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewBlockCache(backend *State) *BlockCache {
|
func NewBlockCache(backend *State) *BlockCache {
|
||||||
@ -33,7 +34,7 @@ func NewBlockCache(backend *State) *BlockCache {
|
|||||||
db: backend.DB,
|
db: backend.DB,
|
||||||
backend: backend,
|
backend: backend,
|
||||||
accounts: make(map[string]accountInfo),
|
accounts: make(map[string]accountInfo),
|
||||||
storages: make(map[Tuple256]Word256),
|
storages: make(map[Tuple256]storageInfo),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,15 +46,14 @@ func (cache *BlockCache) State() *State {
|
|||||||
// BlockCache.account
|
// BlockCache.account
|
||||||
|
|
||||||
func (cache *BlockCache) GetAccount(addr []byte) *ac.Account {
|
func (cache *BlockCache) GetAccount(addr []byte) *ac.Account {
|
||||||
acc, storage, removed := unpack(cache.accounts[string(addr)])
|
acc, _, removed, _ := cache.accounts[string(addr)].unpack()
|
||||||
if removed {
|
if removed {
|
||||||
return nil
|
return nil
|
||||||
} else if acc != nil {
|
} else if acc != nil {
|
||||||
return acc
|
return acc
|
||||||
} else {
|
} else {
|
||||||
acc = cache.backend.GetAccount(addr)
|
acc = cache.backend.GetAccount(addr)
|
||||||
storage = makeStorage(cache.db, acc.StorageRoot)
|
cache.accounts[string(addr)] = accountInfo{acc, nil, false, false}
|
||||||
cache.accounts[string(addr)] = accountInfo{acc, storage, false}
|
|
||||||
return acc
|
return acc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -61,22 +61,22 @@ func (cache *BlockCache) GetAccount(addr []byte) *ac.Account {
|
|||||||
func (cache *BlockCache) UpdateAccount(acc *ac.Account) {
|
func (cache *BlockCache) UpdateAccount(acc *ac.Account) {
|
||||||
addr := acc.Address
|
addr := acc.Address
|
||||||
// SANITY CHECK
|
// SANITY CHECK
|
||||||
_, storage, removed := unpack(cache.accounts[string(addr)])
|
_, storage, removed, _ := cache.accounts[string(addr)].unpack()
|
||||||
if removed {
|
if removed {
|
||||||
panic("UpdateAccount on a removed account")
|
panic("UpdateAccount on a removed account")
|
||||||
}
|
}
|
||||||
// SANITY CHECK END
|
// SANITY CHECK END
|
||||||
cache.accounts[string(addr)] = accountInfo{acc, storage, false}
|
cache.accounts[string(addr)] = accountInfo{acc, storage, false, true}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cache *BlockCache) RemoveAccount(addr []byte) {
|
func (cache *BlockCache) RemoveAccount(addr []byte) {
|
||||||
// SANITY CHECK
|
// SANITY CHECK
|
||||||
_, _, removed := unpack(cache.accounts[string(addr)])
|
_, _, removed, _ := cache.accounts[string(addr)].unpack()
|
||||||
if removed {
|
if removed {
|
||||||
panic("RemoveAccount on a removed account")
|
panic("RemoveAccount on a removed account")
|
||||||
}
|
}
|
||||||
// SANITY CHECK END
|
// SANITY CHECK END
|
||||||
cache.accounts[string(addr)] = accountInfo{nil, nil, true}
|
cache.accounts[string(addr)] = accountInfo{nil, nil, true, false}
|
||||||
}
|
}
|
||||||
|
|
||||||
// BlockCache.account
|
// BlockCache.account
|
||||||
@ -85,16 +85,20 @@ func (cache *BlockCache) RemoveAccount(addr []byte) {
|
|||||||
|
|
||||||
func (cache *BlockCache) GetStorage(addr Word256, key Word256) (value Word256) {
|
func (cache *BlockCache) GetStorage(addr Word256, key Word256) (value Word256) {
|
||||||
// Check cache
|
// Check cache
|
||||||
value, ok := cache.storages[Tuple256{addr, key}]
|
info, ok := cache.storages[Tuple256{addr, key}]
|
||||||
if ok {
|
if ok {
|
||||||
return value
|
return info.value
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get or load storage
|
// Get or load storage
|
||||||
_, storage, removed := unpack(cache.accounts[string(addr.Prefix(20))])
|
acc, storage, removed, dirty := cache.accounts[string(addr.Prefix(20))].unpack()
|
||||||
if removed {
|
if removed {
|
||||||
panic("GetStorage() on removed account")
|
panic("GetStorage() on removed account")
|
||||||
}
|
}
|
||||||
|
if storage == nil {
|
||||||
|
storage = makeStorage(cache.db, acc.StorageRoot)
|
||||||
|
cache.accounts[string(addr.Prefix(20))] = accountInfo{acc, storage, false, dirty}
|
||||||
|
}
|
||||||
|
|
||||||
// Load and set cache
|
// Load and set cache
|
||||||
_, val_ := storage.Get(key.Bytes())
|
_, val_ := storage.Get(key.Bytes())
|
||||||
@ -102,17 +106,17 @@ func (cache *BlockCache) GetStorage(addr Word256, key Word256) (value Word256) {
|
|||||||
if val_ != nil {
|
if val_ != nil {
|
||||||
value = RightPadWord256(val_.([]byte))
|
value = RightPadWord256(val_.([]byte))
|
||||||
}
|
}
|
||||||
cache.storages[Tuple256{addr, key}] = value
|
cache.storages[Tuple256{addr, key}] = storageInfo{value, false}
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: Set value to zero to removed from the trie.
|
// NOTE: Set value to zero to removed from the trie.
|
||||||
func (cache *BlockCache) SetStorage(addr Word256, key Word256, value Word256) {
|
func (cache *BlockCache) SetStorage(addr Word256, key Word256, value Word256) {
|
||||||
_, _, removed := unpack(cache.accounts[string(addr.Prefix(20))])
|
_, _, removed, _ := cache.accounts[string(addr.Prefix(20))].unpack()
|
||||||
if removed {
|
if removed {
|
||||||
panic("SetStorage() on a removed account")
|
panic("SetStorage() on a removed account")
|
||||||
}
|
}
|
||||||
cache.storages[Tuple256{addr, key}] = value
|
cache.storages[Tuple256{addr, key}] = storageInfo{value, true}
|
||||||
}
|
}
|
||||||
|
|
||||||
// BlockCache.storage
|
// BlockCache.storage
|
||||||
@ -140,7 +144,7 @@ func (cache *BlockCache) Sync() {
|
|||||||
for _, storageKey := range storageKeys {
|
for _, storageKey := range storageKeys {
|
||||||
addr, key := Tuple256Split(storageKey)
|
addr, key := Tuple256Split(storageKey)
|
||||||
if addr != curAddr || curAcc == nil {
|
if addr != curAddr || curAcc == nil {
|
||||||
acc, storage, removed := unpack(cache.accounts[string(addr.Prefix(20))])
|
acc, storage, removed, _ := cache.accounts[string(addr.Prefix(20))].unpack()
|
||||||
curAddr = addr
|
curAddr = addr
|
||||||
curAcc = acc
|
curAcc = acc
|
||||||
curAccRemoved = removed
|
curAccRemoved = removed
|
||||||
@ -149,7 +153,10 @@ func (cache *BlockCache) Sync() {
|
|||||||
if curAccRemoved {
|
if curAccRemoved {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
value := cache.storages[storageKey]
|
value, dirty := cache.storages[storageKey].unpack()
|
||||||
|
if !dirty {
|
||||||
|
continue
|
||||||
|
}
|
||||||
if value.IsZero() {
|
if value.IsZero() {
|
||||||
curStorage.Remove(key.Bytes())
|
curStorage.Remove(key.Bytes())
|
||||||
} else {
|
} else {
|
||||||
@ -166,7 +173,7 @@ func (cache *BlockCache) Sync() {
|
|||||||
|
|
||||||
// Update or delete accounts.
|
// Update or delete accounts.
|
||||||
for _, addrStr := range addrStrs {
|
for _, addrStr := range addrStrs {
|
||||||
acc, storage, removed := unpack(cache.accounts[addrStr])
|
acc, storage, removed, dirty := cache.accounts[addrStr].unpack()
|
||||||
if removed {
|
if removed {
|
||||||
removed := cache.backend.RemoveAccount(acc.Address)
|
removed := cache.backend.RemoveAccount(acc.Address)
|
||||||
if !removed {
|
if !removed {
|
||||||
@ -176,8 +183,16 @@ func (cache *BlockCache) Sync() {
|
|||||||
if acc == nil {
|
if acc == nil {
|
||||||
panic(Fmt("Account should not be nil for addr: %X", acc.Address))
|
panic(Fmt("Account should not be nil for addr: %X", acc.Address))
|
||||||
}
|
}
|
||||||
acc.StorageRoot = storage.Save()
|
if storage != nil {
|
||||||
cache.backend.UpdateAccount(acc)
|
newStorageRoot := storage.Save()
|
||||||
|
if !bytes.Equal(newStorageRoot, acc.StorageRoot) {
|
||||||
|
acc.StorageRoot = newStorageRoot
|
||||||
|
dirty = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if dirty {
|
||||||
|
cache.backend.UpdateAccount(acc)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -189,8 +204,18 @@ type accountInfo struct {
|
|||||||
account *ac.Account
|
account *ac.Account
|
||||||
storage merkle.Tree
|
storage merkle.Tree
|
||||||
removed bool
|
removed bool
|
||||||
|
dirty bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func unpack(accInfo accountInfo) (*ac.Account, merkle.Tree, bool) {
|
func (accInfo accountInfo) unpack() (*ac.Account, merkle.Tree, bool, bool) {
|
||||||
return accInfo.account, accInfo.storage, accInfo.removed
|
return accInfo.account, accInfo.storage, accInfo.removed, accInfo.dirty
|
||||||
|
}
|
||||||
|
|
||||||
|
type storageInfo struct {
|
||||||
|
value Word256
|
||||||
|
dirty bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (stjInfo storageInfo) unpack() (Word256, bool) {
|
||||||
|
return stjInfo.value, stjInfo.dirty
|
||||||
}
|
}
|
||||||
|
@ -94,10 +94,8 @@ func (cache *TxCache) GetStorage(addr Word256, key Word256) Word256 {
|
|||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load and set cache
|
// Load from backend
|
||||||
value = cache.backend.GetStorage(addr, key)
|
return cache.backend.GetStorage(addr, key)
|
||||||
cache.storages[Tuple256{addr, key}] = value
|
|
||||||
return value
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: Set value to zero to removed from the trie.
|
// NOTE: Set value to zero to removed from the trie.
|
||||||
|
Reference in New Issue
Block a user