diff --git a/pkg/core/state/deposit.go b/pkg/core/state/deposit.go index 8e45e9595..879b562b3 100644 --- a/pkg/core/state/deposit.go +++ b/pkg/core/state/deposit.go @@ -1,10 +1,13 @@ package state import ( + "errors" + "fmt" + "math" "math/big" - "github.com/nspcc-dev/neo-go/pkg/encoding/bigint" "github.com/nspcc-dev/neo-go/pkg/io" + "github.com/nspcc-dev/neo-go/pkg/vm/stackitem" ) // Deposit represents GAS deposit from Notary contract. @@ -15,12 +18,46 @@ type Deposit struct { // EncodeBinary implements io.Serializable interface. func (d *Deposit) EncodeBinary(w *io.BinWriter) { - w.WriteVarBytes(bigint.ToBytes(d.Amount)) - w.WriteU32LE(d.Till) + stackitem.EncodeBinary(d.toStackItem(), w) } // DecodeBinary implements io.Serializable interface. func (d *Deposit) DecodeBinary(r *io.BinReader) { - d.Amount = bigint.FromBytes(r.ReadVarBytes()) - d.Till = r.ReadU32LE() + si := stackitem.DecodeBinary(r) + if r.Err != nil { + return + } + r.Err = d.fromStackItem(si) +} + +func (d *Deposit) toStackItem() stackitem.Item { + return stackitem.NewStruct([]stackitem.Item{ + stackitem.NewBigInteger(d.Amount), + stackitem.Make(d.Till), + }) +} + +func (d *Deposit) fromStackItem(it stackitem.Item) error { + items, ok := it.Value().([]stackitem.Item) + if !ok { + return errors.New("not a struct") + } + if len(items) != 2 { + return errors.New("wrong number of elements") + } + amount, err := items[0].TryInteger() + if err != nil { + return fmt.Errorf("invalid amount: %w", err) + } + till, err := items[1].TryInteger() + if err != nil { + return fmt.Errorf("invalid till: %w", err) + } + ti64 := till.Int64() + if !till.IsInt64() || ti64 > math.MaxUint32 || ti64 < 0 { + return errors.New("wrong till value") + } + d.Amount = amount + d.Till = uint32(ti64) + return nil } diff --git a/pkg/core/state/deposit_test.go b/pkg/core/state/deposit_test.go new file mode 100644 index 000000000..e928bc3a7 --- /dev/null +++ b/pkg/core/state/deposit_test.go @@ -0,0 +1,59 @@ +package state + +import ( + "math/big" + "testing" + + "github.com/nspcc-dev/neo-go/internal/testserdes" + "github.com/nspcc-dev/neo-go/pkg/vm/stackitem" + "github.com/stretchr/testify/require" +) + +func TestEncodeDecodeDeposit(t *testing.T) { + d := &Deposit{Amount: big.NewInt(100500), Till: 888} + + depo := new(Deposit) + testserdes.EncodeDecodeBinary(t, d, depo) + item := stackitem.Make(42) + data, err := stackitem.Serialize(item) + require.NoError(t, err) + require.Error(t, testserdes.DecodeBinary(data, depo)) +} + +func TestDepositFromStackItem(t *testing.T) { + var d Deposit + + item := stackitem.Make(42) + require.Error(t, d.fromStackItem(item)) + + item = stackitem.NewStruct(nil) + require.Error(t, d.fromStackItem(item)) + + item = stackitem.NewStruct([]stackitem.Item{ + stackitem.NewStruct(nil), + stackitem.NewStruct(nil), + }) + require.Error(t, d.fromStackItem(item)) + + item = stackitem.NewStruct([]stackitem.Item{ + stackitem.Make(777), + stackitem.NewStruct(nil), + }) + require.Error(t, d.fromStackItem(item)) + + item = stackitem.NewStruct([]stackitem.Item{ + stackitem.Make(777), + stackitem.Make(-1), + }) + require.Error(t, d.fromStackItem(item)) + item = stackitem.NewStruct([]stackitem.Item{ + stackitem.Make(777), + stackitem.Make("somenonu64value"), + }) + require.Error(t, d.fromStackItem(item)) + item = stackitem.NewStruct([]stackitem.Item{ + stackitem.Make(777), + stackitem.Make(888), + }) + require.NoError(t, d.fromStackItem(item)) +}