smartcontract: introduce Convertible interface

Allow to pass Convertible to NewParameterFromValue. Close #3285.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
This commit is contained in:
Anna Shaleva 2024-01-23 14:47:07 +03:00
parent ef99a7a9e3
commit b90c0ece87
2 changed files with 63 additions and 3 deletions

View file

@ -25,6 +25,11 @@ type Parameter struct {
Value any `json:"value"` Value any `json:"value"`
} }
// Convertible is something that can be converted to Parameter.
type Convertible interface {
ToSCParameter() (Parameter, error)
}
// ParameterPair represents a key-value pair, a slice of which is stored in // ParameterPair represents a key-value pair, a slice of which is stored in
// MapType Parameter. // MapType Parameter.
type ParameterPair struct { type ParameterPair struct {
@ -307,6 +312,12 @@ func NewParameterFromValue(value any) (Parameter, error) {
result = *v result = *v
case Parameter: case Parameter:
result = v result = v
case Convertible:
var err error
result, err = v.ToSCParameter()
if err != nil {
return result, fmt.Errorf("failed to convert smartcontract.Convertible (%T) to Parameter: %w", v, err)
}
case util.Uint160: case util.Uint160:
result.Type = Hash160Type result.Type = Hash160Type
case util.Uint256: case util.Uint256:

View file

@ -4,6 +4,7 @@ import (
"encoding/base64" "encoding/base64"
"encoding/hex" "encoding/hex"
"encoding/json" "encoding/json"
"errors"
"math" "math"
"math/big" "math/big"
"strings" "strings"
@ -554,6 +555,25 @@ func TestExpandParameterToEmitableToStackitem(t *testing.T) {
} }
} }
// testConvertible implements Convertible interface and needed for NewParameterFromValue
// test.
type testConvertible struct {
i int
err string
}
var _ = Convertible(testConvertible{})
func (c testConvertible) ToSCParameter() (Parameter, error) {
if c.err != "" {
return Parameter{}, errors.New(c.err)
}
return Parameter{
Type: IntegerType,
Value: c.i,
}, nil
}
func TestParameterFromValue(t *testing.T) { func TestParameterFromValue(t *testing.T) {
pk1, _ := keys.NewPrivateKey() pk1, _ := keys.NewPrivateKey()
pk2, _ := keys.NewPrivateKey() pk2, _ := keys.NewPrivateKey()
@ -561,6 +581,7 @@ func TestParameterFromValue(t *testing.T) {
value any value any
expType ParamType expType ParamType
expVal any expVal any
err string // expected error substring
}{ }{
{ {
value: []byte{1, 2, 3}, value: []byte{1, 2, 3},
@ -741,14 +762,42 @@ func TestParameterFromValue(t *testing.T) {
Value: []byte{1, 2, 3}, Value: []byte{1, 2, 3},
}}, }},
}, },
{
value: testConvertible{i: 123},
expType: IntegerType,
expVal: 123,
},
{
value: []any{1, testConvertible{i: 123}},
expType: ArrayType,
expVal: []Parameter{
{
Type: IntegerType,
Value: big.NewInt(1),
},
{
Type: IntegerType,
Value: 123,
},
},
},
{
value: testConvertible{err: "invalid i value"},
err: "invalid i value",
},
} }
for _, item := range items { for _, item := range items {
t.Run(item.expType.String()+" to stack parameter", func(t *testing.T) { t.Run(item.expType.String()+" to stack parameter", func(t *testing.T) {
res, err := NewParameterFromValue(item.value) res, err := NewParameterFromValue(item.value)
if item.err != "" {
require.Error(t, err)
require.Contains(t, err.Error(), item.err)
} else {
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, item.expType, res.Type) require.Equal(t, item.expType, res.Type)
require.Equal(t, item.expVal, res.Value) require.Equal(t, item.expVal, res.Value)
}
}) })
} }
_, err := NewParameterFromValue(make(map[string]int)) _, err := NewParameterFromValue(make(map[string]int))