Skip to content

Commit

Permalink
Merge pull request #472 from qianbin/storage-barrier
Browse files Browse the repository at this point in the history
Storage barrier
  • Loading branch information
libotony authored Jul 14, 2021
2 parents 322e356 + 93468d8 commit 8eff2b2
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 6 deletions.
41 changes: 35 additions & 6 deletions state/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,12 @@ func (s *State) cacheGetter(key interface{}) (value interface{}, exist bool, err
}
return code, true, nil
case storageKey: // get storage
// the address was ever deleted in the life-cycle of this state instance.
// treat its storage as an empty set.
if k.barrier != 0 {
return rlp.RawValue(nil), true, nil
}

obj, err := s.getCachedObject(k.addr)
if err != nil {
return nil, false, err
Expand All @@ -96,6 +102,8 @@ func (s *State) cacheGetter(key interface{}) (value interface{}, exist bool, err
return nil, false, err
}
return v, true, nil
case storageBarrierKey: // get barrier, 0 as initial value
return 0, true, nil
}
panic(fmt.Errorf("unexpected key type %+v", key))
}
Expand Down Expand Up @@ -135,6 +143,15 @@ func (s *State) updateAccount(addr thor.Address, acc *Account) {
s.sm.Put(addr, acc)
}

func (s *State) getStorageBarrier(addr thor.Address) int {
b, _, _ := s.sm.Get(storageBarrierKey(addr))
return b.(int)
}

func (s *State) setStorageBarrier(addr thor.Address, barrier int) {
s.sm.Put(storageBarrierKey(addr), barrier)
}

// GetBalance returns balance for the given address.
func (s *State) GetBalance(addr thor.Address) (*big.Int, error) {
acc, err := s.getAccount(addr)
Expand Down Expand Up @@ -233,7 +250,7 @@ func (s *State) SetStorage(addr thor.Address, key, value thor.Bytes32) {

// GetRawStorage returns storage value in rlp raw for given address and key.
func (s *State) GetRawStorage(addr thor.Address, key thor.Bytes32) (rlp.RawValue, error) {
data, _, err := s.sm.Get(storageKey{addr, key})
data, _, err := s.sm.Get(storageKey{addr, s.getStorageBarrier(addr), key})
if err != nil {
return nil, &Error{err}
}
Expand All @@ -242,7 +259,7 @@ func (s *State) GetRawStorage(addr thor.Address, key thor.Bytes32) (rlp.RawValue

// SetRawStorage set storage value in rlp raw.
func (s *State) SetRawStorage(addr thor.Address, key thor.Bytes32, raw rlp.RawValue) {
s.sm.Put(storageKey{addr, key}, raw)
s.sm.Put(storageKey{addr, s.getStorageBarrier(addr), key}, raw)
}

// EncodeStorage set storage value encoded by given enc method.
Expand Down Expand Up @@ -321,6 +338,8 @@ func (s *State) Exists(addr thor.Address) (bool, error) {
func (s *State) Delete(addr thor.Address) {
s.sm.Put(codeKey(addr), []byte(nil))
s.updateAccount(addr, emptyAccount())
// increase the barrier value
s.setStorageBarrier(addr, s.getStorageBarrier(addr)+1)
}

// NewCheckpoint makes a checkpoint of current state.
Expand All @@ -345,11 +364,13 @@ func (s *State) BuildStorageTrie(addr thor.Address) (*muxdb.Trie, error) {

trie := s.db.NewSecureTrie(StorageTrieName(thor.Blake2b(addr[:])), root)

barrier := s.getStorageBarrier(addr)

// traverse journal to filter out storage changes for addr
s.sm.Journal(func(k, v interface{}) bool {
switch key := k.(type) {
case storageKey:
if key.addr == addr {
if key.barrier == barrier && key.addr == addr {
err = saveStorage(trie, key.key, v.(rlp.RawValue))
if err != nil {
return false
Expand Down Expand Up @@ -414,6 +435,12 @@ func (s *State) Stage() (*Stage, error) {
c.storage = make(map[thor.Bytes32]rlp.RawValue)
}
c.storage[key.key] = v.(rlp.RawValue)
case storageBarrierKey:
if c, jerr = getChanged(thor.Address(key)); jerr != nil {
return false
}
// discard all storage updates when meet the barrier.
c.storage = nil
}
return true
})
Expand Down Expand Up @@ -453,8 +480,10 @@ func (s *State) Stage() (*Stage, error) {

type (
storageKey struct {
addr thor.Address
key thor.Bytes32
addr thor.Address
barrier int
key thor.Bytes32
}
codeKey thor.Address
codeKey thor.Address
storageBarrierKey thor.Address
)
23 changes: 23 additions & 0 deletions state/state_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,3 +146,26 @@ func TestStorage(t *testing.T) {

assert.Equal(t, M(thor.Blake2b(data), nil), M(st.GetStorage(addr, key)))
}

func TestStorageBarrier(t *testing.T) {
db := muxdb.NewMem()
st := New(db, thor.Bytes32{})

addr := thor.BytesToAddress([]byte("addr"))
key := thor.BytesToBytes32([]byte("key"))

st.SetCode(addr, []byte("code"))
st.SetStorage(addr, key, thor.BytesToBytes32([]byte("data")))

st.Delete(addr)
assert.Equal(t, M(rlp.RawValue(nil), nil), M(st.GetRawStorage(addr, key)), "should read empty storage when account deleted")

st.SetCode(addr, []byte("code"))

stage, err := st.Stage()
assert.Nil(t, err)

acc, err := loadAccount(stage.accountTrie, addr)
assert.Nil(t, err)
assert.Equal(t, 0, len(acc.StorageRoot), "should skip storage writes when account deleteed then recreated")
}

0 comments on commit 8eff2b2

Please sign in to comment.