99 lines
2.6 KiB
Go
99 lines
2.6 KiB
Go
|
package stateroot
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
|
||
|
"github.com/nspcc-dev/neo-go/pkg/core/blockchainer"
|
||
|
"github.com/nspcc-dev/neo-go/pkg/core/mpt"
|
||
|
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
||
|
"github.com/nspcc-dev/neo-go/pkg/core/storage"
|
||
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||
|
"go.uber.org/atomic"
|
||
|
"go.uber.org/zap"
|
||
|
)
|
||
|
|
||
|
type (
|
||
|
// Module represents module for local processing of state roots.
|
||
|
Module struct {
|
||
|
Store *storage.MemCachedStore
|
||
|
mpt *mpt.Trie
|
||
|
bc blockchainer.Blockchainer
|
||
|
log *zap.Logger
|
||
|
|
||
|
localHeight atomic.Uint32
|
||
|
validatedHeight atomic.Uint32
|
||
|
currentLocal atomic.Value
|
||
|
}
|
||
|
)
|
||
|
|
||
|
// NewModule returns new instance of stateroot module.
|
||
|
func NewModule(bc blockchainer.Blockchainer, log *zap.Logger, s *storage.MemCachedStore) *Module {
|
||
|
return &Module{
|
||
|
bc: bc,
|
||
|
log: log,
|
||
|
Store: s,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// GetStateProof returns proof of having key in the MPT with the specified root.
|
||
|
func (s *Module) GetStateProof(root util.Uint256, key []byte) ([][]byte, error) {
|
||
|
tr := mpt.NewTrie(mpt.NewHashNode(root), false, storage.NewMemCachedStore(s.Store))
|
||
|
return tr.GetProof(key)
|
||
|
}
|
||
|
|
||
|
// GetStateRoot returns state root for a given height.
|
||
|
func (s *Module) GetStateRoot(height uint32) (*state.MPTRoot, error) {
|
||
|
return s.getStateRoot(makeStateRootKey(height))
|
||
|
}
|
||
|
|
||
|
// CurrentLocalStateRoot returns hash of the local state root.
|
||
|
func (s *Module) CurrentLocalStateRoot() util.Uint256 {
|
||
|
return s.currentLocal.Load().(util.Uint256)
|
||
|
}
|
||
|
|
||
|
// Init initializes state root module at the given height.
|
||
|
func (s *Module) Init(height uint32, enableRefCount bool) error {
|
||
|
var gcKey = []byte{byte(storage.DataMPT), prefixGC}
|
||
|
if height == 0 {
|
||
|
s.mpt = mpt.NewTrie(nil, enableRefCount, s.Store)
|
||
|
var val byte
|
||
|
if enableRefCount {
|
||
|
val = 1
|
||
|
}
|
||
|
s.currentLocal.Store(util.Uint256{})
|
||
|
return s.Store.Put(gcKey, []byte{val})
|
||
|
}
|
||
|
var hasRefCount bool
|
||
|
if v, err := s.Store.Get(gcKey); err == nil {
|
||
|
hasRefCount = v[0] != 0
|
||
|
}
|
||
|
if hasRefCount != enableRefCount {
|
||
|
return fmt.Errorf("KeepOnlyLatestState setting mismatch: old=%v, new=%v", hasRefCount, enableRefCount)
|
||
|
}
|
||
|
r, err := s.getStateRoot(makeStateRootKey(height))
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
s.currentLocal.Store(r.Root)
|
||
|
s.localHeight.Store(r.Index)
|
||
|
s.mpt = mpt.NewTrie(mpt.NewHashNode(r.Root), enableRefCount, s.Store)
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// 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
|
||
|
}
|
||
|
s.mpt.Flush()
|
||
|
err := s.addLocalStateRoot(&state.MPTRoot{
|
||
|
Index: index,
|
||
|
Root: s.mpt.StateRoot(),
|
||
|
})
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
_, err = s.Store.Persist()
|
||
|
return err
|
||
|
}
|