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 }