mirror of
https://github.com/nspcc-dev/neo-go.git
synced 2025-01-09 11:19:06 +00:00
Merge pull request #3687 from nspcc-dev/extend-smartcontract-conversions
Extend smartcontract type conversions
This commit is contained in:
commit
176593b31f
4 changed files with 89 additions and 65 deletions
|
@ -73,7 +73,7 @@ func GetVarSize(value any) int {
|
||||||
valueSize := 0
|
valueSize := 0
|
||||||
|
|
||||||
if valueLength != 0 {
|
if valueLength != 0 {
|
||||||
switch reflect.ValueOf(value).Index(0).Interface().(type) {
|
switch v.Index(0).Interface().(type) {
|
||||||
case Serializable:
|
case Serializable:
|
||||||
for i := range valueLength {
|
for i := range valueLength {
|
||||||
valueSize += GetVarSize(v.Index(i).Interface())
|
valueSize += GetVarSize(v.Index(i).Interface())
|
||||||
|
|
|
@ -83,17 +83,17 @@ func TestInvoker(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, resExp, res)
|
require.Equal(t, resExp, res)
|
||||||
|
|
||||||
_, err = inv.Verify(util.Uint160{}, nil, make(map[int]int))
|
_, err = inv.Verify(util.Uint160{}, nil, make(chan struct{}))
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
|
|
||||||
_, err = inv.Call(util.Uint160{}, "method", make(map[int]int))
|
_, err = inv.Call(util.Uint160{}, "method", make(chan struct{}))
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
|
|
||||||
res, err = inv.CallAndExpandIterator(util.Uint160{}, "method", 10, 42)
|
res, err = inv.CallAndExpandIterator(util.Uint160{}, "method", 10, 42)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, resExp, res)
|
require.Equal(t, resExp, res)
|
||||||
|
|
||||||
_, err = inv.CallAndExpandIterator(util.Uint160{}, "method", 10, make(map[int]int))
|
_, err = inv.CallAndExpandIterator(util.Uint160{}, "method", 10, make(chan struct{}))
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
}
|
}
|
||||||
t.Run("standard", func(t *testing.T) {
|
t.Run("standard", func(t *testing.T) {
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
"os"
|
"os"
|
||||||
|
"reflect"
|
||||||
"slices"
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
|
@ -265,7 +266,7 @@ func NewParameterFromString(in string) (*Parameter, error) {
|
||||||
// NewParameterFromValue infers Parameter type from the value given and adjusts
|
// NewParameterFromValue infers Parameter type from the value given and adjusts
|
||||||
// the value if needed. It does not copy the value if it can avoid doing so. All
|
// the value if needed. It does not copy the value if it can avoid doing so. All
|
||||||
// regular integers, util.*, keys.PublicKey*, string and bool types are supported,
|
// regular integers, util.*, keys.PublicKey*, string and bool types are supported,
|
||||||
// slice of byte slices is accepted and converted as well. [errors.ErrUnsupported]
|
// slices of various kinds are converted as well. [errors.ErrUnsupported]
|
||||||
// will be returned for types that can't be used now.
|
// will be returned for types that can't be used now.
|
||||||
func NewParameterFromValue(value any) (Parameter, error) {
|
func NewParameterFromValue(value any) (Parameter, error) {
|
||||||
var result = Parameter{
|
var result = Parameter{
|
||||||
|
@ -345,69 +346,46 @@ func NewParameterFromValue(value any) (Parameter, error) {
|
||||||
case []Parameter:
|
case []Parameter:
|
||||||
result.Type = ArrayType
|
result.Type = ArrayType
|
||||||
result.Value = slices.Clone(v)
|
result.Value = slices.Clone(v)
|
||||||
case [][]byte:
|
|
||||||
return newArrayParameter(v)
|
|
||||||
case []string:
|
|
||||||
return newArrayParameter(v)
|
|
||||||
case []bool:
|
|
||||||
return newArrayParameter(v)
|
|
||||||
case []*big.Int:
|
|
||||||
return newArrayParameter(v)
|
|
||||||
case []int8:
|
|
||||||
return newArrayParameter(v)
|
|
||||||
case []int16:
|
|
||||||
return newArrayParameter(v)
|
|
||||||
case []uint16:
|
|
||||||
return newArrayParameter(v)
|
|
||||||
case []int32:
|
|
||||||
return newArrayParameter(v)
|
|
||||||
case []uint32:
|
|
||||||
return newArrayParameter(v)
|
|
||||||
case []int:
|
|
||||||
return newArrayParameter(v)
|
|
||||||
case []uint:
|
|
||||||
return newArrayParameter(v)
|
|
||||||
case []int64:
|
|
||||||
return newArrayParameter(v)
|
|
||||||
case []uint64:
|
|
||||||
return newArrayParameter(v)
|
|
||||||
case []*Parameter:
|
|
||||||
return newArrayParameter(v)
|
|
||||||
case []Convertible:
|
|
||||||
return newArrayParameter(v)
|
|
||||||
case []util.Uint160:
|
|
||||||
return newArrayParameter(v)
|
|
||||||
case []util.Uint256:
|
|
||||||
return newArrayParameter(v)
|
|
||||||
case []*util.Uint160:
|
|
||||||
return newArrayParameter(v)
|
|
||||||
case []*util.Uint256:
|
|
||||||
return newArrayParameter(v)
|
|
||||||
case []keys.PublicKey:
|
|
||||||
return newArrayParameter(v)
|
|
||||||
case []*keys.PublicKey:
|
|
||||||
return newArrayParameter(v)
|
|
||||||
case keys.PublicKeys:
|
|
||||||
return newArrayParameter(v)
|
|
||||||
case []any:
|
|
||||||
return newArrayParameter(v)
|
|
||||||
case nil:
|
case nil:
|
||||||
result.Type = AnyType
|
result.Type = AnyType
|
||||||
default:
|
default:
|
||||||
return result, fmt.Errorf("%w: %T type", errors.ErrUnsupported, value)
|
rv := reflect.ValueOf(value)
|
||||||
|
switch rv.Kind() {
|
||||||
|
case reflect.Slice, reflect.Array:
|
||||||
|
res := make([]Parameter, 0, rv.Len())
|
||||||
|
for i := range rv.Len() {
|
||||||
|
elem, err := NewParameterFromValue(rv.Index(i).Interface())
|
||||||
|
if err != nil {
|
||||||
|
return result, fmt.Errorf("array index %d: %w", i, err)
|
||||||
|
}
|
||||||
|
res = append(res, elem)
|
||||||
|
}
|
||||||
|
result.Type = ArrayType
|
||||||
|
result.Value = res
|
||||||
|
case reflect.Map:
|
||||||
|
res := make([]ParameterPair, 0, rv.Len())
|
||||||
|
iter := rv.MapRange()
|
||||||
|
for iter.Next() {
|
||||||
|
k, err := NewParameterFromValue(iter.Key().Interface())
|
||||||
|
if err != nil {
|
||||||
|
return result, fmt.Errorf("map key: %w", err)
|
||||||
|
}
|
||||||
|
v, err := NewParameterFromValue(iter.Value().Interface())
|
||||||
|
if err != nil {
|
||||||
|
return result, fmt.Errorf("map value: %w", err)
|
||||||
|
}
|
||||||
|
res = append(res, ParameterPair{Key: k, Value: v})
|
||||||
|
}
|
||||||
|
result.Type = MapType
|
||||||
|
result.Value = res
|
||||||
|
default:
|
||||||
|
return result, fmt.Errorf("%w: %T type", errors.ErrUnsupported, value)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func newArrayParameter[E any, S ~[]E](values S) (Parameter, error) {
|
|
||||||
arr, err := newArrayOfParameters(values)
|
|
||||||
if err != nil {
|
|
||||||
return Parameter{}, err
|
|
||||||
}
|
|
||||||
return Parameter{Type: ArrayType, Value: arr}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func newArrayOfParameters[E any, S ~[]E](values S) ([]Parameter, error) {
|
func newArrayOfParameters[E any, S ~[]E](values S) ([]Parameter, error) {
|
||||||
res := make([]Parameter, 0, len(values))
|
res := make([]Parameter, 0, len(values))
|
||||||
for i := range values {
|
for i := range values {
|
||||||
|
|
|
@ -887,12 +887,58 @@ func TestParameterFromValue(t *testing.T) {
|
||||||
err: "invalid i value",
|
err: "invalid i value",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: make(map[string]int),
|
value: make(map[string]int),
|
||||||
err: "unsupported operation: map[string]int type",
|
expType: MapType,
|
||||||
|
expVal: []ParameterPair{},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: []any{1, 2, make(map[string]int)},
|
value: make(map[string]int),
|
||||||
err: "unsupported operation: map[string]int type",
|
expType: MapType,
|
||||||
|
expVal: []ParameterPair{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: map[string]string{"key": "value"},
|
||||||
|
expType: MapType,
|
||||||
|
expVal: []ParameterPair{{
|
||||||
|
Key: Parameter{
|
||||||
|
Type: StringType,
|
||||||
|
Value: "key",
|
||||||
|
},
|
||||||
|
Value: Parameter{
|
||||||
|
Type: StringType,
|
||||||
|
Value: "value",
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: map[int]int64{42: 100500},
|
||||||
|
expType: MapType,
|
||||||
|
expVal: []ParameterPair{{
|
||||||
|
Key: Parameter{
|
||||||
|
Type: IntegerType,
|
||||||
|
Value: big.NewInt(42),
|
||||||
|
},
|
||||||
|
Value: Parameter{
|
||||||
|
Type: IntegerType,
|
||||||
|
Value: big.NewInt(100500),
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: make(chan int),
|
||||||
|
err: "unsupported operation: chan int type",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: []any{1, 2, make(chan int)},
|
||||||
|
err: "unsupported operation: chan int type",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: map[string]chan int{"aaa": make(chan int)},
|
||||||
|
err: "unsupported operation: chan int type",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: map[error]string{errors.New("some"): "value"},
|
||||||
|
err: "unsupported operation: *errors.errorString type",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -924,6 +970,6 @@ func TestParametersFromValues(t *testing.T) {
|
||||||
Type: ByteArrayType,
|
Type: ByteArrayType,
|
||||||
Value: []byte{3, 2, 1},
|
Value: []byte{3, 2, 1},
|
||||||
}}, res)
|
}}, res)
|
||||||
_, err = NewParametersFromValues(42, make(map[int]int), []byte{3, 2, 1})
|
_, err = NewParametersFromValues(42, make(chan int), []byte{3, 2, 1})
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue