github.com/nspcc-dev/neo-go@v0.105.2-0.20240517133400-6be757af3eba/pkg/core/stateroot/store.go (about)

     1  package stateroot
     2  
     3  import (
     4  	"encoding/binary"
     5  	"errors"
     6  	"fmt"
     7  
     8  	"github.com/nspcc-dev/neo-go/pkg/core/state"
     9  	"github.com/nspcc-dev/neo-go/pkg/core/storage"
    10  	"github.com/nspcc-dev/neo-go/pkg/io"
    11  )
    12  
    13  var (
    14  	// ErrStateMismatch means that local state root doesn't match the one
    15  	// signed by state validators.
    16  	ErrStateMismatch = errors.New("stateroot mismatch")
    17  )
    18  
    19  const (
    20  	prefixLocal     = 0x02
    21  	prefixValidated = 0x03
    22  )
    23  
    24  func (s *Module) addLocalStateRoot(store *storage.MemCachedStore, sr *state.MPTRoot) {
    25  	key := makeStateRootKey(sr.Index)
    26  	putStateRoot(store, key, sr)
    27  
    28  	data := make([]byte, 4)
    29  	binary.LittleEndian.PutUint32(data, sr.Index)
    30  	store.Put([]byte{byte(storage.DataMPTAux), prefixLocal}, data)
    31  }
    32  
    33  func putStateRoot(store *storage.MemCachedStore, key []byte, sr *state.MPTRoot) {
    34  	w := io.NewBufBinWriter()
    35  	sr.EncodeBinary(w.BinWriter)
    36  	store.Put(key, w.Bytes())
    37  }
    38  
    39  func (s *Module) getStateRoot(key []byte) (*state.MPTRoot, error) {
    40  	data, err := s.Store.Get(key)
    41  	if err != nil {
    42  		return nil, err
    43  	}
    44  
    45  	sr := &state.MPTRoot{}
    46  	r := io.NewBinReaderFromBuf(data)
    47  	sr.DecodeBinary(r)
    48  	return sr, r.Err
    49  }
    50  
    51  func makeStateRootKey(index uint32) []byte {
    52  	key := make([]byte, 5)
    53  	key[0] = byte(storage.DataMPTAux)
    54  	binary.BigEndian.PutUint32(key[1:], index)
    55  	return key
    56  }
    57  
    58  // AddStateRoot adds validated state root provided by network.
    59  func (s *Module) AddStateRoot(sr *state.MPTRoot) error {
    60  	if err := s.VerifyStateRoot(sr); err != nil {
    61  		return err
    62  	}
    63  	key := makeStateRootKey(sr.Index)
    64  	local, err := s.getStateRoot(key)
    65  	if err != nil {
    66  		return err
    67  	}
    68  	if !local.Root.Equals(sr.Root) {
    69  		return fmt.Errorf("%w at block %d: %v vs %v", ErrStateMismatch, sr.Index, local.Root, sr.Root)
    70  	}
    71  	if len(local.Witness) != 0 {
    72  		return nil
    73  	}
    74  	putStateRoot(s.Store, key, sr)
    75  
    76  	data := make([]byte, 4)
    77  	binary.LittleEndian.PutUint32(data, sr.Index)
    78  	s.Store.Put([]byte{byte(storage.DataMPTAux), prefixValidated}, data)
    79  	s.validatedHeight.Store(sr.Index)
    80  	if !s.srInHead {
    81  		updateStateHeightMetric(sr.Index)
    82  	}
    83  	return nil
    84  }