stateroot: try to fix MPT caching/updating

It was completely ruined by bf20db09e0. MPT was
updating bc.dao directly which shouldn't ever happen, it must write into the
same cache and then Persist these KVs as usual.
This commit is contained in:
Roman Khimov 2021-03-27 00:13:19 +03:00
parent 56fd375c6d
commit d143696328
4 changed files with 36 additions and 28 deletions

View file

@ -731,7 +731,8 @@ func (bc *Blockchain) storeBlock(block *block.Block, txpool *mempool.Pool) error
d := cache.DAO.(*dao.Simple)
b := d.GetMPTBatch()
if err := bc.stateRoot.AddMPTBatch(block.Index, b); err != nil {
mpt, sr, err := bc.stateRoot.AddMPTBatch(block.Index, b, d.Store)
if err != nil {
// Here MPT can be left in a half-applied state.
// However if this error occurs, this is a bug somewhere in code
// because changes applied are the ones from HALTed transactions.
@ -761,6 +762,8 @@ func (bc *Blockchain) storeBlock(block *block.Block, txpool *mempool.Pool) error
return err
}
mpt.Store = bc.dao.Store
bc.stateRoot.UpdateCurrentLocal(mpt, sr)
bc.topBlock.Store(block)
atomic.StoreUint32(&bc.blockHeight, block.Index)
bc.memPool.RemoveStale(func(tx *transaction.Transaction) bool { return bc.IsTxStillRelevant(tx, txpool, false) }, bc)

View file

@ -557,7 +557,8 @@ func TestContractDestroy(t *testing.T) {
err = bc.dao.PutStorageItem(cs1.ID, []byte{1, 2, 3}, state.StorageItem{3, 2, 1})
require.NoError(t, err)
b := bc.dao.GetMPTBatch()
require.NoError(t, bc.GetStateModule().(*stateroot.Module).AddMPTBatch(bc.BlockHeight(), b))
_, _, err = bc.GetStateModule().(*stateroot.Module).AddMPTBatch(bc.BlockHeight(), b, bc.dao.Store)
require.NoError(t, err)
t.Run("no contract", func(t *testing.T) {
res, err := invokeContractMethod(bc, 1_00000000, mgmtHash, "destroy")

View file

@ -110,20 +110,33 @@ func (s *Module) Init(height uint32, enableRefCount bool) error {
}
// AddMPTBatch updates using provided batch.
func (s *Module) AddMPTBatch(index uint32, b mpt.Batch) error {
if _, err := s.mpt.PutBatch(b); err != nil {
return err
func (s *Module) AddMPTBatch(index uint32, b mpt.Batch, cache *storage.MemCachedStore) (*mpt.Trie, *state.MPTRoot, error) {
mpt := *s.mpt
mpt.Store = cache
if _, err := mpt.PutBatch(b); err != nil {
return nil, nil, err
}
s.mpt.Flush()
err := s.addLocalStateRoot(&state.MPTRoot{
mpt.Flush()
sr := &state.MPTRoot{
Index: index,
Root: s.mpt.StateRoot(),
})
if err != nil {
return err
Root: mpt.StateRoot(),
}
err := s.addLocalStateRoot(cache, sr)
if err != nil {
return nil, nil, err
}
return &mpt, sr, err
}
// UpdateCurrentLocal updates local caches using provided state root.
func (s *Module) UpdateCurrentLocal(mpt *mpt.Trie, sr *state.MPTRoot) {
s.mpt = mpt
s.currentLocal.Store(sr.Root)
s.localHeight.Store(sr.Index)
if s.bc.GetConfig().StateRootInHeader {
s.validatedHeight.Store(sr.Index)
updateStateHeightMetric(sr.Index)
}
_, err = s.Store.Persist()
return err
}
// VerifyStateRoot checks if state root is valid.

View file

@ -14,30 +14,21 @@ const (
prefixValidated = 0x03
)
func (s *Module) addLocalStateRoot(sr *state.MPTRoot) error {
func (s *Module) addLocalStateRoot(store *storage.MemCachedStore, sr *state.MPTRoot) error {
key := makeStateRootKey(sr.Index)
if err := s.putStateRoot(key, sr); err != nil {
if err := putStateRoot(store, key, sr); err != nil {
return err
}
data := make([]byte, 4)
binary.LittleEndian.PutUint32(data, sr.Index)
if err := s.Store.Put([]byte{byte(storage.DataMPT), prefixLocal}, data); err != nil {
return err
}
s.currentLocal.Store(sr.Root)
s.localHeight.Store(sr.Index)
if s.bc.GetConfig().StateRootInHeader {
s.validatedHeight.Store(sr.Index)
updateStateHeightMetric(sr.Index)
}
return nil
return store.Put([]byte{byte(storage.DataMPT), prefixLocal}, data)
}
func (s *Module) putStateRoot(key []byte, sr *state.MPTRoot) error {
func putStateRoot(store *storage.MemCachedStore, key []byte, sr *state.MPTRoot) error {
w := io.NewBufBinWriter()
sr.EncodeBinary(w.BinWriter)
return s.Store.Put(key, w.Bytes())
return store.Put(key, w.Bytes())
}
func (s *Module) getStateRoot(key []byte) (*state.MPTRoot, error) {
@ -72,7 +63,7 @@ func (s *Module) AddStateRoot(sr *state.MPTRoot) error {
if len(local.Witness) != 0 {
return nil
}
if err := s.putStateRoot(key, sr); err != nil {
if err := putStateRoot(s.Store, key, sr); err != nil {
return err
}