forked from TrueCloudLab/neoneo-go
Merge pull request #2413 from nspcc-dev/smartcontract-big-numbers
smartcontract: allow to use `*big.Int` numbers for integers
This commit is contained in:
commit
2d60d4021b
7 changed files with 86 additions and 286 deletions
|
@ -5,6 +5,7 @@ package client
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math/big"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/native/nativenames"
|
"github.com/nspcc-dev/neo-go/pkg/core/native/nativenames"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/native/noderoles"
|
"github.com/nspcc-dev/neo-go/pkg/core/native/noderoles"
|
||||||
|
@ -55,11 +56,11 @@ func (c *Client) GetDesignatedByRole(role noderoles.Role, index uint32) (keys.Pu
|
||||||
result, err := c.InvokeFunction(rmHash, "getDesignatedByRole", []smartcontract.Parameter{
|
result, err := c.InvokeFunction(rmHash, "getDesignatedByRole", []smartcontract.Parameter{
|
||||||
{
|
{
|
||||||
Type: smartcontract.IntegerType,
|
Type: smartcontract.IntegerType,
|
||||||
Value: int64(role),
|
Value: big.NewInt(int64(role)),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Type: smartcontract.IntegerType,
|
Type: smartcontract.IntegerType,
|
||||||
Value: int64(index),
|
Value: big.NewInt(int64(index)),
|
||||||
},
|
},
|
||||||
}, nil)
|
}, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -84,7 +85,7 @@ func (c *Client) NNSResolve(nnsHash util.Uint160, name string, typ nns.RecordTyp
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Type: smartcontract.IntegerType,
|
Type: smartcontract.IntegerType,
|
||||||
Value: int64(typ),
|
Value: big.NewInt(int64(typ)),
|
||||||
},
|
},
|
||||||
}, nil)
|
}, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -1,72 +0,0 @@
|
||||||
package smartcontract
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"math/big"
|
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ParameterFromStackItem converts stackitem.Item to Parameter.
|
|
||||||
func ParameterFromStackItem(i stackitem.Item, seen map[stackitem.Item]bool) Parameter {
|
|
||||||
switch t := i.(type) {
|
|
||||||
case stackitem.Null, *stackitem.Pointer:
|
|
||||||
return NewParameter(AnyType)
|
|
||||||
case *stackitem.BigInteger:
|
|
||||||
return Parameter{
|
|
||||||
Type: IntegerType,
|
|
||||||
Value: i.Value().(*big.Int).Int64(),
|
|
||||||
}
|
|
||||||
case stackitem.Bool:
|
|
||||||
return Parameter{
|
|
||||||
Type: BoolType,
|
|
||||||
Value: i.Value().(bool),
|
|
||||||
}
|
|
||||||
case *stackitem.ByteArray:
|
|
||||||
return Parameter{
|
|
||||||
Type: ByteArrayType,
|
|
||||||
Value: i.Value().([]byte),
|
|
||||||
}
|
|
||||||
case *stackitem.Interop:
|
|
||||||
return Parameter{
|
|
||||||
Type: InteropInterfaceType,
|
|
||||||
Value: nil,
|
|
||||||
}
|
|
||||||
case *stackitem.Buffer:
|
|
||||||
return Parameter{
|
|
||||||
Type: ByteArrayType,
|
|
||||||
Value: i.Value().([]byte),
|
|
||||||
}
|
|
||||||
case *stackitem.Struct, *stackitem.Array:
|
|
||||||
var value []Parameter
|
|
||||||
|
|
||||||
if !seen[i] {
|
|
||||||
seen[i] = true
|
|
||||||
for _, stackItem := range i.Value().([]stackitem.Item) {
|
|
||||||
parameter := ParameterFromStackItem(stackItem, seen)
|
|
||||||
value = append(value, parameter)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Parameter{
|
|
||||||
Type: ArrayType,
|
|
||||||
Value: value,
|
|
||||||
}
|
|
||||||
case *stackitem.Map:
|
|
||||||
value := make([]ParameterPair, 0)
|
|
||||||
if !seen[i] {
|
|
||||||
seen[i] = true
|
|
||||||
for _, element := range i.Value().([]stackitem.MapElement) {
|
|
||||||
value = append(value, ParameterPair{
|
|
||||||
Key: ParameterFromStackItem(element.Key, seen),
|
|
||||||
Value: ParameterFromStackItem(element.Value, seen),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Parameter{
|
|
||||||
Type: MapType,
|
|
||||||
Value: value,
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
panic(fmt.Sprintf("unknown stack item type: %v", t))
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,79 +0,0 @@
|
||||||
package smartcontract
|
|
||||||
|
|
||||||
import (
|
|
||||||
"math/big"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
var toContractParameterTestCases = []struct {
|
|
||||||
input stackitem.Item
|
|
||||||
result Parameter
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
input: stackitem.NewStruct([]stackitem.Item{
|
|
||||||
stackitem.NewBigInteger(big.NewInt(1)),
|
|
||||||
stackitem.NewBool(true),
|
|
||||||
}),
|
|
||||||
result: Parameter{Type: ArrayType, Value: []Parameter{
|
|
||||||
{Type: IntegerType, Value: int64(1)},
|
|
||||||
{Type: BoolType, Value: true},
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: stackitem.NewBool(false),
|
|
||||||
result: Parameter{Type: BoolType, Value: false},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: stackitem.NewByteArray([]byte{0x01, 0x02, 0x03}),
|
|
||||||
result: Parameter{Type: ByteArrayType, Value: []byte{0x01, 0x02, 0x03}},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: stackitem.NewBuffer([]byte{0x01, 0x02, 0x03}),
|
|
||||||
result: Parameter{Type: ByteArrayType, Value: []byte{0x01, 0x02, 0x03}},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: stackitem.NewArray([]stackitem.Item{stackitem.NewBigInteger(big.NewInt(2)), stackitem.NewBool(true)}),
|
|
||||||
result: Parameter{Type: ArrayType, Value: []Parameter{
|
|
||||||
{Type: IntegerType, Value: int64(2)},
|
|
||||||
{Type: BoolType, Value: true},
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: stackitem.NewInterop(nil),
|
|
||||||
result: Parameter{Type: InteropInterfaceType, Value: nil},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: stackitem.NewMapWithValue([]stackitem.MapElement{
|
|
||||||
{Key: stackitem.NewBigInteger(big.NewInt(1)), Value: stackitem.NewBool(true)},
|
|
||||||
{Key: stackitem.NewByteArray([]byte("qwerty")), Value: stackitem.NewBigInteger(big.NewInt(3))},
|
|
||||||
{Key: stackitem.NewBool(true), Value: stackitem.NewBool(false)},
|
|
||||||
}),
|
|
||||||
result: Parameter{
|
|
||||||
Type: MapType,
|
|
||||||
Value: []ParameterPair{
|
|
||||||
{
|
|
||||||
Key: Parameter{Type: IntegerType, Value: int64(1)},
|
|
||||||
Value: Parameter{Type: BoolType, Value: true},
|
|
||||||
}, {
|
|
||||||
Key: Parameter{Type: ByteArrayType, Value: []byte("qwerty")},
|
|
||||||
Value: Parameter{Type: IntegerType, Value: int64(3)},
|
|
||||||
}, {
|
|
||||||
|
|
||||||
Key: Parameter{Type: BoolType, Value: true},
|
|
||||||
Value: Parameter{Type: BoolType, Value: false},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestToContractParameter(t *testing.T) {
|
|
||||||
for _, tc := range toContractParameterTestCases {
|
|
||||||
seen := make(map[stackitem.Item]bool)
|
|
||||||
res := ParameterFromStackItem(tc.input, seen)
|
|
||||||
assert.Equal(t, res, tc.result)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -5,13 +5,14 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"math/big"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/io"
|
"github.com/nspcc-dev/neo-go/pkg/io"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ParamType represents the Type of the smart contract parameter.
|
// ParamType represents the Type of the smart contract parameter.
|
||||||
|
@ -208,7 +209,11 @@ func adjustValToType(typ ParamType, val string) (interface{}, error) {
|
||||||
return nil, errors.New("invalid boolean value")
|
return nil, errors.New("invalid boolean value")
|
||||||
}
|
}
|
||||||
case IntegerType:
|
case IntegerType:
|
||||||
return strconv.ParseInt(val, 10, 64)
|
bi, ok := new(big.Int).SetString(val, 10)
|
||||||
|
if !ok || stackitem.CheckIntegerSize(bi) != nil {
|
||||||
|
return nil, errors.New("invalid integer value")
|
||||||
|
}
|
||||||
|
return bi, nil
|
||||||
case Hash160Type:
|
case Hash160Type:
|
||||||
u, err := address.StringToUint160(val)
|
u, err := address.StringToUint160(val)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
@ -250,8 +255,8 @@ func adjustValToType(typ ParamType, val string) (interface{}, error) {
|
||||||
func inferParamType(val string) ParamType {
|
func inferParamType(val string) ParamType {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
_, err = strconv.Atoi(val)
|
bi, ok := new(big.Int).SetString(val, 10)
|
||||||
if err == nil {
|
if ok && stackitem.CheckIntegerSize(bi) == nil {
|
||||||
return IntegerType
|
return IntegerType
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,9 +2,11 @@ package smartcontract
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
|
"math/big"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
@ -76,6 +78,7 @@ func TestParseParamType(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestInferParamType(t *testing.T) {
|
func TestInferParamType(t *testing.T) {
|
||||||
|
bi := new(big.Int).Lsh(big.NewInt(1), stackitem.MaxBigIntegerSizeBits-2)
|
||||||
var inouts = []struct {
|
var inouts = []struct {
|
||||||
in string
|
in string
|
||||||
out ParamType
|
out ParamType
|
||||||
|
@ -88,6 +91,15 @@ func TestInferParamType(t *testing.T) {
|
||||||
}, {
|
}, {
|
||||||
in: "0",
|
in: "0",
|
||||||
out: IntegerType,
|
out: IntegerType,
|
||||||
|
}, {
|
||||||
|
in: "8765432187654321111",
|
||||||
|
out: IntegerType,
|
||||||
|
}, {
|
||||||
|
in: bi.String(),
|
||||||
|
out: IntegerType,
|
||||||
|
}, {
|
||||||
|
in: bi.String() + "0", // big for Integer but is still a valid hex
|
||||||
|
out: ByteArrayType,
|
||||||
}, {
|
}, {
|
||||||
in: "2e10",
|
in: "2e10",
|
||||||
out: ByteArrayType,
|
out: ByteArrayType,
|
||||||
|
@ -150,6 +162,8 @@ func TestInferParamType(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAdjustValToType(t *testing.T) {
|
func TestAdjustValToType(t *testing.T) {
|
||||||
|
bi := big.NewInt(1).Lsh(big.NewInt(1), stackitem.MaxBigIntegerSizeBits-2)
|
||||||
|
|
||||||
var inouts = []struct {
|
var inouts = []struct {
|
||||||
typ ParamType
|
typ ParamType
|
||||||
val string
|
val string
|
||||||
|
@ -190,15 +204,23 @@ func TestAdjustValToType(t *testing.T) {
|
||||||
}, {
|
}, {
|
||||||
typ: IntegerType,
|
typ: IntegerType,
|
||||||
val: "0",
|
val: "0",
|
||||||
out: int64(0),
|
out: big.NewInt(0),
|
||||||
}, {
|
}, {
|
||||||
typ: IntegerType,
|
typ: IntegerType,
|
||||||
val: "42",
|
val: "42",
|
||||||
out: int64(42),
|
out: big.NewInt(42),
|
||||||
}, {
|
}, {
|
||||||
typ: IntegerType,
|
typ: IntegerType,
|
||||||
val: "-42",
|
val: "-42",
|
||||||
out: int64(-42),
|
out: big.NewInt(-42),
|
||||||
|
}, {
|
||||||
|
typ: IntegerType,
|
||||||
|
val: bi.String(),
|
||||||
|
out: bi,
|
||||||
|
}, {
|
||||||
|
typ: IntegerType,
|
||||||
|
val: bi.String() + "0",
|
||||||
|
err: true,
|
||||||
}, {
|
}, {
|
||||||
typ: IntegerType,
|
typ: IntegerType,
|
||||||
val: "q",
|
val: "q",
|
||||||
|
|
|
@ -8,16 +8,16 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math/big"
|
||||||
"math/bits"
|
"math/bits"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/io"
|
"github.com/nspcc-dev/neo-go/pkg/encoding/bigint"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Parameter represents a smart contract parameter.
|
// Parameter represents a smart contract parameter.
|
||||||
|
@ -65,13 +65,12 @@ func (p Parameter) MarshalJSON() ([]byte, error) {
|
||||||
case BoolType, StringType, Hash160Type, Hash256Type:
|
case BoolType, StringType, Hash160Type, Hash256Type:
|
||||||
resultRawValue, resultErr = json.Marshal(p.Value)
|
resultRawValue, resultErr = json.Marshal(p.Value)
|
||||||
case IntegerType:
|
case IntegerType:
|
||||||
val, ok := p.Value.(int64)
|
val, ok := p.Value.(*big.Int)
|
||||||
if !ok {
|
if !ok {
|
||||||
resultErr = errors.New("invalid integer value")
|
resultErr = errors.New("invalid integer value")
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
valStr := strconv.FormatInt(val, 10)
|
resultRawValue = json.RawMessage(`"` + val.String() + `"`)
|
||||||
resultRawValue = json.RawMessage(`"` + valStr + `"`)
|
|
||||||
case PublicKeyType, ByteArrayType, SignatureType:
|
case PublicKeyType, ByteArrayType, SignatureType:
|
||||||
if p.Type == PublicKeyType {
|
if p.Type == PublicKeyType {
|
||||||
resultRawValue, resultErr = json.Marshal(hex.EncodeToString(p.Value.([]byte)))
|
resultRawValue, resultErr = json.Marshal(hex.EncodeToString(p.Value.([]byte)))
|
||||||
|
@ -145,17 +144,22 @@ func (p *Parameter) UnmarshalJSON(data []byte) (err error) {
|
||||||
p.Value = s
|
p.Value = s
|
||||||
case IntegerType:
|
case IntegerType:
|
||||||
if err = json.Unmarshal(r.Value, &i); err == nil {
|
if err = json.Unmarshal(r.Value, &i); err == nil {
|
||||||
p.Value = i
|
p.Value = big.NewInt(i)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// sometimes integer comes as string
|
// sometimes integer comes as string
|
||||||
if err = json.Unmarshal(r.Value, &s); err != nil {
|
if jErr := json.Unmarshal(r.Value, &s); jErr != nil {
|
||||||
return
|
return jErr
|
||||||
}
|
}
|
||||||
if i, err = strconv.ParseInt(s, 10, 64); err != nil {
|
bi, ok := new(big.Int).SetString(s, 10)
|
||||||
return
|
if !ok {
|
||||||
|
// In this case previous err should mean string contains non-digit characters.
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = stackitem.CheckIntegerSize(bi)
|
||||||
|
if err == nil {
|
||||||
|
p.Value = bi
|
||||||
}
|
}
|
||||||
p.Value = i
|
|
||||||
case ArrayType:
|
case ArrayType:
|
||||||
// https://github.com/neo-project/neo/blob/3d59ecca5a8deb057bdad94b3028a6d5e25ac088/neo/Network/RPC/RpcServer.cs#L67
|
// https://github.com/neo-project/neo/blob/3d59ecca5a8deb057bdad94b3028a6d5e25ac088/neo/Network/RPC/RpcServer.cs#L67
|
||||||
var rs []Parameter
|
var rs []Parameter
|
||||||
|
@ -190,87 +194,6 @@ func (p *Parameter) UnmarshalJSON(data []byte) (err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// EncodeBinary implements io.Serializable interface.
|
|
||||||
func (p *Parameter) EncodeBinary(w *io.BinWriter) {
|
|
||||||
w.WriteB(byte(p.Type))
|
|
||||||
switch p.Type {
|
|
||||||
case BoolType:
|
|
||||||
w.WriteBool(p.Value.(bool))
|
|
||||||
case ByteArrayType, PublicKeyType, SignatureType:
|
|
||||||
if p.Value == nil {
|
|
||||||
w.WriteVarUint(math.MaxUint64)
|
|
||||||
} else {
|
|
||||||
w.WriteVarBytes(p.Value.([]byte))
|
|
||||||
}
|
|
||||||
case StringType:
|
|
||||||
w.WriteString(p.Value.(string))
|
|
||||||
case IntegerType:
|
|
||||||
w.WriteU64LE(uint64(p.Value.(int64)))
|
|
||||||
case ArrayType:
|
|
||||||
w.WriteArray(p.Value.([]Parameter))
|
|
||||||
case MapType:
|
|
||||||
w.WriteArray(p.Value.([]ParameterPair))
|
|
||||||
case Hash160Type:
|
|
||||||
w.WriteBytes(p.Value.(util.Uint160).BytesBE())
|
|
||||||
case Hash256Type:
|
|
||||||
w.WriteBytes(p.Value.(util.Uint256).BytesBE())
|
|
||||||
case InteropInterfaceType, AnyType:
|
|
||||||
default:
|
|
||||||
w.Err = fmt.Errorf("unknown type: %x", p.Type)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// DecodeBinary implements io.Serializable interface.
|
|
||||||
func (p *Parameter) DecodeBinary(r *io.BinReader) {
|
|
||||||
p.Type = ParamType(r.ReadB())
|
|
||||||
switch p.Type {
|
|
||||||
case BoolType:
|
|
||||||
p.Value = r.ReadBool()
|
|
||||||
case ByteArrayType, PublicKeyType, SignatureType:
|
|
||||||
ln := r.ReadVarUint()
|
|
||||||
if ln != math.MaxUint64 {
|
|
||||||
b := make([]byte, ln)
|
|
||||||
r.ReadBytes(b)
|
|
||||||
p.Value = b
|
|
||||||
}
|
|
||||||
case StringType:
|
|
||||||
p.Value = r.ReadString()
|
|
||||||
case IntegerType:
|
|
||||||
p.Value = int64(r.ReadU64LE())
|
|
||||||
case ArrayType:
|
|
||||||
ps := []Parameter{}
|
|
||||||
r.ReadArray(&ps)
|
|
||||||
p.Value = ps
|
|
||||||
case MapType:
|
|
||||||
ps := []ParameterPair{}
|
|
||||||
r.ReadArray(&ps)
|
|
||||||
p.Value = ps
|
|
||||||
case Hash160Type:
|
|
||||||
var u util.Uint160
|
|
||||||
r.ReadBytes(u[:])
|
|
||||||
p.Value = u
|
|
||||||
case Hash256Type:
|
|
||||||
var u util.Uint256
|
|
||||||
r.ReadBytes(u[:])
|
|
||||||
p.Value = u
|
|
||||||
case InteropInterfaceType, AnyType:
|
|
||||||
default:
|
|
||||||
r.Err = fmt.Errorf("unknown type: %x", p.Type)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// EncodeBinary implements io.Serializable interface.
|
|
||||||
func (p *ParameterPair) EncodeBinary(w *io.BinWriter) {
|
|
||||||
p.Key.EncodeBinary(w)
|
|
||||||
p.Value.EncodeBinary(w)
|
|
||||||
}
|
|
||||||
|
|
||||||
// DecodeBinary implements io.Serializable interface.
|
|
||||||
func (p *ParameterPair) DecodeBinary(r *io.BinReader) {
|
|
||||||
p.Key.DecodeBinary(r)
|
|
||||||
p.Value.DecodeBinary(r)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Params is an array of Parameter (TODO: drop it?).
|
// Params is an array of Parameter (TODO: drop it?).
|
||||||
type Params []Parameter
|
type Params []Parameter
|
||||||
|
|
||||||
|
@ -318,6 +241,9 @@ func (p Parameter) TryParse(dest interface{}) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
case **big.Int:
|
||||||
|
*dest = bigint.FromBytes(data)
|
||||||
|
return nil
|
||||||
case *int64, *int32, *int16, *int8, *int, *uint64, *uint32, *uint16, *uint8, *uint:
|
case *int64, *int32, *int16, *int8, *int, *uint64, *uint32, *uint16, *uint8, *uint:
|
||||||
var size int
|
var size int
|
||||||
switch dest.(type) {
|
switch dest.(type) {
|
||||||
|
|
|
@ -5,10 +5,11 @@ import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"math"
|
"math"
|
||||||
|
"math/big"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/internal/testserdes"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/io"
|
"github.com/nspcc-dev/neo-go/pkg/io"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
|
@ -22,9 +23,13 @@ var marshalJSONTestCases = []struct {
|
||||||
result string
|
result string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
input: Parameter{Type: IntegerType, Value: int64(12345)},
|
input: Parameter{Type: IntegerType, Value: big.NewInt(12345)},
|
||||||
result: `{"type":"Integer","value":12345}`,
|
result: `{"type":"Integer","value":12345}`,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
input: Parameter{Type: IntegerType, Value: new(big.Int).Lsh(big.NewInt(1), 254)},
|
||||||
|
result: `{"type":"Integer","value":"` + new(big.Int).Lsh(big.NewInt(1), 254).String() + `"}`,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
input: Parameter{Type: StringType, Value: "Some string"},
|
input: Parameter{Type: StringType, Value: "Some string"},
|
||||||
result: `{"type":"String","value":"Some string"}`,
|
result: `{"type":"String","value":"Some string"}`,
|
||||||
|
@ -57,7 +62,7 @@ var marshalJSONTestCases = []struct {
|
||||||
Type: ArrayType,
|
Type: ArrayType,
|
||||||
Value: []Parameter{
|
Value: []Parameter{
|
||||||
{Type: StringType, Value: "str 1"},
|
{Type: StringType, Value: "str 1"},
|
||||||
{Type: IntegerType, Value: int64(2)},
|
{Type: IntegerType, Value: big.NewInt(2)},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
result: `{"type":"Array","value":[{"type":"String","value":"str 1"},{"type":"Integer","value":2}]}`,
|
result: `{"type":"Array","value":[{"type":"String","value":"str 1"},{"type":"Integer","value":2}]}`,
|
||||||
|
@ -84,7 +89,7 @@ var marshalJSONTestCases = []struct {
|
||||||
Value: []ParameterPair{
|
Value: []ParameterPair{
|
||||||
{
|
{
|
||||||
Key: Parameter{Type: StringType, Value: "key1"},
|
Key: Parameter{Type: StringType, Value: "key1"},
|
||||||
Value: Parameter{Type: IntegerType, Value: int64(1)},
|
Value: Parameter{Type: IntegerType, Value: big.NewInt(1)},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Key: Parameter{Type: StringType, Value: "key2"},
|
Key: Parameter{Type: StringType, Value: "key2"},
|
||||||
|
@ -102,7 +107,7 @@ var marshalJSONTestCases = []struct {
|
||||||
Key: Parameter{Type: StringType, Value: "key1"},
|
Key: Parameter{Type: StringType, Value: "key1"},
|
||||||
Value: Parameter{Type: ArrayType, Value: []Parameter{
|
Value: Parameter{Type: ArrayType, Value: []Parameter{
|
||||||
{Type: StringType, Value: "str 1"},
|
{Type: StringType, Value: "str 1"},
|
||||||
{Type: IntegerType, Value: int64(2)},
|
{Type: IntegerType, Value: big.NewInt(2)},
|
||||||
}},
|
}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -185,11 +190,11 @@ var unmarshalJSONTestCases = []struct {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: `{"type":"Integer","value":12345}`,
|
input: `{"type":"Integer","value":12345}`,
|
||||||
result: Parameter{Type: IntegerType, Value: int64(12345)},
|
result: Parameter{Type: IntegerType, Value: big.NewInt(12345)},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: `{"type":"Integer","value":"12345"}`,
|
input: `{"type":"Integer","value":"12345"}`,
|
||||||
result: Parameter{Type: IntegerType, Value: int64(12345)},
|
result: Parameter{Type: IntegerType, Value: big.NewInt(12345)},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: `{"type":"ByteString","value":"` + hexToBase64("010203") + `"}`,
|
input: `{"type":"ByteString","value":"` + hexToBase64("010203") + `"}`,
|
||||||
|
@ -215,7 +220,7 @@ var unmarshalJSONTestCases = []struct {
|
||||||
Type: ArrayType,
|
Type: ArrayType,
|
||||||
Value: []Parameter{
|
Value: []Parameter{
|
||||||
{Type: StringType, Value: "str 1"},
|
{Type: StringType, Value: "str 1"},
|
||||||
{Type: IntegerType, Value: int64(2)},
|
{Type: IntegerType, Value: big.NewInt(2)},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -248,7 +253,7 @@ var unmarshalJSONTestCases = []struct {
|
||||||
Value: []ParameterPair{
|
Value: []ParameterPair{
|
||||||
{
|
{
|
||||||
Key: Parameter{Type: StringType, Value: "key1"},
|
Key: Parameter{Type: StringType, Value: "key1"},
|
||||||
Value: Parameter{Type: IntegerType, Value: int64(1)},
|
Value: Parameter{Type: IntegerType, Value: big.NewInt(1)},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Key: Parameter{Type: StringType, Value: "key2"},
|
Key: Parameter{Type: StringType, Value: "key2"},
|
||||||
|
@ -266,7 +271,7 @@ var unmarshalJSONTestCases = []struct {
|
||||||
Key: Parameter{Type: StringType, Value: "key1"},
|
Key: Parameter{Type: StringType, Value: "key1"},
|
||||||
Value: Parameter{Type: ArrayType, Value: []Parameter{
|
Value: Parameter{Type: ArrayType, Value: []Parameter{
|
||||||
{Type: StringType, Value: "str 1"},
|
{Type: StringType, Value: "str 1"},
|
||||||
{Type: IntegerType, Value: int64(2)},
|
{Type: IntegerType, Value: big.NewInt(2)},
|
||||||
}},
|
}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -310,6 +315,8 @@ var unmarshalJSONErrorCases = []string{
|
||||||
`{"type": "String","value":1}`, // incorrect Value
|
`{"type": "String","value":1}`, // incorrect Value
|
||||||
`{"type": "Integer","value": "nn"}`, // incorrect Integer value
|
`{"type": "Integer","value": "nn"}`, // incorrect Integer value
|
||||||
`{"type": "Integer","value": []}`, // incorrect Integer value
|
`{"type": "Integer","value": []}`, // incorrect Integer value
|
||||||
|
`{"type": "Integer","value":"` +
|
||||||
|
strings.Repeat("9", 100) + `"}`, // too big Integer
|
||||||
`{"type": "Array","value": 123}`, // incorrect Array value
|
`{"type": "Array","value": 123}`, // incorrect Array value
|
||||||
`{"type": "Hash160","value": "0bcd"}`, // incorrect Uint160 value
|
`{"type": "Hash160","value": "0bcd"}`, // incorrect Uint160 value
|
||||||
`{"type": "Hash256","value": "0bcd"}`, // incorrect Uint256 value
|
`{"type": "Hash256","value": "0bcd"}`, // incorrect Uint256 value
|
||||||
|
@ -330,7 +337,7 @@ func TestParam_UnmarshalJSON(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, input := range unmarshalJSONErrorCases {
|
for _, input := range unmarshalJSONErrorCases {
|
||||||
assert.Error(t, json.Unmarshal([]byte(input), &s))
|
assert.Error(t, json.Unmarshal([]byte(input), &s), input)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -370,6 +377,10 @@ var tryParseTestCases = []struct {
|
||||||
input: []byte{0x63, 0x78, 0x29, 0xcd, 0x0b},
|
input: []byte{0x63, 0x78, 0x29, 0xcd, 0x0b},
|
||||||
expected: int64(50686687331),
|
expected: int64(50686687331),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
input: []byte{0x63, 0x78, 0x29, 0xcd, 0x0b},
|
||||||
|
expected: big.NewInt(50686687331),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
input: []byte("this is a test string"),
|
input: []byte("this is a test string"),
|
||||||
expected: "this is a test string",
|
expected: "this is a test string",
|
||||||
|
@ -450,13 +461,13 @@ func TestNewParameterFromString(t *testing.T) {
|
||||||
out: Parameter{StringType, "qwerty"},
|
out: Parameter{StringType, "qwerty"},
|
||||||
}, {
|
}, {
|
||||||
in: "42",
|
in: "42",
|
||||||
out: Parameter{IntegerType, int64(42)},
|
out: Parameter{IntegerType, big.NewInt(42)},
|
||||||
}, {
|
}, {
|
||||||
in: "Hello, 世界",
|
in: "Hello, 世界",
|
||||||
out: Parameter{StringType, "Hello, 世界"},
|
out: Parameter{StringType, "Hello, 世界"},
|
||||||
}, {
|
}, {
|
||||||
in: `\4\2`,
|
in: `\4\2`,
|
||||||
out: Parameter{IntegerType, int64(42)},
|
out: Parameter{IntegerType, big.NewInt(42)},
|
||||||
}, {
|
}, {
|
||||||
in: `\\4\2`,
|
in: `\\4\2`,
|
||||||
out: Parameter{StringType, `\42`},
|
out: Parameter{StringType, `\42`},
|
||||||
|
@ -465,7 +476,7 @@ func TestNewParameterFromString(t *testing.T) {
|
||||||
out: Parameter{StringType, `\42`},
|
out: Parameter{StringType, `\42`},
|
||||||
}, {
|
}, {
|
||||||
in: "int:42",
|
in: "int:42",
|
||||||
out: Parameter{IntegerType, int64(42)},
|
out: Parameter{IntegerType, big.NewInt(42)},
|
||||||
}, {
|
}, {
|
||||||
in: "true",
|
in: "true",
|
||||||
out: Parameter{BoolType, true},
|
out: Parameter{BoolType, true},
|
||||||
|
@ -514,20 +525,6 @@ func TestNewParameterFromString(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestEncodeDecodeBinary(t *testing.T) {
|
|
||||||
for _, tc := range marshalJSONTestCases {
|
|
||||||
testserdes.EncodeDecodeBinary(t, &tc.input, new(Parameter))
|
|
||||||
}
|
|
||||||
|
|
||||||
t.Run("unknown", func(t *testing.T) {
|
|
||||||
p := Parameter{Type: UnknownType}
|
|
||||||
_, err := testserdes.EncodeBinary(&p)
|
|
||||||
require.Error(t, err)
|
|
||||||
|
|
||||||
require.Error(t, testserdes.DecodeBinary([]byte{0xAA}, &p))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func hexToBase64(s string) string {
|
func hexToBase64(s string) string {
|
||||||
b, _ := hex.DecodeString(s)
|
b, _ := hex.DecodeString(s)
|
||||||
return base64.StdEncoding.EncodeToString(b)
|
return base64.StdEncoding.EncodeToString(b)
|
||||||
|
@ -544,8 +541,8 @@ func TestExpandParameterToEmitable(t *testing.T) {
|
||||||
Expected: true,
|
Expected: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
In: Parameter{Type: IntegerType, Value: int64(123)},
|
In: Parameter{Type: IntegerType, Value: big.NewInt(123)},
|
||||||
Expected: int64(123),
|
Expected: big.NewInt(123),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
In: Parameter{Type: ByteArrayType, Value: []byte{1, 2, 3}},
|
In: Parameter{Type: ByteArrayType, Value: []byte{1, 2, 3}},
|
||||||
|
@ -575,7 +572,7 @@ func TestExpandParameterToEmitable(t *testing.T) {
|
||||||
In: Parameter{Type: ArrayType, Value: []Parameter{
|
In: Parameter{Type: ArrayType, Value: []Parameter{
|
||||||
{
|
{
|
||||||
Type: IntegerType,
|
Type: IntegerType,
|
||||||
Value: int64(123),
|
Value: big.NewInt(123),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Type: ByteArrayType,
|
Type: ByteArrayType,
|
||||||
|
@ -591,7 +588,7 @@ func TestExpandParameterToEmitable(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}},
|
}},
|
||||||
Expected: []interface{}{int64(123), []byte{1, 2, 3}, []interface{}{true}},
|
Expected: []interface{}{big.NewInt(123), []byte{1, 2, 3}, []interface{}{true}},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
bw := io.NewBufBinWriter()
|
bw := io.NewBufBinWriter()
|
||||||
|
|
Loading…
Reference in a new issue