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

     1  package smartcontract
     2  
     3  import (
     4  	"encoding/hex"
     5  	"math/big"
     6  	"testing"
     7  
     8  	"github.com/nspcc-dev/neo-go/pkg/io"
     9  	"github.com/nspcc-dev/neo-go/pkg/util"
    10  	"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
    11  	"github.com/stretchr/testify/assert"
    12  	"github.com/stretchr/testify/require"
    13  )
    14  
    15  func TestParseParamType(t *testing.T) {
    16  	var inouts = []struct {
    17  		in  string
    18  		out ParamType
    19  		err bool
    20  	}{{
    21  		in:  "signature",
    22  		out: SignatureType,
    23  	}, {
    24  		in:  "Signature",
    25  		out: SignatureType,
    26  	}, {
    27  		in:  "SiGnAtUrE",
    28  		out: SignatureType,
    29  	}, {
    30  		in:  "bool",
    31  		out: BoolType,
    32  	}, {
    33  		in:  "int",
    34  		out: IntegerType,
    35  	}, {
    36  		in:  "hash160",
    37  		out: Hash160Type,
    38  	}, {
    39  		in:  "hash256",
    40  		out: Hash256Type,
    41  	}, {
    42  		in:  "bytes",
    43  		out: ByteArrayType,
    44  	}, {
    45  		in:  "key",
    46  		out: PublicKeyType,
    47  	}, {
    48  		in:  "string",
    49  		out: StringType,
    50  	}, {
    51  		in:  "array",
    52  		out: ArrayType,
    53  	}, {
    54  		in:  "map",
    55  		out: MapType,
    56  	}, {
    57  		in:  "interopinterface",
    58  		out: InteropInterfaceType,
    59  	}, {
    60  		in:  "void",
    61  		out: VoidType,
    62  	}, {
    63  		in:  "qwerty",
    64  		err: true,
    65  	}, {
    66  		in:  "filebytes",
    67  		out: ByteArrayType,
    68  	},
    69  	}
    70  	for _, inout := range inouts {
    71  		out, err := ParseParamType(inout.in)
    72  		if inout.err {
    73  			assert.NotNil(t, err, "should error on '%s' input", inout.in)
    74  		} else {
    75  			assert.Nil(t, err, "shouldn't error on '%s' input", inout.in)
    76  			assert.Equal(t, inout.out, out, "bad output for '%s' input", inout.in)
    77  		}
    78  	}
    79  }
    80  
    81  func TestInferParamType(t *testing.T) {
    82  	bi := new(big.Int).Lsh(big.NewInt(1), stackitem.MaxBigIntegerSizeBits-2)
    83  	var inouts = []struct {
    84  		in  string
    85  		out ParamType
    86  	}{{
    87  		in:  "42",
    88  		out: IntegerType,
    89  	}, {
    90  		in:  "-42",
    91  		out: IntegerType,
    92  	}, {
    93  		in:  "0",
    94  		out: IntegerType,
    95  	}, {
    96  		in:  "8765432187654321111",
    97  		out: IntegerType,
    98  	}, {
    99  		in:  bi.String(),
   100  		out: IntegerType,
   101  	}, {
   102  		in:  bi.String() + "0", // big for Integer but is still a valid hex
   103  		out: ByteArrayType,
   104  	}, {
   105  		in:  "2e10",
   106  		out: ByteArrayType,
   107  	}, {
   108  		in:  "true",
   109  		out: BoolType,
   110  	}, {
   111  		in:  "false",
   112  		out: BoolType,
   113  	}, {
   114  		in:  "truee",
   115  		out: StringType,
   116  	}, {
   117  		in:  "NPAsqZkx9WhNd4P72uhZxBhLinSuNkxfB8",
   118  		out: Hash160Type,
   119  	}, {
   120  		in:  "ZK2nJJpJr6o664CWJKi1QRXjqeic2zRp8y",
   121  		out: StringType,
   122  	}, {
   123  		in:  "50befd26fdf6e4d957c11e078b24ebce6291456f",
   124  		out: Hash160Type,
   125  	}, {
   126  		in:  "03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c",
   127  		out: PublicKeyType,
   128  	}, {
   129  		in:  "30b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c",
   130  		out: ByteArrayType,
   131  	}, {
   132  		in:  "602c79718b16e442de58778e148d0b1084e3b2dffd5de6b7b16cee7969282de7",
   133  		out: Hash256Type,
   134  	}, {
   135  		in:  "602c79718b16e442de58778e148d0b1084e3b2dffd5de6b7b16cee7969282de7da",
   136  		out: ByteArrayType,
   137  	}, {
   138  		in:  "602c79718b16e442de58778e148d0b1084e3b2dffd5de6b7b16cee7969282de7c56f33fc6ecfcd0c225c4ab356fee59390af8560be0e930faebe74a6daff7c9b",
   139  		out: SignatureType,
   140  	}, {
   141  		in:  "qwerty",
   142  		out: StringType,
   143  	}, {
   144  		in:  "ab",
   145  		out: ByteArrayType,
   146  	}, {
   147  		in:  "az",
   148  		out: StringType,
   149  	}, {
   150  		in:  "bad",
   151  		out: StringType,
   152  	}, {
   153  		in:  "фыва",
   154  		out: StringType,
   155  	}, {
   156  		in:  "dead",
   157  		out: ByteArrayType,
   158  	}, {
   159  		in:  "nil",
   160  		out: AnyType,
   161  	}}
   162  	for _, inout := range inouts {
   163  		out := inferParamType(inout.in)
   164  		assert.Equal(t, inout.out, out, "bad output for '%s' input", inout.in)
   165  	}
   166  }
   167  
   168  func TestAdjustValToType(t *testing.T) {
   169  	bi := big.NewInt(1).Lsh(big.NewInt(1), stackitem.MaxBigIntegerSizeBits-2)
   170  
   171  	var inouts = []struct {
   172  		typ ParamType
   173  		val string
   174  		out any
   175  		err bool
   176  	}{{
   177  		typ: SignatureType,
   178  		val: "602c79718b16e442de58778e148d0b1084e3b2dffd5de6b7b16cee7969282de7c56f33fc6ecfcd0c225c4ab356fee59390af8560be0e930faebe74a6daff7c9b",
   179  		out: mustHex("602c79718b16e442de58778e148d0b1084e3b2dffd5de6b7b16cee7969282de7c56f33fc6ecfcd0c225c4ab356fee59390af8560be0e930faebe74a6daff7c9b"),
   180  	}, {
   181  		typ: SignatureType,
   182  		val: "602c79718b16e442de58778e148d0b1084e3b2dffd5de6b7b16cee7969282de7c56f33fc6ecfcd0c225c4ab356fee59390af8560be0e930faebe74a6daff7c",
   183  		err: true,
   184  	}, {
   185  		typ: SignatureType,
   186  		val: "qwerty",
   187  		err: true,
   188  	}, {
   189  		typ: BoolType,
   190  		val: "false",
   191  		out: false,
   192  	}, {
   193  		typ: BoolType,
   194  		val: "true",
   195  		out: true,
   196  	}, {
   197  		typ: BoolType,
   198  		val: "qwerty",
   199  		err: true,
   200  	}, {
   201  		typ: BoolType,
   202  		val: "42",
   203  		err: true,
   204  	}, {
   205  		typ: BoolType,
   206  		val: "0",
   207  		err: true,
   208  	}, {
   209  		typ: IntegerType,
   210  		val: "0",
   211  		out: big.NewInt(0),
   212  	}, {
   213  		typ: IntegerType,
   214  		val: "42",
   215  		out: big.NewInt(42),
   216  	}, {
   217  		typ: IntegerType,
   218  		val: "-42",
   219  		out: big.NewInt(-42),
   220  	}, {
   221  		typ: IntegerType,
   222  		val: bi.String(),
   223  		out: bi,
   224  	}, {
   225  		typ: IntegerType,
   226  		val: bi.String() + "0",
   227  		err: true,
   228  	}, {
   229  		typ: IntegerType,
   230  		val: "q",
   231  		err: true,
   232  	}, {
   233  		typ: Hash160Type,
   234  		val: "NPAsqZkx9WhNd4P72uhZxBhLinSuNkxfB8",
   235  		out: util.Uint160{
   236  			0x23, 0xba, 0x27, 0x3, 0xc5, 0x32, 0x63, 0xe8, 0xd6, 0xe5,
   237  			0x22, 0xdc, 0x32, 0x20, 0x33, 0x39, 0xdc, 0xd8, 0xee, 0xe9,
   238  		},
   239  	}, {
   240  		typ: Hash160Type,
   241  		val: "50befd26fdf6e4d957c11e078b24ebce6291456f",
   242  		out: util.Uint160{
   243  			0x6f, 0x45, 0x91, 0x62, 0xce, 0xeb, 0x24, 0x8b, 0x7, 0x1e,
   244  			0xc1, 0x57, 0xd9, 0xe4, 0xf6, 0xfd, 0x26, 0xfd, 0xbe, 0x50,
   245  		},
   246  	}, {
   247  		typ: Hash160Type,
   248  		val: "befd26fdf6e4d957c11e078b24ebce6291456f",
   249  		err: true,
   250  	}, {
   251  		typ: Hash160Type,
   252  		val: "q",
   253  		err: true,
   254  	}, {
   255  		typ: Hash256Type,
   256  		val: "602c79718b16e442de58778e148d0b1084e3b2dffd5de6b7b16cee7969282de7",
   257  		out: util.Uint256{
   258  			0xe7, 0x2d, 0x28, 0x69, 0x79, 0xee, 0x6c, 0xb1, 0xb7, 0xe6, 0x5d, 0xfd, 0xdf, 0xb2, 0xe3, 0x84,
   259  			0x10, 0xb, 0x8d, 0x14, 0x8e, 0x77, 0x58, 0xde, 0x42, 0xe4, 0x16, 0x8b, 0x71, 0x79, 0x2c, 0x60,
   260  		},
   261  	}, {
   262  		typ: Hash256Type,
   263  		val: "602c79718b16e442de58778e148d0b1084e3b2dffd5de6b7b16cee7969282d",
   264  		err: true,
   265  	}, {
   266  		typ: Hash256Type,
   267  		val: "q",
   268  		err: true,
   269  	}, {
   270  		typ: ByteArrayType,
   271  		val: "602c79718b16e442de58778e148d0b1084e3b2dffd5de6b7b16cee7969282d",
   272  		out: mustHex("602c79718b16e442de58778e148d0b1084e3b2dffd5de6b7b16cee7969282d"),
   273  	}, {
   274  		typ: ByteArrayType,
   275  		val: "602c79718b16e442de58778e148d0b1084e3b2dffd5de6b7b16cee7969282de7",
   276  		out: mustHex("602c79718b16e442de58778e148d0b1084e3b2dffd5de6b7b16cee7969282de7"),
   277  	}, {
   278  		typ: ByteArrayType,
   279  		val: "50befd26fdf6e4d957c11e078b24ebce6291456f",
   280  		out: mustHex("50befd26fdf6e4d957c11e078b24ebce6291456f"),
   281  	}, {
   282  		typ: ByteArrayType,
   283  		val: "AK2nJJpJr6o664CWJKi1QRXjqeic2zRp8y",
   284  		err: true,
   285  	}, {
   286  		typ: ByteArrayType,
   287  		val: "q",
   288  		err: true,
   289  	}, {
   290  		typ: ByteArrayType,
   291  		val: "ab",
   292  		out: mustHex("ab"),
   293  	}, {
   294  		typ: PublicKeyType,
   295  		val: "03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c",
   296  		out: mustHex("03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c"),
   297  	}, {
   298  		typ: PublicKeyType,
   299  		val: "01b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c",
   300  		err: true,
   301  	}, {
   302  		typ: PublicKeyType,
   303  		val: "q",
   304  		err: true,
   305  	}, {
   306  		typ: StringType,
   307  		val: "q",
   308  		out: "q",
   309  	}, {
   310  		typ: StringType,
   311  		val: "dead",
   312  		out: "dead",
   313  	}, {
   314  		typ: StringType,
   315  		val: "йцукен",
   316  		out: "йцукен",
   317  	}, {
   318  		typ: ArrayType,
   319  		val: "",
   320  		err: true,
   321  	}, {
   322  		typ: MapType,
   323  		val: "[]",
   324  		err: true,
   325  	}, {
   326  		typ: InteropInterfaceType,
   327  		val: "",
   328  		err: true,
   329  	}, {
   330  		typ: AnyType,
   331  		val: "nil",
   332  		out: nil,
   333  	}}
   334  
   335  	for _, inout := range inouts {
   336  		out, err := adjustValToType(inout.typ, inout.val)
   337  		if inout.err {
   338  			assert.NotNil(t, err, "should error on '%s/%s' input", inout.typ, inout.val)
   339  		} else {
   340  			assert.Nil(t, err, "shouldn't error on '%s/%s' input", inout.typ, inout.val)
   341  			assert.Equal(t, inout.out, out, "bad output for '%s/%s' input", inout.typ, inout.val)
   342  		}
   343  	}
   344  }
   345  
   346  func TestEncodeDefaultValue(t *testing.T) {
   347  	for p, l := range map[ParamType]int{
   348  		UnknownType:          0,
   349  		AnyType:              66,
   350  		BoolType:             1,
   351  		IntegerType:          33,
   352  		ByteArrayType:        66,
   353  		StringType:           66,
   354  		Hash160Type:          22,
   355  		Hash256Type:          34,
   356  		PublicKeyType:        35,
   357  		SignatureType:        66,
   358  		ArrayType:            0,
   359  		MapType:              0,
   360  		InteropInterfaceType: 0,
   361  		VoidType:             0,
   362  	} {
   363  		b := io.NewBufBinWriter()
   364  		p.EncodeDefaultValue(b.BinWriter)
   365  		require.NoError(t, b.Err)
   366  		require.Equalf(t, l, len(b.Bytes()), p.String())
   367  	}
   368  }
   369  
   370  func mustHex(s string) []byte {
   371  	b, err := hex.DecodeString(s)
   372  	if err != nil {
   373  		panic(err)
   374  	}
   375  	return b
   376  }
   377  
   378  func TestConvertToParamType(t *testing.T) {
   379  	for _, expected := range []ParamType{
   380  		UnknownType,
   381  		AnyType,
   382  		BoolType,
   383  		IntegerType,
   384  		ByteArrayType,
   385  		StringType,
   386  		Hash160Type,
   387  		Hash256Type,
   388  		PublicKeyType,
   389  		SignatureType,
   390  		ArrayType,
   391  		MapType,
   392  		InteropInterfaceType,
   393  		VoidType,
   394  	} {
   395  		actual, err := ConvertToParamType(int(expected))
   396  		require.NoError(t, err)
   397  		require.Equal(t, expected, actual)
   398  	}
   399  
   400  	_, err := ConvertToParamType(0x01)
   401  	require.NotNil(t, err)
   402  }
   403  
   404  func TestConvertToStackitemType(t *testing.T) {
   405  	for p, expected := range map[ParamType]stackitem.Type{
   406  		AnyType:              stackitem.AnyT,
   407  		BoolType:             stackitem.BooleanT,
   408  		IntegerType:          stackitem.IntegerT,
   409  		ByteArrayType:        stackitem.ByteArrayT,
   410  		StringType:           stackitem.ByteArrayT,
   411  		Hash160Type:          stackitem.ByteArrayT,
   412  		Hash256Type:          stackitem.ByteArrayT,
   413  		PublicKeyType:        stackitem.ByteArrayT,
   414  		SignatureType:        stackitem.ByteArrayT,
   415  		ArrayType:            stackitem.ArrayT,
   416  		MapType:              stackitem.MapT,
   417  		InteropInterfaceType: stackitem.InteropT,
   418  		VoidType:             stackitem.AnyT,
   419  	} {
   420  		actual := p.ConvertToStackitemType()
   421  		require.Equal(t, expected, actual)
   422  	}
   423  
   424  	require.Panics(t, func() {
   425  		UnknownType.ConvertToStackitemType()
   426  	})
   427  }
   428  
   429  func TestParamTypeMatch(t *testing.T) {
   430  	for itm, pt := range map[stackitem.Item]ParamType{
   431  		&stackitem.Pointer{}:         BoolType,
   432  		&stackitem.Pointer{}:         MapType,
   433  		stackitem.Make(0):            BoolType,
   434  		stackitem.Make(0):            ByteArrayType,
   435  		stackitem.Make(0):            StringType,
   436  		stackitem.Make(false):        ByteArrayType,
   437  		stackitem.Make(true):         StringType,
   438  		stackitem.Make([]byte{1}):    Hash160Type,
   439  		stackitem.Make([]byte{1}):    Hash256Type,
   440  		stackitem.Make([]byte{1}):    PublicKeyType,
   441  		stackitem.Make([]byte{1}):    SignatureType,
   442  		stackitem.Make(0):            Hash160Type,
   443  		stackitem.Make(0):            Hash256Type,
   444  		stackitem.Make(0):            PublicKeyType,
   445  		stackitem.Make(0):            SignatureType,
   446  		stackitem.Make(0):            ArrayType,
   447  		stackitem.Make(0):            MapType,
   448  		stackitem.Make(0):            InteropInterfaceType,
   449  		stackitem.Make(0):            VoidType,
   450  		stackitem.Null{}:             StringType,
   451  		stackitem.Make([]byte{0x80}): StringType, // non utf-8
   452  	} {
   453  		require.Falsef(t, pt.Match(itm), "%s - %s", pt.String(), itm.String())
   454  	}
   455  	for itm, pt := range map[stackitem.Item]ParamType{
   456  		stackitem.Make(false):                      BoolType,
   457  		stackitem.Make(true):                       BoolType,
   458  		stackitem.Make(0):                          IntegerType,
   459  		stackitem.Make(100500):                     IntegerType,
   460  		stackitem.Make([]byte{1}):                  ByteArrayType,
   461  		stackitem.Make([]byte{0x80}):               ByteArrayType, // non utf-8
   462  		stackitem.Make([]byte{1}):                  StringType,
   463  		stackitem.NewBuffer([]byte{1}):             ByteArrayType,
   464  		stackitem.NewBuffer([]byte{1}):             StringType,
   465  		stackitem.Null{}:                           ByteArrayType,
   466  		stackitem.Make(util.Uint160{}.BytesBE()):   Hash160Type,
   467  		stackitem.Make(util.Uint256{}.BytesBE()):   Hash256Type,
   468  		stackitem.Null{}:                           Hash160Type,
   469  		stackitem.Null{}:                           Hash256Type,
   470  		stackitem.Make(make([]byte, PublicKeyLen)): PublicKeyType,
   471  		stackitem.Null{}:                           PublicKeyType,
   472  		stackitem.Make(make([]byte, SignatureLen)): SignatureType,
   473  		stackitem.Null{}:                           SignatureType,
   474  		stackitem.Make([]stackitem.Item{}):         ArrayType,
   475  		stackitem.NewStruct([]stackitem.Item{}):    ArrayType,
   476  		stackitem.Null{}:                           ArrayType,
   477  		stackitem.NewMap():                         MapType,
   478  		stackitem.Null{}:                           MapType,
   479  		stackitem.NewInterop(true):                 InteropInterfaceType,
   480  		stackitem.Null{}:                           InteropInterfaceType,
   481  	} {
   482  		require.Truef(t, pt.Match(itm), "%s - %s", pt.String(), itm.String())
   483  	}
   484  }