diff --git a/pkg/core/state/mpt_root.go b/pkg/core/state/mpt_root.go index 5fd716ff4..0a4e4c183 100644 --- a/pkg/core/state/mpt_root.go +++ b/pkg/core/state/mpt_root.go @@ -1,6 +1,9 @@ package state import ( + "encoding/binary" + + "github.com/nspcc-dev/neo-go/pkg/config/netmode" "github.com/nspcc-dev/neo-go/pkg/core/transaction" "github.com/nspcc-dev/neo-go/pkg/crypto/hash" "github.com/nspcc-dev/neo-go/pkg/io" @@ -9,6 +12,7 @@ import ( // MPTRoot represents storage state root together with sign info. type MPTRoot struct { + Network netmode.Magic `json:"-"` Version byte `json:"version"` Index uint32 `json:"index"` Root util.Uint256 `json:"stateroot"` @@ -17,9 +21,11 @@ type MPTRoot struct { // GetSignedPart returns part of MPTRootBase which needs to be signed. func (s *MPTRoot) GetSignedPart() []byte { - buf := io.NewBufBinWriter() - s.EncodeBinaryUnsigned(buf.BinWriter) - return buf.Bytes() + b := make([]byte, 4+32) + binary.LittleEndian.PutUint32(b, uint32(s.Network)) + h := s.Hash() + copy(b[4:], h[:]) + return b } // GetSignedHash returns hash of MPTRootBase which needs to be signed. @@ -29,7 +35,9 @@ func (s *MPTRoot) GetSignedHash() util.Uint256 { // Hash returns hash of s. func (s *MPTRoot) Hash() util.Uint256 { - return hash.DoubleSha256(s.GetSignedPart()) + buf := io.NewBufBinWriter() + s.EncodeBinaryUnsigned(buf.BinWriter) + return hash.Sha256(buf.Bytes()) } // DecodeBinaryUnsigned decodes hashable part of state root. diff --git a/pkg/core/stateroot/module.go b/pkg/core/stateroot/module.go index 2d63b89b5..49b5b2661 100644 --- a/pkg/core/stateroot/module.go +++ b/pkg/core/stateroot/module.go @@ -6,6 +6,7 @@ import ( "fmt" "sync" + "github.com/nspcc-dev/neo-go/pkg/config/netmode" "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" @@ -19,10 +20,11 @@ import ( type ( // Module represents module for local processing of state roots. Module struct { - Store *storage.MemCachedStore - mpt *mpt.Trie - bc blockchainer.Blockchainer - log *zap.Logger + Store *storage.MemCachedStore + network netmode.Magic + mpt *mpt.Trie + bc blockchainer.Blockchainer + log *zap.Logger currentLocal atomic.Value localHeight atomic.Uint32 @@ -45,9 +47,10 @@ type ( // 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, + network: bc.GetConfig().Magic, + bc: bc, + log: log, + Store: s, } } @@ -113,8 +116,9 @@ func (s *Module) AddMPTBatch(index uint32, b mpt.Batch) error { } s.mpt.Flush() err := s.addLocalStateRoot(&state.MPTRoot{ - Index: index, - Root: s.mpt.StateRoot(), + Network: s.network, + Index: index, + Root: s.mpt.StateRoot(), }) if err != nil { return err diff --git a/pkg/core/stateroot/store.go b/pkg/core/stateroot/store.go index b2ab7d210..d2f7fd4c4 100644 --- a/pkg/core/stateroot/store.go +++ b/pkg/core/stateroot/store.go @@ -46,7 +46,7 @@ func (s *Module) getStateRoot(key []byte) (*state.MPTRoot, error) { return nil, err } - sr := new(state.MPTRoot) + sr := &state.MPTRoot{Network: s.network} r := io.NewBinReaderFromBuf(data) sr.DecodeBinary(r) return sr, r.Err diff --git a/pkg/core/stateroot_test.go b/pkg/core/stateroot_test.go index dc9632081..27cad0cd0 100644 --- a/pkg/core/stateroot_test.go +++ b/pkg/core/stateroot_test.go @@ -10,6 +10,7 @@ import ( "github.com/nspcc-dev/neo-go/internal/testserdes" "github.com/nspcc-dev/neo-go/pkg/config" + "github.com/nspcc-dev/neo-go/pkg/config/netmode" "github.com/nspcc-dev/neo-go/pkg/core/native/noderoles" "github.com/nspcc-dev/neo-go/pkg/core/state" "github.com/nspcc-dev/neo-go/pkg/core/storage" @@ -43,7 +44,7 @@ func testSignStateRoot(t *testing.T, r *state.MPTRoot, pubs keys.PublicKeys, acc VerificationScript: script, InvocationScript: w.Bytes(), } - data, err := testserdes.EncodeBinary(stateroot.NewMessage(stateroot.RootT, r)) + data, err := testserdes.EncodeBinary(stateroot.NewMessage(netmode.UnitTestNet, stateroot.RootT, r)) require.NoError(t, err) return data } @@ -96,7 +97,7 @@ func TestStateRoot(t *testing.T) { t.Run("drop zero index", func(t *testing.T) { r, err := srv.GetStateRoot(0) require.NoError(t, err) - data, err := testserdes.EncodeBinary(stateroot.NewMessage(stateroot.RootT, r)) + data, err := testserdes.EncodeBinary(stateroot.NewMessage(netmode.UnitTestNet, stateroot.RootT, r)) require.NoError(t, err) require.NoError(t, srv.OnPayload(&payload.Extensible{Data: data})) require.EqualValues(t, 0, srv.CurrentValidatedHeight()) diff --git a/pkg/rpc/server/server_test.go b/pkg/rpc/server/server_test.go index aa222cb32..a7317d519 100644 --- a/pkg/rpc/server/server_test.go +++ b/pkg/rpc/server/server_test.go @@ -1368,7 +1368,7 @@ func testRPCProtocol(t *testing.T, doRPCCall func(string, string, *testing.T) [] body := doRPCCall(rpc, httpSrv.URL, t) rawRes := checkErrGetResult(t, body, false) - res := new(state.MPTRoot) + res := &state.MPTRoot{Network: netmode.UnitTestNet} require.NoError(t, json.Unmarshal(rawRes, res)) require.NotEqual(t, util.Uint256{}, res.Root) // be sure this test uses valid height diff --git a/pkg/services/stateroot/message.go b/pkg/services/stateroot/message.go index 5b1e32e73..2e65acf1d 100644 --- a/pkg/services/stateroot/message.go +++ b/pkg/services/stateroot/message.go @@ -3,6 +3,7 @@ package stateroot import ( "fmt" + "github.com/nspcc-dev/neo-go/pkg/config/netmode" "github.com/nspcc-dev/neo-go/pkg/core/state" "github.com/nspcc-dev/neo-go/pkg/io" ) @@ -13,6 +14,7 @@ type ( // Message represents state-root related message. Message struct { + Network netmode.Magic Type MessageType Payload io.Serializable } @@ -25,8 +27,9 @@ const ( ) // NewMessage creates new message of specified type. -func NewMessage(typ MessageType, p io.Serializable) *Message { +func NewMessage(net netmode.Magic, typ MessageType, p io.Serializable) *Message { return &Message{ + Network: net, Type: typ, Payload: p, } @@ -44,7 +47,7 @@ func (m *Message) DecodeBinary(r *io.BinReader) { case VoteT: m.Payload = new(Vote) case RootT: - m.Payload = new(state.MPTRoot) + m.Payload = &state.MPTRoot{Network: m.Network} default: r.Err = fmt.Errorf("invalid type: %x", m.Type) return diff --git a/pkg/services/stateroot/network.go b/pkg/services/stateroot/network.go index b5489edc5..a98e1af82 100644 --- a/pkg/services/stateroot/network.go +++ b/pkg/services/stateroot/network.go @@ -72,7 +72,7 @@ func (s *service) getIncompleteRoot(height uint32) *incompleteRoot { func (s *service) sendValidatedRoot(r *state.MPTRoot) { w := io.NewBufBinWriter() - m := NewMessage(RootT, r) + m := NewMessage(s.Network, RootT, r) m.EncodeBinary(w.BinWriter) ep := &payload.Extensible{ Network: s.Network, diff --git a/pkg/services/stateroot/service.go b/pkg/services/stateroot/service.go index 0c5b17f40..55a86ab4e 100644 --- a/pkg/services/stateroot/service.go +++ b/pkg/services/stateroot/service.go @@ -61,6 +61,7 @@ const ( func New(cfg config.StateRoot, log *zap.Logger, bc blockchainer.Blockchainer) (Service, error) { s := &service{ StateRoot: bc.GetStateModule(), + Network: bc.GetConfig().Magic, chain: bc, log: log, incompleteRoots: make(map[uint32]*incompleteRoot), @@ -94,7 +95,7 @@ func New(cfg config.StateRoot, log *zap.Logger, bc blockchainer.Blockchainer) (S // OnPayload implements Service interface. func (s *service) OnPayload(ep *payload.Extensible) error { - m := new(Message) + m := &Message{Network: s.Network} r := io.NewBinReaderFromBuf(ep.Data) m.DecodeBinary(r) if r.Err != nil { diff --git a/pkg/services/stateroot/validators.go b/pkg/services/stateroot/validators.go index b3a98378e..359d2b779 100644 --- a/pkg/services/stateroot/validators.go +++ b/pkg/services/stateroot/validators.go @@ -55,7 +55,7 @@ func (s *service) signAndSend(r *state.MPTRoot) error { s.accMtx.RLock() myIndex := s.myIndex s.accMtx.RUnlock() - msg := NewMessage(VoteT, &Vote{ + msg := NewMessage(s.Network, VoteT, &Vote{ ValidatorIndex: int32(myIndex), Height: r.Index, Signature: sig,