neo-go/pkg/core/stateroot/store.go
Roman Khimov ccdda21718 stateroot: add and use DataMPTAux for auxiliary data
Use DataMPT for nodes only, otherwise with 1M blocks with have 1M
height-stateroot mapping entries that our GC has to iterate over for no
reason.
2022-02-14 17:29:21 +03:00

90 lines
2.1 KiB
Go

package stateroot
import (
"encoding/binary"
"errors"
"fmt"
"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/io"
)
var (
// ErrStateMismatch means that local state root doesn't match the one
// signed by state validators.
ErrStateMismatch = errors.New("stateroot mismatch")
)
const (
prefixLocal = 0x02
prefixValidated = 0x03
)
func (s *Module) addLocalStateRoot(store *storage.MemCachedStore, sr *state.MPTRoot) error {
key := makeStateRootKey(sr.Index)
if err := putStateRoot(store, key, sr); err != nil {
return err
}
data := make([]byte, 4)
binary.LittleEndian.PutUint32(data, sr.Index)
return store.Put([]byte{byte(storage.DataMPTAux), prefixLocal}, data)
}
func putStateRoot(store *storage.MemCachedStore, key []byte, sr *state.MPTRoot) error {
w := io.NewBufBinWriter()
sr.EncodeBinary(w.BinWriter)
return store.Put(key, w.Bytes())
}
func (s *Module) getStateRoot(key []byte) (*state.MPTRoot, error) {
data, err := s.Store.Get(key)
if err != nil {
return nil, err
}
sr := &state.MPTRoot{}
r := io.NewBinReaderFromBuf(data)
sr.DecodeBinary(r)
return sr, r.Err
}
func makeStateRootKey(index uint32) []byte {
key := make([]byte, 5)
key[0] = byte(storage.DataMPTAux)
binary.BigEndian.PutUint32(key, index)
return key
}
// AddStateRoot adds validated state root provided by network.
func (s *Module) AddStateRoot(sr *state.MPTRoot) error {
if err := s.VerifyStateRoot(sr); err != nil {
return err
}
key := makeStateRootKey(sr.Index)
local, err := s.getStateRoot(key)
if err != nil {
return err
}
if !local.Root.Equals(sr.Root) {
return fmt.Errorf("%w at block %d: %v vs %v", ErrStateMismatch, sr.Index, local.Root, sr.Root)
}
if len(local.Witness) != 0 {
return nil
}
if err := putStateRoot(s.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.DataMPTAux), prefixValidated}, data); err != nil {
return err
}
s.validatedHeight.Store(sr.Index)
if !s.srInHead {
updateStateHeightMetric(sr.Index)
}
return nil
}