From db2956f1af33eeb6f0482b8491e2e486ec46c227 Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Fri, 15 Nov 2024 22:51:35 +0300 Subject: [PATCH] smartcontract: add support for maps in NewParameterFromValue It's just not possible to use maps in invokers/actors without this. And maps have too many combinations to try pushing them into a type switch, that's where reflection kicks in and solves it easily. Signed-off-by: Roman Khimov --- pkg/rpcclient/invoker/invoker_test.go | 6 +-- pkg/smartcontract/parameter.go | 16 ++++++++ pkg/smartcontract/parameter_test.go | 56 ++++++++++++++++++++++++--- 3 files changed, 70 insertions(+), 8 deletions(-) diff --git a/pkg/rpcclient/invoker/invoker_test.go b/pkg/rpcclient/invoker/invoker_test.go index 39b21bcaf..699a99fab 100644 --- a/pkg/rpcclient/invoker/invoker_test.go +++ b/pkg/rpcclient/invoker/invoker_test.go @@ -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) { diff --git a/pkg/smartcontract/parameter.go b/pkg/smartcontract/parameter.go index f5bad5277..c24c09c75 100644 --- a/pkg/smartcontract/parameter.go +++ b/pkg/smartcontract/parameter.go @@ -362,6 +362,22 @@ func NewParameterFromValue(value any) (Parameter, error) { } 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) } diff --git a/pkg/smartcontract/parameter_test.go b/pkg/smartcontract/parameter_test.go index 865dd7919..7afb7b3f4 100644 --- a/pkg/smartcontract/parameter_test.go +++ b/pkg/smartcontract/parameter_test.go @@ -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", }, } @@ -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) }