state: implement JSON marshaling for MPT* items

This commit is contained in:
Evgenii Stratonikov 2020-06-03 18:09:28 +03:00
parent 24785f1f50
commit 5794bdb169
2 changed files with 87 additions and 7 deletions

View file

@ -1,6 +1,9 @@
package state package state
import ( import (
"encoding/json"
"errors"
"github.com/nspcc-dev/neo-go/pkg/core/transaction" "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/crypto/hash"
"github.com/nspcc-dev/neo-go/pkg/io" "github.com/nspcc-dev/neo-go/pkg/io"
@ -9,16 +12,16 @@ import (
// MPTRootBase represents storage state root. // MPTRootBase represents storage state root.
type MPTRootBase struct { type MPTRootBase struct {
Version byte Version byte `json:"version"`
Index uint32 Index uint32 `json:"index"`
PrevHash util.Uint256 PrevHash util.Uint256 `json:"prehash"`
Root util.Uint256 Root util.Uint256 `json:"stateroot"`
} }
// MPTRoot represents storage state root together with sign info. // MPTRoot represents storage state root together with sign info.
type MPTRoot struct { type MPTRoot struct {
MPTRootBase MPTRootBase
Witness *transaction.Witness Witness *transaction.Witness `json:"witness,omitempty"`
} }
// MPTRootStateFlag represents verification state of the state root. // MPTRootStateFlag represents verification state of the state root.
@ -33,8 +36,8 @@ const (
// MPTRootState represents state root together with its verification state. // MPTRootState represents state root together with its verification state.
type MPTRootState struct { type MPTRootState struct {
MPTRoot MPTRoot `json:"stateroot"`
Flag MPTRootStateFlag Flag MPTRootStateFlag `json:"flag"`
} }
// EncodeBinary implements io.Serializable. // EncodeBinary implements io.Serializable.
@ -103,3 +106,41 @@ func (s *MPTRoot) EncodeBinary(w *io.BinWriter) {
w.WriteArray([]*transaction.Witness{s.Witness}) w.WriteArray([]*transaction.Witness{s.Witness})
} }
} }
// String implements fmt.Stringer.
func (f MPTRootStateFlag) String() string {
switch f {
case Unverified:
return "Unverified"
case Verified:
return "Verified"
case Invalid:
return "Invalid"
default:
return ""
}
}
// MarshalJSON implements json.Marshaler.
func (f MPTRootStateFlag) MarshalJSON() ([]byte, error) {
return []byte(`"` + f.String() + `"`), nil
}
// UnmarshalJSON implements json.Unmarshaler.
func (f *MPTRootStateFlag) UnmarshalJSON(data []byte) error {
var s string
if err := json.Unmarshal(data, &s); err != nil {
return err
}
switch s {
case "Unverified":
*f = Unverified
case "Verified":
*f = Verified
case "Invalid":
*f = Invalid
default:
return errors.New("unknown flag")
}
return nil
}

View file

@ -1,12 +1,14 @@
package state package state
import ( import (
"encoding/json"
"math/rand" "math/rand"
"testing" "testing"
"github.com/nspcc-dev/neo-go/pkg/core/transaction" "github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/internal/random" "github.com/nspcc-dev/neo-go/pkg/internal/random"
"github.com/nspcc-dev/neo-go/pkg/internal/testserdes" "github.com/nspcc-dev/neo-go/pkg/internal/testserdes"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@ -59,3 +61,40 @@ func TestMPTRootStateUnverifiedByDefault(t *testing.T) {
var r MPTRootState var r MPTRootState
require.Equal(t, Unverified, r.Flag) require.Equal(t, Unverified, r.Flag)
} }
func TestMPTRoot_MarshalJSON(t *testing.T) {
t.Run("Good", func(t *testing.T) {
r := testStateRoot()
rs := &MPTRootState{
MPTRoot: *r,
Flag: Verified,
}
testserdes.MarshalUnmarshalJSON(t, rs, new(MPTRootState))
})
t.Run("Compatibility", func(t *testing.T) {
js := []byte(`{
"flag": "Unverified",
"stateroot": {
"version": 1,
"index": 3000000,
"prehash": "0x4f30f43af8dd2262fc331c45bfcd9066ebbacda204e6e81371cbd884fe7d6c90",
"stateroot": "0xb2fd7e368a848ef70d27cf44940a35237333ed05f1d971c9408f0eb285e0b6f3"
}}`)
rs := new(MPTRootState)
require.NoError(t, json.Unmarshal(js, &rs))
require.EqualValues(t, 1, rs.Version)
require.EqualValues(t, 3000000, rs.Index)
require.Nil(t, rs.Witness)
u, err := util.Uint256DecodeStringLE("4f30f43af8dd2262fc331c45bfcd9066ebbacda204e6e81371cbd884fe7d6c90")
require.NoError(t, err)
require.Equal(t, u, rs.PrevHash)
u, err = util.Uint256DecodeStringLE("b2fd7e368a848ef70d27cf44940a35237333ed05f1d971c9408f0eb285e0b6f3")
require.NoError(t, err)
require.Equal(t, u, rs.Root)
})
}