github.com/nspcc-dev/neo-go@v0.105.2-0.20240517133400-6be757af3eba/pkg/smartcontract/parameter_test.go (about)

     1  package smartcontract
     2  
     3  import (
     4  	"encoding/base64"
     5  	"encoding/hex"
     6  	"encoding/json"
     7  	"errors"
     8  	"math"
     9  	"math/big"
    10  	"strings"
    11  	"testing"
    12  
    13  	"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
    14  
    15  	"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
    16  	"github.com/nspcc-dev/neo-go/pkg/io"
    17  	"github.com/nspcc-dev/neo-go/pkg/util"
    18  	"github.com/nspcc-dev/neo-go/pkg/vm/emit"
    19  	"github.com/stretchr/testify/assert"
    20  	"github.com/stretchr/testify/require"
    21  )
    22  
    23  var marshalJSONTestCases = []struct {
    24  	input  Parameter
    25  	result string
    26  }{
    27  	{
    28  		input:  Parameter{Type: IntegerType, Value: big.NewInt(12345)},
    29  		result: `{"type":"Integer","value":12345}`,
    30  	},
    31  	{
    32  		input:  Parameter{Type: IntegerType, Value: new(big.Int).Lsh(big.NewInt(1), 254)},
    33  		result: `{"type":"Integer","value":"` + new(big.Int).Lsh(big.NewInt(1), 254).String() + `"}`,
    34  	},
    35  	{
    36  		input:  Parameter{Type: StringType, Value: "Some string"},
    37  		result: `{"type":"String","value":"Some string"}`,
    38  	},
    39  	{
    40  		input:  Parameter{Type: BoolType, Value: true},
    41  		result: `{"type":"Boolean","value":true}`,
    42  	},
    43  	{
    44  		input:  Parameter{Type: ByteArrayType, Value: []byte{0x01, 0x02, 0x03}},
    45  		result: `{"type":"ByteString","value":"` + hexToBase64("010203") + `"}`,
    46  	},
    47  	{
    48  		input:  Parameter{Type: ByteArrayType},
    49  		result: `{"type":"ByteString","value":null}`,
    50  	},
    51  	{
    52  		input:  Parameter{Type: SignatureType},
    53  		result: `{"type":"Signature"}`,
    54  	},
    55  	{
    56  		input: Parameter{
    57  			Type:  PublicKeyType,
    58  			Value: []byte{0x03, 0xb3, 0xbf, 0x15, 0x02, 0xfb, 0xdc, 0x05, 0x44, 0x9b, 0x50, 0x6a, 0xaf, 0x04, 0x57, 0x97, 0x24, 0x02, 0x4b, 0x06, 0x54, 0x2e, 0x49, 0x26, 0x2b, 0xfa, 0xa3, 0xf7, 0x0e, 0x20, 0x00, 0x40, 0xa9},
    59  		},
    60  		result: `{"type":"PublicKey","value":"03b3bf1502fbdc05449b506aaf04579724024b06542e49262bfaa3f70e200040a9"}`,
    61  	},
    62  	{
    63  		input: Parameter{
    64  			Type: ArrayType,
    65  			Value: []Parameter{
    66  				{Type: StringType, Value: "str 1"},
    67  				{Type: IntegerType, Value: big.NewInt(2)},
    68  			},
    69  		},
    70  		result: `{"type":"Array","value":[{"type":"String","value":"str 1"},{"type":"Integer","value":2}]}`,
    71  	},
    72  	{
    73  		input: Parameter{
    74  			Type: ArrayType,
    75  			Value: []Parameter{
    76  				{Type: ByteArrayType, Value: []byte{1, 2}},
    77  				{
    78  					Type: ArrayType,
    79  					Value: []Parameter{
    80  						{Type: ByteArrayType, Value: []byte{3, 2, 1}},
    81  						{Type: ByteArrayType, Value: []byte{7, 8, 9}},
    82  					}},
    83  			},
    84  		},
    85  		result: `{"type":"Array","value":[{"type":"ByteString","value":"` + hexToBase64("0102") + `"},{"type":"Array","value":[` +
    86  			`{"type":"ByteString","value":"` + hexToBase64("030201") + `"},{"type":"ByteString","value":"` + hexToBase64("070809") + `"}]}]}`,
    87  	},
    88  	{
    89  		input: Parameter{
    90  			Type: MapType,
    91  			Value: []ParameterPair{
    92  				{
    93  					Key:   Parameter{Type: StringType, Value: "key1"},
    94  					Value: Parameter{Type: IntegerType, Value: big.NewInt(1)},
    95  				},
    96  				{
    97  					Key:   Parameter{Type: StringType, Value: "key2"},
    98  					Value: Parameter{Type: StringType, Value: "two"},
    99  				},
   100  			},
   101  		},
   102  		result: `{"type":"Map","value":[{"key":{"type":"String","value":"key1"},"value":{"type":"Integer","value":1}},{"key":{"type":"String","value":"key2"},"value":{"type":"String","value":"two"}}]}`,
   103  	},
   104  	{
   105  		input: Parameter{
   106  			Type: MapType,
   107  			Value: []ParameterPair{
   108  				{
   109  					Key: Parameter{Type: StringType, Value: "key1"},
   110  					Value: Parameter{Type: ArrayType, Value: []Parameter{
   111  						{Type: StringType, Value: "str 1"},
   112  						{Type: IntegerType, Value: big.NewInt(2)},
   113  					}},
   114  				},
   115  			},
   116  		},
   117  		result: `{"type":"Map","value":[{"key":{"type":"String","value":"key1"},"value":{"type":"Array","value":[{"type":"String","value":"str 1"},{"type":"Integer","value":2}]}}]}`,
   118  	},
   119  	{
   120  		input: Parameter{
   121  			Type: Hash160Type,
   122  			Value: util.Uint160{
   123  				0xd6, 0x24, 0x87, 0x12, 0xff, 0x97, 0x22, 0x80, 0xa0, 0xae,
   124  				0xf5, 0x24, 0x1c, 0x96, 0x4d, 0x63, 0x78, 0x29, 0xcd, 0xb,
   125  			},
   126  		},
   127  		result: `{"type":"Hash160","value":"0x0bcd2978634d961c24f5aea0802297ff128724d6"}`,
   128  	},
   129  	{
   130  		input: Parameter{
   131  			Type: Hash256Type,
   132  			Value: util.Uint256{
   133  				0x2d, 0xf3, 0x45, 0xf2, 0x45, 0xc5, 0x98, 0x9e,
   134  				0x69, 0x95, 0x45, 0x06, 0xa5, 0x9e, 0x40, 0x12,
   135  				0xc1, 0x68, 0x54, 0x48, 0x08, 0xfc, 0xcc, 0x5b,
   136  				0x15, 0x18, 0xab, 0xa0, 0x8f, 0x30, 0x37, 0xf0,
   137  			},
   138  		},
   139  		result: `{"type":"Hash256","value":"0xf037308fa0ab18155bccfc08485468c112409ea5064595699e98c545f245f32d"}`,
   140  	},
   141  	{
   142  		input: Parameter{
   143  			Type:  InteropInterfaceType,
   144  			Value: nil,
   145  		},
   146  		result: `{"type":"InteropInterface","value":null}`,
   147  	},
   148  	{
   149  		input: Parameter{
   150  			Type:  ArrayType,
   151  			Value: []Parameter{},
   152  		},
   153  		result: `{"type":"Array","value":[]}`,
   154  	},
   155  }
   156  
   157  var marshalJSONErrorCases = []Parameter{
   158  	{
   159  		Type:  UnknownType,
   160  		Value: nil,
   161  	},
   162  	{
   163  		Type:  IntegerType,
   164  		Value: math.Inf(1),
   165  	},
   166  }
   167  
   168  func TestParam_MarshalJSON(t *testing.T) {
   169  	for _, tc := range marshalJSONTestCases {
   170  		res, err := json.Marshal(tc.input)
   171  		assert.NoError(t, err)
   172  		var actual, expected Parameter
   173  		assert.NoError(t, json.Unmarshal(res, &actual))
   174  		assert.NoError(t, json.Unmarshal([]byte(tc.result), &expected))
   175  
   176  		assert.Equal(t, expected, actual)
   177  	}
   178  
   179  	for _, input := range marshalJSONErrorCases {
   180  		_, err := json.Marshal(&input)
   181  		assert.Error(t, err)
   182  	}
   183  }
   184  
   185  var unmarshalJSONTestCases = []struct {
   186  	input  string
   187  	result Parameter
   188  }{
   189  	{
   190  		input:  `{"type":"Bool","value":true}`,
   191  		result: Parameter{Type: BoolType, Value: true},
   192  	},
   193  	{
   194  		input:  `{"type":"Integer","value":12345}`,
   195  		result: Parameter{Type: IntegerType, Value: big.NewInt(12345)},
   196  	},
   197  	{
   198  		input:  `{"type":"Integer","value":"12345"}`,
   199  		result: Parameter{Type: IntegerType, Value: big.NewInt(12345)},
   200  	},
   201  	{
   202  		input:  `{"type":"ByteString","value":"` + hexToBase64("010203") + `"}`,
   203  		result: Parameter{Type: ByteArrayType, Value: []byte{0x01, 0x02, 0x03}},
   204  	},
   205  	{
   206  		input:  `{"type":"String","value":"Some string"}`,
   207  		result: Parameter{Type: StringType, Value: "Some string"},
   208  	},
   209  	{
   210  		input:  `{"type":"Signature"}`,
   211  		result: Parameter{Type: SignatureType},
   212  	},
   213  	{
   214  		input:  `{"type":"Signature","value":null }`,
   215  		result: Parameter{Type: SignatureType},
   216  	},
   217  	{
   218  		input: `{"type":"Array","value":[
   219  				{"type": "String", "value": "str 1"},
   220  				{"type": "Integer", "value": 2}]}`,
   221  		result: Parameter{
   222  			Type: ArrayType,
   223  			Value: []Parameter{
   224  				{Type: StringType, Value: "str 1"},
   225  				{Type: IntegerType, Value: big.NewInt(2)},
   226  			},
   227  		},
   228  	},
   229  	{
   230  		input: `{"type": "Hash160", "value": "0bcd2978634d961c24f5aea0802297ff128724d6"}`,
   231  		result: Parameter{
   232  			Type: Hash160Type,
   233  			Value: util.Uint160{
   234  				0xd6, 0x24, 0x87, 0x12, 0xff, 0x97, 0x22, 0x80, 0xa0, 0xae,
   235  				0xf5, 0x24, 0x1c, 0x96, 0x4d, 0x63, 0x78, 0x29, 0xcd, 0xb,
   236  			},
   237  		},
   238  	},
   239  	{
   240  		input: `{"type": "Hash256", "value": "f037308fa0ab18155bccfc08485468c112409ea5064595699e98c545f245f32d"}`,
   241  		result: Parameter{
   242  			Type: Hash256Type,
   243  			Value: util.Uint256{
   244  				0x2d, 0xf3, 0x45, 0xf2, 0x45, 0xc5, 0x98, 0x9e,
   245  				0x69, 0x95, 0x45, 0x06, 0xa5, 0x9e, 0x40, 0x12,
   246  				0xc1, 0x68, 0x54, 0x48, 0x08, 0xfc, 0xcc, 0x5b,
   247  				0x15, 0x18, 0xab, 0xa0, 0x8f, 0x30, 0x37, 0xf0,
   248  			},
   249  		},
   250  	},
   251  	{
   252  		input: `{"type":"Map","value":[{"key":{"type":"String","value":"key1"},"value":{"type":"Integer","value":1}},{"key":{"type":"String","value":"key2"},"value":{"type":"String","value":"two"}}]}`,
   253  		result: Parameter{
   254  			Type: MapType,
   255  			Value: []ParameterPair{
   256  				{
   257  					Key:   Parameter{Type: StringType, Value: "key1"},
   258  					Value: Parameter{Type: IntegerType, Value: big.NewInt(1)},
   259  				},
   260  				{
   261  					Key:   Parameter{Type: StringType, Value: "key2"},
   262  					Value: Parameter{Type: StringType, Value: "two"},
   263  				},
   264  			},
   265  		},
   266  	},
   267  	{
   268  		input: `{"type":"Map","value":[{"key":{"type":"String","value":"key1"},"value":{"type":"Array","value":[{"type":"String","value":"str 1"},{"type":"Integer","value":2}]}}]}`,
   269  		result: Parameter{
   270  			Type: MapType,
   271  			Value: []ParameterPair{
   272  				{
   273  					Key: Parameter{Type: StringType, Value: "key1"},
   274  					Value: Parameter{Type: ArrayType, Value: []Parameter{
   275  						{Type: StringType, Value: "str 1"},
   276  						{Type: IntegerType, Value: big.NewInt(2)},
   277  					}},
   278  				},
   279  			},
   280  		},
   281  	},
   282  	{
   283  		result: Parameter{
   284  			Type:  PublicKeyType,
   285  			Value: []byte{0x03, 0xb3, 0xbf, 0x15, 0x02, 0xfb, 0xdc, 0x05, 0x44, 0x9b, 0x50, 0x6a, 0xaf, 0x04, 0x57, 0x97, 0x24, 0x02, 0x4b, 0x06, 0x54, 0x2e, 0x49, 0x26, 0x2b, 0xfa, 0xa3, 0xf7, 0x0e, 0x20, 0x00, 0x40, 0xa9},
   286  		},
   287  		input: `{"type":"PublicKey","value":"03b3bf1502fbdc05449b506aaf04579724024b06542e49262bfaa3f70e200040a9"}`,
   288  	},
   289  	{
   290  		input: `{"type":"InteropInterface","value":null}`,
   291  		result: Parameter{
   292  			Type:  InteropInterfaceType,
   293  			Value: nil,
   294  		},
   295  	},
   296  	{
   297  		input: `{"type":"InteropInterface","value":""}`,
   298  		result: Parameter{
   299  			Type:  InteropInterfaceType,
   300  			Value: nil,
   301  		},
   302  	},
   303  	{
   304  		input: `{"type":"InteropInterface","value":"Hundertwasser"}`,
   305  		result: Parameter{
   306  			Type:  InteropInterfaceType,
   307  			Value: nil,
   308  		},
   309  	},
   310  }
   311  
   312  var unmarshalJSONErrorCases = []string{
   313  	`{"type": "ByteString","value":`,       // incorrect JSON
   314  	`{"type": "ByteString","value":1}`,     // incorrect Value
   315  	`{"type": "ByteString","value":"12^"}`, // incorrect ByteArray value
   316  	`{"type": "String","value":`,           // incorrect JSON
   317  	`{"type": "String","value":1}`,         // incorrect Value
   318  	`{"type": "Integer","value": "nn"}`,    // incorrect Integer value
   319  	`{"type": "Integer","value": []}`,      // incorrect Integer value
   320  	`{"type": "Integer","value":"` +
   321  		strings.Repeat("9", 100) + `"}`, // too big Integer
   322  	`{"type": "Array","value": 123}`,       // incorrect Array value
   323  	`{"type": "Hash160","value": "0bcd"}`,  // incorrect Uint160 value
   324  	`{"type": "Hash256","value": "0bcd"}`,  // incorrect Uint256 value
   325  	`{"type": "Stringg","value": ""}`,      // incorrect type
   326  	`{"type": {},"value": ""}`,             // incorrect value
   327  	`{"type": "Boolean","value": qwerty}`,  // incorrect Bool value
   328  	`{"type": "Boolean","value": ""}`,      // incorrect Bool value
   329  	`{"type": "Map","value": ["key": {}]}`, // incorrect Map value
   330  	`{"type": "Map","value": ["key": {"type":"String", "value":"qwer"}, "value": {"type":"Boolean"}]}`, // incorrect Map Value value
   331  	`{"type": "Map","value": ["key": {"type":"String"}, "value": {"type":"Boolean", "value":true}]}`,   // incorrect Map Key value
   332  }
   333  
   334  func TestParam_UnmarshalJSON(t *testing.T) {
   335  	var s Parameter
   336  	for _, tc := range unmarshalJSONTestCases {
   337  		assert.NoError(t, json.Unmarshal([]byte(tc.input), &s))
   338  		assert.Equal(t, s, tc.result)
   339  	}
   340  
   341  	for _, input := range unmarshalJSONErrorCases {
   342  		assert.Error(t, json.Unmarshal([]byte(input), &s), input)
   343  	}
   344  }
   345  
   346  func TestParamType_String(t *testing.T) {
   347  	types := []ParamType{
   348  		SignatureType,
   349  		BoolType,
   350  		IntegerType,
   351  		Hash160Type,
   352  		Hash256Type,
   353  		ByteArrayType,
   354  		PublicKeyType,
   355  		StringType,
   356  		ArrayType,
   357  		InteropInterfaceType,
   358  		MapType,
   359  		VoidType,
   360  	}
   361  
   362  	for _, exp := range types {
   363  		actual, err := ParseParamType(exp.String())
   364  		assert.NoError(t, err)
   365  		assert.Equal(t, exp, actual)
   366  	}
   367  
   368  	actual, err := ParseParamType(UnknownType.String())
   369  	assert.Error(t, err)
   370  	assert.Equal(t, UnknownType, actual)
   371  }
   372  
   373  func TestNewParameterFromString(t *testing.T) {
   374  	var inouts = []struct {
   375  		in  string
   376  		out Parameter
   377  		err bool
   378  	}{{
   379  		in:  "qwerty",
   380  		out: Parameter{StringType, "qwerty"},
   381  	}, {
   382  		in:  "42",
   383  		out: Parameter{IntegerType, big.NewInt(42)},
   384  	}, {
   385  		in:  "Hello, 世界",
   386  		out: Parameter{StringType, "Hello, 世界"},
   387  	}, {
   388  		in:  `\4\2`,
   389  		out: Parameter{IntegerType, big.NewInt(42)},
   390  	}, {
   391  		in:  `\\4\2`,
   392  		out: Parameter{StringType, `\42`},
   393  	}, {
   394  		in:  `\\\4\2`,
   395  		out: Parameter{StringType, `\42`},
   396  	}, {
   397  		in:  "int:42",
   398  		out: Parameter{IntegerType, big.NewInt(42)},
   399  	}, {
   400  		in:  "true",
   401  		out: Parameter{BoolType, true},
   402  	}, {
   403  		in:  "string:true",
   404  		out: Parameter{StringType, "true"},
   405  	}, {
   406  		in:  "\xfe\xff",
   407  		err: true,
   408  	}, {
   409  		in:  `string\:true`,
   410  		out: Parameter{StringType, "string:true"},
   411  	}, {
   412  		in:  "string:true:true",
   413  		out: Parameter{StringType, "true:true"},
   414  	}, {
   415  		in:  `string\\:true`,
   416  		err: true,
   417  	}, {
   418  		in:  `qwerty:asdf`,
   419  		err: true,
   420  	}, {
   421  		in:  `bool:asdf`,
   422  		err: true,
   423  	}, {
   424  		in:  `InteropInterface:123`,
   425  		err: true,
   426  	}, {
   427  		in:  `Map:[]`,
   428  		err: true,
   429  	}, {
   430  		in:  "filebytes:./testdata/adjustValToType_filebytes_good.txt",
   431  		out: Parameter{Type: ByteArrayType, Value: []byte{0x30, 0x31, 0x30, 0x32, 0x30, 0x33, 0x65, 0x66}},
   432  	}, {
   433  		in:  "filebytes:./testdata/does_not_exists.txt",
   434  		err: true,
   435  	}}
   436  	for _, inout := range inouts {
   437  		out, err := NewParameterFromString(inout.in)
   438  		if inout.err {
   439  			assert.NotNil(t, err, "should error on '%s' input", inout.in)
   440  		} else {
   441  			assert.Nil(t, err, "shouldn't error on '%s' input", inout.in)
   442  			assert.Equal(t, inout.out, *out, "bad output for '%s' input", inout.in)
   443  		}
   444  	}
   445  }
   446  
   447  func hexToBase64(s string) string {
   448  	b, _ := hex.DecodeString(s)
   449  	return base64.StdEncoding.EncodeToString(b)
   450  }
   451  
   452  func TestExpandParameterToEmitableToStackitem(t *testing.T) {
   453  	pk, _ := keys.NewPrivateKey()
   454  	testCases := []struct {
   455  		In                Parameter
   456  		Expected          any
   457  		ExpectedStackitem stackitem.Item
   458  	}{
   459  		{
   460  			In:                Parameter{Type: BoolType, Value: true},
   461  			Expected:          true,
   462  			ExpectedStackitem: stackitem.NewBool(true),
   463  		},
   464  		{
   465  			In:                Parameter{Type: IntegerType, Value: big.NewInt(123)},
   466  			Expected:          big.NewInt(123),
   467  			ExpectedStackitem: stackitem.NewBigInteger(big.NewInt(123)),
   468  		},
   469  		{
   470  			In:                Parameter{Type: ByteArrayType, Value: []byte{1, 2, 3}},
   471  			Expected:          []byte{1, 2, 3},
   472  			ExpectedStackitem: stackitem.NewByteArray([]byte{1, 2, 3}),
   473  		},
   474  		{
   475  			In:                Parameter{Type: StringType, Value: "writing's on the wall"},
   476  			Expected:          "writing's on the wall",
   477  			ExpectedStackitem: stackitem.NewByteArray([]byte("writing's on the wall")),
   478  		},
   479  		{
   480  			In:                Parameter{Type: Hash160Type, Value: util.Uint160{1, 2, 3}},
   481  			Expected:          util.Uint160{1, 2, 3},
   482  			ExpectedStackitem: stackitem.NewByteArray(util.Uint160{1, 2, 3}.BytesBE()),
   483  		},
   484  		{
   485  			In:                Parameter{Type: Hash256Type, Value: util.Uint256{1, 2, 3}},
   486  			Expected:          util.Uint256{1, 2, 3},
   487  			ExpectedStackitem: stackitem.NewByteArray(util.Uint256{1, 2, 3}.BytesBE()),
   488  		},
   489  		{
   490  			In:                Parameter{Type: PublicKeyType, Value: pk.PublicKey().Bytes()},
   491  			Expected:          pk.PublicKey().Bytes(),
   492  			ExpectedStackitem: stackitem.NewByteArray(pk.PublicKey().Bytes()),
   493  		},
   494  		{
   495  			In:                Parameter{Type: SignatureType, Value: []byte{1, 2, 3}},
   496  			Expected:          []byte{1, 2, 3},
   497  			ExpectedStackitem: stackitem.NewByteArray([]byte{1, 2, 3}),
   498  		},
   499  		{
   500  			In:                Parameter{Type: AnyType},
   501  			Expected:          nil,
   502  			ExpectedStackitem: stackitem.Null{},
   503  		},
   504  		{
   505  			In: Parameter{Type: ArrayType, Value: []Parameter{
   506  				{
   507  					Type:  IntegerType,
   508  					Value: big.NewInt(123),
   509  				},
   510  				{
   511  					Type:  ByteArrayType,
   512  					Value: []byte{1, 2, 3},
   513  				},
   514  				{
   515  					Type: ArrayType,
   516  					Value: []Parameter{
   517  						{
   518  							Type:  BoolType,
   519  							Value: true,
   520  						},
   521  					},
   522  				},
   523  			}},
   524  			Expected: []any{big.NewInt(123), []byte{1, 2, 3}, []any{true}},
   525  			ExpectedStackitem: stackitem.NewArray([]stackitem.Item{
   526  				stackitem.NewBigInteger(big.NewInt(123)),
   527  				stackitem.NewByteArray([]byte{1, 2, 3}),
   528  				stackitem.NewArray([]stackitem.Item{
   529  					stackitem.NewBool(true),
   530  				}),
   531  			}),
   532  		},
   533  	}
   534  	bw := io.NewBufBinWriter()
   535  	for _, testCase := range testCases {
   536  		actual, err := ExpandParameterToEmitable(testCase.In)
   537  		require.NoError(t, err)
   538  		require.Equal(t, testCase.Expected, actual)
   539  
   540  		emit.Array(bw.BinWriter, actual)
   541  		require.NoError(t, bw.Err)
   542  
   543  		actualSI, err := testCase.In.ToStackItem()
   544  		require.NoError(t, err)
   545  		require.Equal(t, testCase.ExpectedStackitem, actualSI)
   546  	}
   547  	errCases := []Parameter{
   548  		{Type: UnknownType},
   549  		{Type: MapType},
   550  		{Type: InteropInterfaceType},
   551  	}
   552  	for _, errCase := range errCases {
   553  		_, err := ExpandParameterToEmitable(errCase)
   554  		require.Error(t, err)
   555  	}
   556  }
   557  
   558  // testConvertible implements Convertible interface and needed for NewParameterFromValue
   559  // test.
   560  type testConvertible struct {
   561  	i   int
   562  	err string
   563  }
   564  
   565  var _ = Convertible(testConvertible{})
   566  
   567  func (c testConvertible) ToSCParameter() (Parameter, error) {
   568  	if c.err != "" {
   569  		return Parameter{}, errors.New(c.err)
   570  	}
   571  	return Parameter{
   572  		Type:  IntegerType,
   573  		Value: c.i,
   574  	}, nil
   575  }
   576  
   577  func TestParameterFromValue(t *testing.T) {
   578  	pk1, _ := keys.NewPrivateKey()
   579  	pk2, _ := keys.NewPrivateKey()
   580  	items := []struct {
   581  		value   any
   582  		expType ParamType
   583  		expVal  any
   584  		err     string // expected error substring
   585  	}{
   586  		{
   587  			value:   []byte{1, 2, 3},
   588  			expType: ByteArrayType,
   589  			expVal:  []byte{1, 2, 3},
   590  		},
   591  		{
   592  			value:   "hello world",
   593  			expType: StringType,
   594  			expVal:  "hello world",
   595  		},
   596  		{
   597  			value:   false,
   598  			expType: BoolType,
   599  			expVal:  false,
   600  		},
   601  		{
   602  			value:   true,
   603  			expType: BoolType,
   604  			expVal:  true,
   605  		},
   606  		{
   607  			value:   big.NewInt(100),
   608  			expType: IntegerType,
   609  			expVal:  big.NewInt(100),
   610  		},
   611  		{
   612  			value:   byte(100),
   613  			expType: IntegerType,
   614  			expVal:  big.NewInt(100),
   615  		},
   616  		{
   617  			value:   int8(100),
   618  			expType: IntegerType,
   619  			expVal:  big.NewInt(100),
   620  		},
   621  		{
   622  			value:   uint8(100),
   623  			expType: IntegerType,
   624  			expVal:  big.NewInt(100),
   625  		},
   626  		{
   627  			value:   int16(100),
   628  			expType: IntegerType,
   629  			expVal:  big.NewInt(100),
   630  		},
   631  		{
   632  			value:   uint16(100),
   633  			expType: IntegerType,
   634  			expVal:  big.NewInt(100),
   635  		},
   636  		{
   637  			value:   int32(100),
   638  			expType: IntegerType,
   639  			expVal:  big.NewInt(100),
   640  		},
   641  		{
   642  			value:   uint32(100),
   643  			expType: IntegerType,
   644  			expVal:  big.NewInt(100),
   645  		},
   646  		{
   647  			value:   100,
   648  			expType: IntegerType,
   649  			expVal:  big.NewInt(100),
   650  		},
   651  		{
   652  			value:   uint(100),
   653  			expType: IntegerType,
   654  			expVal:  big.NewInt(100),
   655  		},
   656  		{
   657  			value:   int64(100),
   658  			expType: IntegerType,
   659  			expVal:  big.NewInt(100),
   660  		},
   661  		{
   662  			value:   uint64(100),
   663  			expType: IntegerType,
   664  			expVal:  big.NewInt(100),
   665  		},
   666  		{
   667  			value:   Parameter{ByteArrayType, []byte{1, 2, 3}},
   668  			expType: ByteArrayType,
   669  			expVal:  []byte{1, 2, 3},
   670  		},
   671  		{
   672  			value:   &Parameter{ByteArrayType, []byte{1, 2, 3}},
   673  			expType: ByteArrayType,
   674  			expVal:  []byte{1, 2, 3},
   675  		},
   676  		{
   677  			value:   util.Uint160{1, 2, 3},
   678  			expType: Hash160Type,
   679  			expVal:  util.Uint160{1, 2, 3},
   680  		},
   681  		{
   682  			value:   util.Uint256{3, 2, 1},
   683  			expType: Hash256Type,
   684  			expVal:  util.Uint256{3, 2, 1},
   685  		},
   686  		{
   687  			value:   (*util.Uint160)(nil),
   688  			expType: AnyType,
   689  		},
   690  		{
   691  			value:   &util.Uint160{1, 2, 3},
   692  			expType: Hash160Type,
   693  			expVal:  util.Uint160{1, 2, 3},
   694  		},
   695  		{
   696  			value:   (*util.Uint256)(nil),
   697  			expType: AnyType,
   698  		},
   699  		{
   700  			value:   &util.Uint256{3, 2, 1},
   701  			expType: Hash256Type,
   702  			expVal:  util.Uint256{3, 2, 1},
   703  		},
   704  		{
   705  			value:   pk1.PublicKey(),
   706  			expType: PublicKeyType,
   707  			expVal:  pk1.PublicKey().Bytes(),
   708  		},
   709  		{
   710  			value:   *pk2.PublicKey(),
   711  			expType: PublicKeyType,
   712  			expVal:  pk2.PublicKey().Bytes(),
   713  		},
   714  		{
   715  			value:   nil,
   716  			expType: AnyType,
   717  			expVal:  nil,
   718  		},
   719  		{
   720  			value:   [][]byte{{1, 2, 3}, {3, 2, 1}},
   721  			expType: ArrayType,
   722  			expVal:  []Parameter{{ByteArrayType, []byte{1, 2, 3}}, {ByteArrayType, []byte{3, 2, 1}}},
   723  		},
   724  		{
   725  			value:   []Parameter{{ByteArrayType, []byte{1, 2, 3}}, {ByteArrayType, []byte{3, 2, 1}}},
   726  			expType: ArrayType,
   727  			expVal:  []Parameter{{ByteArrayType, []byte{1, 2, 3}}, {ByteArrayType, []byte{3, 2, 1}}},
   728  		},
   729  		{
   730  			value:   []*keys.PublicKey{pk1.PublicKey(), pk2.PublicKey()},
   731  			expType: ArrayType,
   732  			expVal: []Parameter{{
   733  				Type:  PublicKeyType,
   734  				Value: pk1.PublicKey().Bytes(),
   735  			}, {
   736  				Type:  PublicKeyType,
   737  				Value: pk2.PublicKey().Bytes(),
   738  			}},
   739  		},
   740  		{
   741  			value:   keys.PublicKeys{pk1.PublicKey(), pk2.PublicKey()},
   742  			expType: ArrayType,
   743  			expVal: []Parameter{{
   744  				Type:  PublicKeyType,
   745  				Value: pk1.PublicKey().Bytes(),
   746  			}, {
   747  				Type:  PublicKeyType,
   748  				Value: pk2.PublicKey().Bytes(),
   749  			}},
   750  		},
   751  		{
   752  			value:   []any{-42, "random", []byte{1, 2, 3}},
   753  			expType: ArrayType,
   754  			expVal: []Parameter{{
   755  				Type:  IntegerType,
   756  				Value: big.NewInt(-42),
   757  			}, {
   758  				Type:  StringType,
   759  				Value: "random",
   760  			}, {
   761  				Type:  ByteArrayType,
   762  				Value: []byte{1, 2, 3},
   763  			}},
   764  		},
   765  		{
   766  			value:   testConvertible{i: 123},
   767  			expType: IntegerType,
   768  			expVal:  123,
   769  		},
   770  		{
   771  			value:   []any{1, testConvertible{i: 123}},
   772  			expType: ArrayType,
   773  			expVal: []Parameter{
   774  				{
   775  					Type:  IntegerType,
   776  					Value: big.NewInt(1),
   777  				},
   778  				{
   779  					Type:  IntegerType,
   780  					Value: 123,
   781  				},
   782  			},
   783  		},
   784  		{
   785  			value: testConvertible{err: "invalid i value"},
   786  			err:   "invalid i value",
   787  		},
   788  		{
   789  			value: make(map[string]int),
   790  			err:   "unsupported parameter map[string]int",
   791  		},
   792  		{
   793  			value: []any{1, 2, make(map[string]int)},
   794  			err:   "unsupported parameter map[string]int",
   795  		},
   796  	}
   797  
   798  	for _, item := range items {
   799  		t.Run(item.expType.String()+" to stack parameter", func(t *testing.T) {
   800  			res, err := NewParameterFromValue(item.value)
   801  			if item.err != "" {
   802  				require.Error(t, err)
   803  				require.Contains(t, err.Error(), item.err)
   804  			} else {
   805  				require.NoError(t, err)
   806  				require.Equal(t, item.expType, res.Type)
   807  				require.Equal(t, item.expVal, res.Value)
   808  			}
   809  		})
   810  	}
   811  }
   812  
   813  func TestParametersFromValues(t *testing.T) {
   814  	res, err := NewParametersFromValues(42, "some", []byte{3, 2, 1})
   815  	require.NoError(t, err)
   816  	require.Equal(t, []Parameter{{
   817  		Type:  IntegerType,
   818  		Value: big.NewInt(42),
   819  	}, {
   820  		Type:  StringType,
   821  		Value: "some",
   822  	}, {
   823  		Type:  ByteArrayType,
   824  		Value: []byte{3, 2, 1},
   825  	}}, res)
   826  	_, err = NewParametersFromValues(42, make(map[int]int), []byte{3, 2, 1})
   827  	require.Error(t, err)
   828  }