github.com/sberex/go-sberex@v1.8.2-0.20181113200658-ed96ac38f7d7/accounts/abi/abi_test.go (about) 1 // This file is part of the go-sberex library. The go-sberex library is 2 // free software: you can redistribute it and/or modify it under the terms 3 // of the GNU Lesser General Public License as published by the Free 4 // Software Foundation, either version 3 of the License, or (at your option) 5 // any later version. 6 // 7 // The go-sberex library is distributed in the hope that it will be useful, 8 // but WITHOUT ANY WARRANTY; without even the implied warranty of 9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 10 // General Public License <http://www.gnu.org/licenses/> for more details. 11 12 package abi 13 14 import ( 15 "bytes" 16 "encoding/hex" 17 "fmt" 18 "log" 19 "math/big" 20 "strings" 21 "testing" 22 23 "reflect" 24 25 "github.com/Sberex/go-sberex/common" 26 "github.com/Sberex/go-sberex/crypto" 27 ) 28 29 const jsondata = ` 30 [ 31 { "type" : "function", "name" : "balance", "constant" : true }, 32 { "type" : "function", "name" : "send", "constant" : false, "inputs" : [ { "name" : "amount", "type" : "uint256" } ] } 33 ]` 34 35 const jsondata2 = ` 36 [ 37 { "type" : "function", "name" : "balance", "constant" : true }, 38 { "type" : "function", "name" : "send", "constant" : false, "inputs" : [ { "name" : "amount", "type" : "uint256" } ] }, 39 { "type" : "function", "name" : "test", "constant" : false, "inputs" : [ { "name" : "number", "type" : "uint32" } ] }, 40 { "type" : "function", "name" : "string", "constant" : false, "inputs" : [ { "name" : "inputs", "type" : "string" } ] }, 41 { "type" : "function", "name" : "bool", "constant" : false, "inputs" : [ { "name" : "inputs", "type" : "bool" } ] }, 42 { "type" : "function", "name" : "address", "constant" : false, "inputs" : [ { "name" : "inputs", "type" : "address" } ] }, 43 { "type" : "function", "name" : "uint64[2]", "constant" : false, "inputs" : [ { "name" : "inputs", "type" : "uint64[2]" } ] }, 44 { "type" : "function", "name" : "uint64[]", "constant" : false, "inputs" : [ { "name" : "inputs", "type" : "uint64[]" } ] }, 45 { "type" : "function", "name" : "foo", "constant" : false, "inputs" : [ { "name" : "inputs", "type" : "uint32" } ] }, 46 { "type" : "function", "name" : "bar", "constant" : false, "inputs" : [ { "name" : "inputs", "type" : "uint32" }, { "name" : "string", "type" : "uint16" } ] }, 47 { "type" : "function", "name" : "slice", "constant" : false, "inputs" : [ { "name" : "inputs", "type" : "uint32[2]" } ] }, 48 { "type" : "function", "name" : "slice256", "constant" : false, "inputs" : [ { "name" : "inputs", "type" : "uint256[2]" } ] }, 49 { "type" : "function", "name" : "sliceAddress", "constant" : false, "inputs" : [ { "name" : "inputs", "type" : "address[]" } ] }, 50 { "type" : "function", "name" : "sliceMultiAddress", "constant" : false, "inputs" : [ { "name" : "a", "type" : "address[]" }, { "name" : "b", "type" : "address[]" } ] } 51 ]` 52 53 func TestReader(t *testing.T) { 54 Uint256, _ := NewType("uint256") 55 exp := ABI{ 56 Methods: map[string]Method{ 57 "balance": { 58 "balance", true, nil, nil, 59 }, 60 "send": { 61 "send", false, []Argument{ 62 {"amount", Uint256, false}, 63 }, nil, 64 }, 65 }, 66 } 67 68 abi, err := JSON(strings.NewReader(jsondata)) 69 if err != nil { 70 t.Error(err) 71 } 72 73 // deep equal fails for some reason 74 for name, expM := range exp.Methods { 75 gotM, exist := abi.Methods[name] 76 if !exist { 77 t.Errorf("Missing expected method %v", name) 78 } 79 if !reflect.DeepEqual(gotM, expM) { 80 t.Errorf("\nGot abi method: \n%v\ndoes not match expected method\n%v", gotM, expM) 81 } 82 } 83 84 for name, gotM := range abi.Methods { 85 expM, exist := exp.Methods[name] 86 if !exist { 87 t.Errorf("Found extra method %v", name) 88 } 89 if !reflect.DeepEqual(gotM, expM) { 90 t.Errorf("\nGot abi method: \n%v\ndoes not match expected method\n%v", gotM, expM) 91 } 92 } 93 } 94 95 func TestTestNumbers(t *testing.T) { 96 abi, err := JSON(strings.NewReader(jsondata2)) 97 if err != nil { 98 t.Error(err) 99 t.FailNow() 100 } 101 102 if _, err := abi.Pack("balance"); err != nil { 103 t.Error(err) 104 } 105 106 if _, err := abi.Pack("balance", 1); err == nil { 107 t.Error("expected error for balance(1)") 108 } 109 110 if _, err := abi.Pack("doesntexist", nil); err == nil { 111 t.Errorf("doesntexist shouldn't exist") 112 } 113 114 if _, err := abi.Pack("doesntexist", 1); err == nil { 115 t.Errorf("doesntexist(1) shouldn't exist") 116 } 117 118 if _, err := abi.Pack("send", big.NewInt(1000)); err != nil { 119 t.Error(err) 120 } 121 122 i := new(int) 123 *i = 1000 124 if _, err := abi.Pack("send", i); err == nil { 125 t.Errorf("expected send( ptr ) to throw, requires *big.Int instead of *int") 126 } 127 128 if _, err := abi.Pack("test", uint32(1000)); err != nil { 129 t.Error(err) 130 } 131 } 132 133 func TestTestString(t *testing.T) { 134 abi, err := JSON(strings.NewReader(jsondata2)) 135 if err != nil { 136 t.Error(err) 137 t.FailNow() 138 } 139 140 if _, err := abi.Pack("string", "hello world"); err != nil { 141 t.Error(err) 142 } 143 } 144 145 func TestTestBool(t *testing.T) { 146 abi, err := JSON(strings.NewReader(jsondata2)) 147 if err != nil { 148 t.Error(err) 149 t.FailNow() 150 } 151 152 if _, err := abi.Pack("bool", true); err != nil { 153 t.Error(err) 154 } 155 } 156 157 func TestTestSlice(t *testing.T) { 158 abi, err := JSON(strings.NewReader(jsondata2)) 159 if err != nil { 160 t.Error(err) 161 t.FailNow() 162 } 163 164 slice := make([]uint64, 2) 165 if _, err := abi.Pack("uint64[2]", slice); err != nil { 166 t.Error(err) 167 } 168 169 if _, err := abi.Pack("uint64[]", slice); err != nil { 170 t.Error(err) 171 } 172 } 173 174 func TestMethodSignature(t *testing.T) { 175 String, _ := NewType("string") 176 m := Method{"foo", false, []Argument{{"bar", String, false}, {"baz", String, false}}, nil} 177 exp := "foo(string,string)" 178 if m.Sig() != exp { 179 t.Error("signature mismatch", exp, "!=", m.Sig()) 180 } 181 182 idexp := crypto.Keccak256([]byte(exp))[:4] 183 if !bytes.Equal(m.Id(), idexp) { 184 t.Errorf("expected ids to match %x != %x", m.Id(), idexp) 185 } 186 187 uintt, _ := NewType("uint256") 188 m = Method{"foo", false, []Argument{{"bar", uintt, false}}, nil} 189 exp = "foo(uint256)" 190 if m.Sig() != exp { 191 t.Error("signature mismatch", exp, "!=", m.Sig()) 192 } 193 } 194 195 func TestMultiPack(t *testing.T) { 196 abi, err := JSON(strings.NewReader(jsondata2)) 197 if err != nil { 198 t.Error(err) 199 t.FailNow() 200 } 201 202 sig := crypto.Keccak256([]byte("bar(uint32,uint16)"))[:4] 203 sig = append(sig, make([]byte, 64)...) 204 sig[35] = 10 205 sig[67] = 11 206 207 packed, err := abi.Pack("bar", uint32(10), uint16(11)) 208 if err != nil { 209 t.Error(err) 210 t.FailNow() 211 } 212 213 if !bytes.Equal(packed, sig) { 214 t.Errorf("expected %x got %x", sig, packed) 215 } 216 } 217 218 func ExampleJSON() { 219 const definition = `[{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"isBar","outputs":[{"name":"","type":"bool"}],"type":"function"}]` 220 221 abi, err := JSON(strings.NewReader(definition)) 222 if err != nil { 223 log.Fatalln(err) 224 } 225 out, err := abi.Pack("isBar", common.HexToAddress("01")) 226 if err != nil { 227 log.Fatalln(err) 228 } 229 230 fmt.Printf("%x\n", out) 231 // Output: 232 // 1f2c40920000000000000000000000000000000000000000000000000000000000000001 233 } 234 235 func TestInputVariableInputLength(t *testing.T) { 236 const definition = `[ 237 { "type" : "function", "name" : "strOne", "constant" : true, "inputs" : [ { "name" : "str", "type" : "string" } ] }, 238 { "type" : "function", "name" : "bytesOne", "constant" : true, "inputs" : [ { "name" : "str", "type" : "bytes" } ] }, 239 { "type" : "function", "name" : "strTwo", "constant" : true, "inputs" : [ { "name" : "str", "type" : "string" }, { "name" : "str1", "type" : "string" } ] } 240 ]` 241 242 abi, err := JSON(strings.NewReader(definition)) 243 if err != nil { 244 t.Fatal(err) 245 } 246 247 // test one string 248 strin := "hello world" 249 strpack, err := abi.Pack("strOne", strin) 250 if err != nil { 251 t.Error(err) 252 } 253 254 offset := make([]byte, 32) 255 offset[31] = 32 256 length := make([]byte, 32) 257 length[31] = byte(len(strin)) 258 value := common.RightPadBytes([]byte(strin), 32) 259 exp := append(offset, append(length, value...)...) 260 261 // ignore first 4 bytes of the output. This is the function identifier 262 strpack = strpack[4:] 263 if !bytes.Equal(strpack, exp) { 264 t.Errorf("expected %x, got %x\n", exp, strpack) 265 } 266 267 // test one bytes 268 btspack, err := abi.Pack("bytesOne", []byte(strin)) 269 if err != nil { 270 t.Error(err) 271 } 272 // ignore first 4 bytes of the output. This is the function identifier 273 btspack = btspack[4:] 274 if !bytes.Equal(btspack, exp) { 275 t.Errorf("expected %x, got %x\n", exp, btspack) 276 } 277 278 // test two strings 279 str1 := "hello" 280 str2 := "world" 281 str2pack, err := abi.Pack("strTwo", str1, str2) 282 if err != nil { 283 t.Error(err) 284 } 285 286 offset1 := make([]byte, 32) 287 offset1[31] = 64 288 length1 := make([]byte, 32) 289 length1[31] = byte(len(str1)) 290 value1 := common.RightPadBytes([]byte(str1), 32) 291 292 offset2 := make([]byte, 32) 293 offset2[31] = 128 294 length2 := make([]byte, 32) 295 length2[31] = byte(len(str2)) 296 value2 := common.RightPadBytes([]byte(str2), 32) 297 298 exp2 := append(offset1, offset2...) 299 exp2 = append(exp2, append(length1, value1...)...) 300 exp2 = append(exp2, append(length2, value2...)...) 301 302 // ignore first 4 bytes of the output. This is the function identifier 303 str2pack = str2pack[4:] 304 if !bytes.Equal(str2pack, exp2) { 305 t.Errorf("expected %x, got %x\n", exp, str2pack) 306 } 307 308 // test two strings, first > 32, second < 32 309 str1 = strings.Repeat("a", 33) 310 str2pack, err = abi.Pack("strTwo", str1, str2) 311 if err != nil { 312 t.Error(err) 313 } 314 315 offset1 = make([]byte, 32) 316 offset1[31] = 64 317 length1 = make([]byte, 32) 318 length1[31] = byte(len(str1)) 319 value1 = common.RightPadBytes([]byte(str1), 64) 320 offset2[31] = 160 321 322 exp2 = append(offset1, offset2...) 323 exp2 = append(exp2, append(length1, value1...)...) 324 exp2 = append(exp2, append(length2, value2...)...) 325 326 // ignore first 4 bytes of the output. This is the function identifier 327 str2pack = str2pack[4:] 328 if !bytes.Equal(str2pack, exp2) { 329 t.Errorf("expected %x, got %x\n", exp, str2pack) 330 } 331 332 // test two strings, first > 32, second >32 333 str1 = strings.Repeat("a", 33) 334 str2 = strings.Repeat("a", 33) 335 str2pack, err = abi.Pack("strTwo", str1, str2) 336 if err != nil { 337 t.Error(err) 338 } 339 340 offset1 = make([]byte, 32) 341 offset1[31] = 64 342 length1 = make([]byte, 32) 343 length1[31] = byte(len(str1)) 344 value1 = common.RightPadBytes([]byte(str1), 64) 345 346 offset2 = make([]byte, 32) 347 offset2[31] = 160 348 length2 = make([]byte, 32) 349 length2[31] = byte(len(str2)) 350 value2 = common.RightPadBytes([]byte(str2), 64) 351 352 exp2 = append(offset1, offset2...) 353 exp2 = append(exp2, append(length1, value1...)...) 354 exp2 = append(exp2, append(length2, value2...)...) 355 356 // ignore first 4 bytes of the output. This is the function identifier 357 str2pack = str2pack[4:] 358 if !bytes.Equal(str2pack, exp2) { 359 t.Errorf("expected %x, got %x\n", exp, str2pack) 360 } 361 } 362 363 func TestInputFixedArrayAndVariableInputLength(t *testing.T) { 364 const definition = `[ 365 { "type" : "function", "name" : "fixedArrStr", "constant" : true, "inputs" : [ { "name" : "str", "type" : "string" }, { "name" : "fixedArr", "type" : "uint256[2]" } ] }, 366 { "type" : "function", "name" : "fixedArrBytes", "constant" : true, "inputs" : [ { "name" : "str", "type" : "bytes" }, { "name" : "fixedArr", "type" : "uint256[2]" } ] }, 367 { "type" : "function", "name" : "mixedArrStr", "constant" : true, "inputs" : [ { "name" : "str", "type" : "string" }, { "name" : "fixedArr", "type": "uint256[2]" }, { "name" : "dynArr", "type": "uint256[]" } ] }, 368 { "type" : "function", "name" : "doubleFixedArrStr", "constant" : true, "inputs" : [ { "name" : "str", "type" : "string" }, { "name" : "fixedArr1", "type": "uint256[2]" }, { "name" : "fixedArr2", "type": "uint256[3]" } ] }, 369 { "type" : "function", "name" : "multipleMixedArrStr", "constant" : true, "inputs" : [ { "name" : "str", "type" : "string" }, { "name" : "fixedArr1", "type": "uint256[2]" }, { "name" : "dynArr", "type" : "uint256[]" }, { "name" : "fixedArr2", "type" : "uint256[3]" } ] } 370 ]` 371 372 abi, err := JSON(strings.NewReader(definition)) 373 if err != nil { 374 t.Error(err) 375 } 376 377 // test string, fixed array uint256[2] 378 strin := "hello world" 379 arrin := [2]*big.Int{big.NewInt(1), big.NewInt(2)} 380 fixedArrStrPack, err := abi.Pack("fixedArrStr", strin, arrin) 381 if err != nil { 382 t.Error(err) 383 } 384 385 // generate expected output 386 offset := make([]byte, 32) 387 offset[31] = 96 388 length := make([]byte, 32) 389 length[31] = byte(len(strin)) 390 strvalue := common.RightPadBytes([]byte(strin), 32) 391 arrinvalue1 := common.LeftPadBytes(arrin[0].Bytes(), 32) 392 arrinvalue2 := common.LeftPadBytes(arrin[1].Bytes(), 32) 393 exp := append(offset, arrinvalue1...) 394 exp = append(exp, arrinvalue2...) 395 exp = append(exp, append(length, strvalue...)...) 396 397 // ignore first 4 bytes of the output. This is the function identifier 398 fixedArrStrPack = fixedArrStrPack[4:] 399 if !bytes.Equal(fixedArrStrPack, exp) { 400 t.Errorf("expected %x, got %x\n", exp, fixedArrStrPack) 401 } 402 403 // test byte array, fixed array uint256[2] 404 bytesin := []byte(strin) 405 arrin = [2]*big.Int{big.NewInt(1), big.NewInt(2)} 406 fixedArrBytesPack, err := abi.Pack("fixedArrBytes", bytesin, arrin) 407 if err != nil { 408 t.Error(err) 409 } 410 411 // generate expected output 412 offset = make([]byte, 32) 413 offset[31] = 96 414 length = make([]byte, 32) 415 length[31] = byte(len(strin)) 416 strvalue = common.RightPadBytes([]byte(strin), 32) 417 arrinvalue1 = common.LeftPadBytes(arrin[0].Bytes(), 32) 418 arrinvalue2 = common.LeftPadBytes(arrin[1].Bytes(), 32) 419 exp = append(offset, arrinvalue1...) 420 exp = append(exp, arrinvalue2...) 421 exp = append(exp, append(length, strvalue...)...) 422 423 // ignore first 4 bytes of the output. This is the function identifier 424 fixedArrBytesPack = fixedArrBytesPack[4:] 425 if !bytes.Equal(fixedArrBytesPack, exp) { 426 t.Errorf("expected %x, got %x\n", exp, fixedArrBytesPack) 427 } 428 429 // test string, fixed array uint256[2], dynamic array uint256[] 430 strin = "hello world" 431 fixedarrin := [2]*big.Int{big.NewInt(1), big.NewInt(2)} 432 dynarrin := []*big.Int{big.NewInt(1), big.NewInt(2), big.NewInt(3)} 433 mixedArrStrPack, err := abi.Pack("mixedArrStr", strin, fixedarrin, dynarrin) 434 if err != nil { 435 t.Error(err) 436 } 437 438 // generate expected output 439 stroffset := make([]byte, 32) 440 stroffset[31] = 128 441 strlength := make([]byte, 32) 442 strlength[31] = byte(len(strin)) 443 strvalue = common.RightPadBytes([]byte(strin), 32) 444 fixedarrinvalue1 := common.LeftPadBytes(fixedarrin[0].Bytes(), 32) 445 fixedarrinvalue2 := common.LeftPadBytes(fixedarrin[1].Bytes(), 32) 446 dynarroffset := make([]byte, 32) 447 dynarroffset[31] = byte(160 + ((len(strin)/32)+1)*32) 448 dynarrlength := make([]byte, 32) 449 dynarrlength[31] = byte(len(dynarrin)) 450 dynarrinvalue1 := common.LeftPadBytes(dynarrin[0].Bytes(), 32) 451 dynarrinvalue2 := common.LeftPadBytes(dynarrin[1].Bytes(), 32) 452 dynarrinvalue3 := common.LeftPadBytes(dynarrin[2].Bytes(), 32) 453 exp = append(stroffset, fixedarrinvalue1...) 454 exp = append(exp, fixedarrinvalue2...) 455 exp = append(exp, dynarroffset...) 456 exp = append(exp, append(strlength, strvalue...)...) 457 dynarrarg := append(dynarrlength, dynarrinvalue1...) 458 dynarrarg = append(dynarrarg, dynarrinvalue2...) 459 dynarrarg = append(dynarrarg, dynarrinvalue3...) 460 exp = append(exp, dynarrarg...) 461 462 // ignore first 4 bytes of the output. This is the function identifier 463 mixedArrStrPack = mixedArrStrPack[4:] 464 if !bytes.Equal(mixedArrStrPack, exp) { 465 t.Errorf("expected %x, got %x\n", exp, mixedArrStrPack) 466 } 467 468 // test string, fixed array uint256[2], fixed array uint256[3] 469 strin = "hello world" 470 fixedarrin1 := [2]*big.Int{big.NewInt(1), big.NewInt(2)} 471 fixedarrin2 := [3]*big.Int{big.NewInt(1), big.NewInt(2), big.NewInt(3)} 472 doubleFixedArrStrPack, err := abi.Pack("doubleFixedArrStr", strin, fixedarrin1, fixedarrin2) 473 if err != nil { 474 t.Error(err) 475 } 476 477 // generate expected output 478 stroffset = make([]byte, 32) 479 stroffset[31] = 192 480 strlength = make([]byte, 32) 481 strlength[31] = byte(len(strin)) 482 strvalue = common.RightPadBytes([]byte(strin), 32) 483 fixedarrin1value1 := common.LeftPadBytes(fixedarrin1[0].Bytes(), 32) 484 fixedarrin1value2 := common.LeftPadBytes(fixedarrin1[1].Bytes(), 32) 485 fixedarrin2value1 := common.LeftPadBytes(fixedarrin2[0].Bytes(), 32) 486 fixedarrin2value2 := common.LeftPadBytes(fixedarrin2[1].Bytes(), 32) 487 fixedarrin2value3 := common.LeftPadBytes(fixedarrin2[2].Bytes(), 32) 488 exp = append(stroffset, fixedarrin1value1...) 489 exp = append(exp, fixedarrin1value2...) 490 exp = append(exp, fixedarrin2value1...) 491 exp = append(exp, fixedarrin2value2...) 492 exp = append(exp, fixedarrin2value3...) 493 exp = append(exp, append(strlength, strvalue...)...) 494 495 // ignore first 4 bytes of the output. This is the function identifier 496 doubleFixedArrStrPack = doubleFixedArrStrPack[4:] 497 if !bytes.Equal(doubleFixedArrStrPack, exp) { 498 t.Errorf("expected %x, got %x\n", exp, doubleFixedArrStrPack) 499 } 500 501 // test string, fixed array uint256[2], dynamic array uint256[], fixed array uint256[3] 502 strin = "hello world" 503 fixedarrin1 = [2]*big.Int{big.NewInt(1), big.NewInt(2)} 504 dynarrin = []*big.Int{big.NewInt(1), big.NewInt(2)} 505 fixedarrin2 = [3]*big.Int{big.NewInt(1), big.NewInt(2), big.NewInt(3)} 506 multipleMixedArrStrPack, err := abi.Pack("multipleMixedArrStr", strin, fixedarrin1, dynarrin, fixedarrin2) 507 if err != nil { 508 t.Error(err) 509 } 510 511 // generate expected output 512 stroffset = make([]byte, 32) 513 stroffset[31] = 224 514 strlength = make([]byte, 32) 515 strlength[31] = byte(len(strin)) 516 strvalue = common.RightPadBytes([]byte(strin), 32) 517 fixedarrin1value1 = common.LeftPadBytes(fixedarrin1[0].Bytes(), 32) 518 fixedarrin1value2 = common.LeftPadBytes(fixedarrin1[1].Bytes(), 32) 519 dynarroffset = U256(big.NewInt(int64(256 + ((len(strin)/32)+1)*32))) 520 dynarrlength = make([]byte, 32) 521 dynarrlength[31] = byte(len(dynarrin)) 522 dynarrinvalue1 = common.LeftPadBytes(dynarrin[0].Bytes(), 32) 523 dynarrinvalue2 = common.LeftPadBytes(dynarrin[1].Bytes(), 32) 524 fixedarrin2value1 = common.LeftPadBytes(fixedarrin2[0].Bytes(), 32) 525 fixedarrin2value2 = common.LeftPadBytes(fixedarrin2[1].Bytes(), 32) 526 fixedarrin2value3 = common.LeftPadBytes(fixedarrin2[2].Bytes(), 32) 527 exp = append(stroffset, fixedarrin1value1...) 528 exp = append(exp, fixedarrin1value2...) 529 exp = append(exp, dynarroffset...) 530 exp = append(exp, fixedarrin2value1...) 531 exp = append(exp, fixedarrin2value2...) 532 exp = append(exp, fixedarrin2value3...) 533 exp = append(exp, append(strlength, strvalue...)...) 534 dynarrarg = append(dynarrlength, dynarrinvalue1...) 535 dynarrarg = append(dynarrarg, dynarrinvalue2...) 536 exp = append(exp, dynarrarg...) 537 538 // ignore first 4 bytes of the output. This is the function identifier 539 multipleMixedArrStrPack = multipleMixedArrStrPack[4:] 540 if !bytes.Equal(multipleMixedArrStrPack, exp) { 541 t.Errorf("expected %x, got %x\n", exp, multipleMixedArrStrPack) 542 } 543 } 544 545 func TestDefaultFunctionParsing(t *testing.T) { 546 const definition = `[{ "name" : "balance" }]` 547 548 abi, err := JSON(strings.NewReader(definition)) 549 if err != nil { 550 t.Fatal(err) 551 } 552 553 if _, ok := abi.Methods["balance"]; !ok { 554 t.Error("expected 'balance' to be present") 555 } 556 } 557 558 func TestBareEvents(t *testing.T) { 559 const definition = `[ 560 { "type" : "event", "name" : "balance" }, 561 { "type" : "event", "name" : "anon", "anonymous" : true}, 562 { "type" : "event", "name" : "args", "inputs" : [{ "indexed":false, "name":"arg0", "type":"uint256" }, { "indexed":true, "name":"arg1", "type":"address" }] } 563 ]` 564 565 arg0, _ := NewType("uint256") 566 arg1, _ := NewType("address") 567 568 expectedEvents := map[string]struct { 569 Anonymous bool 570 Args []Argument 571 }{ 572 "balance": {false, nil}, 573 "anon": {true, nil}, 574 "args": {false, []Argument{ 575 {Name: "arg0", Type: arg0, Indexed: false}, 576 {Name: "arg1", Type: arg1, Indexed: true}, 577 }}, 578 } 579 580 abi, err := JSON(strings.NewReader(definition)) 581 if err != nil { 582 t.Fatal(err) 583 } 584 585 if len(abi.Events) != len(expectedEvents) { 586 t.Fatalf("invalid number of events after parsing, want %d, got %d", len(expectedEvents), len(abi.Events)) 587 } 588 589 for name, exp := range expectedEvents { 590 got, ok := abi.Events[name] 591 if !ok { 592 t.Errorf("could not found event %s", name) 593 continue 594 } 595 if got.Anonymous != exp.Anonymous { 596 t.Errorf("invalid anonymous indication for event %s, want %v, got %v", name, exp.Anonymous, got.Anonymous) 597 } 598 if len(got.Inputs) != len(exp.Args) { 599 t.Errorf("invalid number of args, want %d, got %d", len(exp.Args), len(got.Inputs)) 600 continue 601 } 602 for i, arg := range exp.Args { 603 if arg.Name != got.Inputs[i].Name { 604 t.Errorf("events[%s].Input[%d] has an invalid name, want %s, got %s", name, i, arg.Name, got.Inputs[i].Name) 605 } 606 if arg.Indexed != got.Inputs[i].Indexed { 607 t.Errorf("events[%s].Input[%d] has an invalid indexed indication, want %v, got %v", name, i, arg.Indexed, got.Inputs[i].Indexed) 608 } 609 if arg.Type.T != got.Inputs[i].Type.T { 610 t.Errorf("events[%s].Input[%d] has an invalid type, want %x, got %x", name, i, arg.Type.T, got.Inputs[i].Type.T) 611 } 612 } 613 } 614 } 615 616 // TestUnpackEvent is based on this contract: 617 // contract T { 618 // event received(address sender, uint amount, bytes memo); 619 // function receive(bytes memo) external payable { 620 // received(msg.sender, msg.value, memo); 621 // } 622 // } 623 // When receive("X") is called with sender 0x00... and value 1, it produces this tx receipt: 624 // receipt{status=1 cgas=23949 bloom=00000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000040200000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 logs=[log: b6818c8064f645cd82d99b59a1a267d6d61117ef [75fd880d39c1daf53b6547ab6cb59451fc6452d27caa90e5b6649dd8293b9eed] 000000000000000000000000376c47978271565f56deb45495afa69e59c16ab200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000158 9ae378b6d4409eada347a5dc0c180f186cb62dc68fcc0f043425eb917335aa28 0 95d429d309bb9d753954195fe2d69bd140b4ae731b9b5b605c34323de162cf00 0]} 625 func TestUnpackEvent(t *testing.T) { 626 const abiJSON = `[{"constant":false,"inputs":[{"name":"memo","type":"bytes"}],"name":"receive","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"sender","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"memo","type":"bytes"}],"name":"received","type":"event"}]` 627 abi, err := JSON(strings.NewReader(abiJSON)) 628 if err != nil { 629 t.Fatal(err) 630 } 631 632 const hexdata = `000000000000000000000000376c47978271565f56deb45495afa69e59c16ab200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000158` 633 data, err := hex.DecodeString(hexdata) 634 if err != nil { 635 t.Fatal(err) 636 } 637 if len(data)%32 == 0 { 638 t.Errorf("len(data) is %d, want a non-multiple of 32", len(data)) 639 } 640 641 type ReceivedEvent struct { 642 Address common.Address 643 Amount *big.Int 644 Memo []byte 645 } 646 var ev ReceivedEvent 647 648 err = abi.Unpack(&ev, "received", data) 649 if err != nil { 650 t.Error(err) 651 } else { 652 t.Logf("len(data): %d; received event: %+v", len(data), ev) 653 } 654 } 655 656 func TestABI_MethodById(t *testing.T) { 657 const abiJSON = `[ 658 {"type":"function","name":"receive","constant":false,"inputs":[{"name":"memo","type":"bytes"}],"outputs":[],"payable":true,"stateMutability":"payable"}, 659 {"type":"event","name":"received","anonymous":false,"inputs":[{"indexed":false,"name":"sender","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"memo","type":"bytes"}]}, 660 {"type":"function","name":"fixedArrStr","constant":true,"inputs":[{"name":"str","type":"string"},{"name":"fixedArr","type":"uint256[2]"}]}, 661 {"type":"function","name":"fixedArrBytes","constant":true,"inputs":[{"name":"str","type":"bytes"},{"name":"fixedArr","type":"uint256[2]"}]}, 662 {"type":"function","name":"mixedArrStr","constant":true,"inputs":[{"name":"str","type":"string"},{"name":"fixedArr","type":"uint256[2]"},{"name":"dynArr","type":"uint256[]"}]}, 663 {"type":"function","name":"doubleFixedArrStr","constant":true,"inputs":[{"name":"str","type":"string"},{"name":"fixedArr1","type":"uint256[2]"},{"name":"fixedArr2","type":"uint256[3]"}]}, 664 {"type":"function","name":"multipleMixedArrStr","constant":true,"inputs":[{"name":"str","type":"string"},{"name":"fixedArr1","type":"uint256[2]"},{"name":"dynArr","type":"uint256[]"},{"name":"fixedArr2","type":"uint256[3]"}]}, 665 {"type":"function","name":"balance","constant":true}, 666 {"type":"function","name":"send","constant":false,"inputs":[{"name":"amount","type":"uint256"}]}, 667 {"type":"function","name":"test","constant":false,"inputs":[{"name":"number","type":"uint32"}]}, 668 {"type":"function","name":"string","constant":false,"inputs":[{"name":"inputs","type":"string"}]}, 669 {"type":"function","name":"bool","constant":false,"inputs":[{"name":"inputs","type":"bool"}]}, 670 {"type":"function","name":"address","constant":false,"inputs":[{"name":"inputs","type":"address"}]}, 671 {"type":"function","name":"uint64[2]","constant":false,"inputs":[{"name":"inputs","type":"uint64[2]"}]}, 672 {"type":"function","name":"uint64[]","constant":false,"inputs":[{"name":"inputs","type":"uint64[]"}]}, 673 {"type":"function","name":"foo","constant":false,"inputs":[{"name":"inputs","type":"uint32"}]}, 674 {"type":"function","name":"bar","constant":false,"inputs":[{"name":"inputs","type":"uint32"},{"name":"string","type":"uint16"}]}, 675 {"type":"function","name":"_slice","constant":false,"inputs":[{"name":"inputs","type":"uint32[2]"}]}, 676 {"type":"function","name":"__slice256","constant":false,"inputs":[{"name":"inputs","type":"uint256[2]"}]}, 677 {"type":"function","name":"sliceAddress","constant":false,"inputs":[{"name":"inputs","type":"address[]"}]}, 678 {"type":"function","name":"sliceMultiAddress","constant":false,"inputs":[{"name":"a","type":"address[]"},{"name":"b","type":"address[]"}]} 679 ] 680 ` 681 abi, err := JSON(strings.NewReader(abiJSON)) 682 if err != nil { 683 t.Fatal(err) 684 } 685 for name, m := range abi.Methods { 686 a := fmt.Sprintf("%v", m) 687 m2, err := abi.MethodById(m.Id()) 688 if err != nil { 689 t.Fatalf("Failed to look up ABI method: %v", err) 690 } 691 b := fmt.Sprintf("%v", m2) 692 if a != b { 693 t.Errorf("Method %v (id %v) not 'findable' by id in ABI", name, common.ToHex(m.Id())) 694 } 695 } 696 697 }