mpt: update MPT after the block processing

This commit is contained in:
Evgenii Stratonikov 2020-12-24 19:32:27 +03:00
parent 168ba7960c
commit 30423f3306
4 changed files with 39 additions and 11 deletions

View file

@ -687,7 +687,12 @@ func (bc *Blockchain) storeBlock(block *block.Block, txpool *mempool.Pool) error
}
writeBuf.Reset()
root := bc.dao.MPT.StateRoot()
d := cache.DAO.(*dao.Simple)
if err := d.UpdateMPT(); err != nil {
return fmt.Errorf("error while trying to apply MPT changes: %w", err)
}
root := d.MPT.StateRoot()
var prevHash util.Uint256
if block.Index > 0 {
prev, err := bc.dao.GetStateRoot(block.Index - 1)

View file

@ -382,11 +382,6 @@ func (dao *Simple) PutStorageItem(id int32, key []byte, si *state.StorageItem) e
return buf.Err
}
v := buf.Bytes()
if dao.MPT != nil {
if err := dao.MPT.Put(stKey[1:], v); err != nil && err != mpt.ErrNotFound {
return err
}
}
return dao.Store.Put(stKey, v)
}
@ -394,11 +389,6 @@ func (dao *Simple) PutStorageItem(id int32, key []byte, si *state.StorageItem) e
// given key from the store.
func (dao *Simple) DeleteStorageItem(id int32, key []byte) error {
stKey := makeStorageItemKey(id, key)
if dao.MPT != nil {
if err := dao.MPT.Delete(stKey[1:]); err != nil && err != mpt.ErrNotFound {
return err
}
}
return dao.Store.Delete(stKey)
}
@ -701,3 +691,18 @@ func (dao *Simple) StoreAsTransaction(tx *transaction.Transaction, index uint32,
func (dao *Simple) Persist() (int, error) {
return dao.Store.Persist()
}
// UpdateMPT updates MPT using storage items from the underlying memcached store.
func (dao *Simple) UpdateMPT() error {
var err error
dao.Store.MemoryStore.SeekAll([]byte{byte(storage.STStorage)}, func(k, v []byte) {
if err != nil {
return
} else if v != nil {
err = dao.MPT.Put(k[1:], v)
} else {
err = dao.MPT.Delete(k[1:])
}
})
return err
}

View file

@ -440,6 +440,7 @@ func TestContractDestroy(t *testing.T) {
require.NoError(t, err)
err = bc.dao.PutStorageItem(cs1.ID, []byte{1, 2, 3}, &state.StorageItem{Value: []byte{3, 2, 1}})
require.NoError(t, err)
require.NoError(t, bc.dao.UpdateMPT())
t.Run("no contract", func(t *testing.T) {
res, err := invokeContractMethod(bc, 1_00000000, mgmtHash, "destroy")

View file

@ -102,6 +102,23 @@ func (s *MemoryStore) Seek(key []byte, f func(k, v []byte)) {
s.mut.RUnlock()
}
// SeekAll is like seek but also iterates over deleted items.
func (s *MemoryStore) SeekAll(key []byte, f func(k, v []byte)) {
s.mut.RLock()
defer s.mut.RUnlock()
sk := string(key)
for k, v := range s.mem {
if strings.HasPrefix(k, sk) {
f([]byte(k), v)
}
}
for k := range s.del {
if strings.HasPrefix(k, sk) {
f([]byte(k), nil)
}
}
}
// seek is an internal unlocked implementation of Seek.
func (s *MemoryStore) seek(key []byte, f func(k, v []byte)) {
for k, v := range s.mem {