diff --git a/pkg/core/blockchain.go b/pkg/core/blockchain.go index c140ec561..08e959bfb 100644 --- a/pkg/core/blockchain.go +++ b/pkg/core/blockchain.go @@ -1235,7 +1235,7 @@ func (bc *Blockchain) AddStateRoot(r *state.MPTRoot) error { our, err := bc.GetStateRoot(r.Index) if err == nil { if our.Flag == state.Verified { - return nil + return bc.updateStateHeight(r.Index) } else if r.Witness == nil && our.Witness != nil { r.Witness = our.Witness } @@ -1257,10 +1257,24 @@ func (bc *Blockchain) AddStateRoot(r *state.MPTRoot) error { } flag = state.Verified } - return bc.dao.PutStateRoot(&state.MPTRootState{ + err = bc.dao.PutStateRoot(&state.MPTRootState{ MPTRoot: *r, Flag: flag, }) + if err != nil { + return err + } + return bc.updateStateHeight(r.Index) +} + +func (bc *Blockchain) updateStateHeight(newHeight uint32) error { + h, err := bc.dao.GetCurrentStateRootHeight() + if err != nil { + return errors.WithMessage(err, "can't get current state root height") + } else if newHeight == h+1 { + return bc.dao.PutCurrentStateRootHeight(h + 1) + } + return nil } // verifyStateRoot checks if state root is valid. diff --git a/pkg/core/dao/dao.go b/pkg/core/dao/dao.go index f55fd68e1..006b1ecdb 100644 --- a/pkg/core/dao/dao.go +++ b/pkg/core/dao/dao.go @@ -30,6 +30,7 @@ type DAO interface { GetContractState(hash util.Uint160) (*state.Contract, error) GetCurrentBlockHeight() (uint32, error) GetCurrentHeaderHeight() (i uint32, h util.Uint256, err error) + GetCurrentStateRootHeight() (uint32, error) GetHeaderHashes() ([]util.Uint256, error) GetNEP5Balances(acc util.Uint160) (*state.NEP5Balances, error) GetNEP5TransferLog(acc util.Uint160, index uint32) (*state.NEP5TransferLog, error) @@ -316,6 +317,27 @@ func (dao *Simple) InitMPT(height uint32) error { return nil } +// GetCurrentStateRootHeight returns current state root height. +func (dao *Simple) GetCurrentStateRootHeight() (uint32, error) { + key := []byte{byte(storage.DataMPT)} + val, err := dao.Store.Get(key) + if err != nil { + if err == storage.ErrKeyNotFound { + err = nil + } + return 0, err + } + return binary.LittleEndian.Uint32(val), nil +} + +// PutCurrentStateRootHeight updates current state root height. +func (dao *Simple) PutCurrentStateRootHeight(height uint32) error { + key := []byte{byte(storage.DataMPT)} + val := make([]byte, 4) + binary.LittleEndian.PutUint32(val, height) + return dao.Store.Put(key, val) +} + // GetStateRoot returns state root of a given height. func (dao *Simple) GetStateRoot(height uint32) (*state.MPTRootState, error) { r := new(state.MPTRootState)