Skip to content

Commit

Permalink
Merge pull request #3687 from nspcc-dev/extend-smartcontract-conversions
Browse files Browse the repository at this point in the history
Extend smartcontract type conversions
  • Loading branch information
AnnaShaleva authored Nov 18, 2024
2 parents 990634a + db2956f commit 176593b
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 65 deletions.
2 changes: 1 addition & 1 deletion pkg/io/size.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ func GetVarSize(value any) int {
valueSize := 0

if valueLength != 0 {
switch reflect.ValueOf(value).Index(0).Interface().(type) {
switch v.Index(0).Interface().(type) {
case Serializable:
for i := range valueLength {
valueSize += GetVarSize(v.Index(i).Interface())
Expand Down
6 changes: 3 additions & 3 deletions pkg/rpcclient/invoker/invoker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,17 +83,17 @@ func TestInvoker(t *testing.T) {
require.NoError(t, err)
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)

_, err = inv.Call(util.Uint160{}, "method", make(map[int]int))
_, err = inv.Call(util.Uint160{}, "method", make(chan struct{}))
require.Error(t, err)

res, err = inv.CallAndExpandIterator(util.Uint160{}, "method", 10, 42)
require.NoError(t, err)
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)
}
t.Run("standard", func(t *testing.T) {
Expand Down
90 changes: 34 additions & 56 deletions pkg/smartcontract/parameter.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"fmt"
"math/big"
"os"
"reflect"
"slices"
"strings"
"unicode/utf8"
Expand Down Expand Up @@ -265,7 +266,7 @@ func NewParameterFromString(in string) (*Parameter, error) {
// 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
// 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.
func NewParameterFromValue(value any) (Parameter, error) {
var result = Parameter{
Expand Down Expand Up @@ -345,69 +346,46 @@ func NewParameterFromValue(value any) (Parameter, error) {
case []Parameter:
result.Type = ArrayType
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:
result.Type = AnyType
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
}

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) {
res := make([]Parameter, 0, len(values))
for i := range values {
Expand Down
56 changes: 51 additions & 5 deletions pkg/smartcontract/parameter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -887,12 +887,58 @@ func TestParameterFromValue(t *testing.T) {
err: "invalid i value",
},
{
value: make(map[string]int),
err: "unsupported operation: map[string]int type",
value: make(map[string]int),
expType: MapType,
expVal: []ParameterPair{},
},
{
value: []any{1, 2, make(map[string]int)},
err: "unsupported operation: map[string]int type",
value: make(map[string]int),
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",
},
}

Expand Down Expand Up @@ -924,6 +970,6 @@ func TestParametersFromValues(t *testing.T) {
Type: ByteArrayType,
Value: []byte{3, 2, 1},
}}, 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)
}

0 comments on commit 176593b

Please sign in to comment.