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 }