// packElement packs the given reflect value according to the abi specification in // t. func packElement(t Type, reflectValue reflect.Value) []byte { switch t.T { case IntTy, UintTy: return packNum(reflectValue) case StringTy: return packBytesSlice([]byte(reflectValue.String()), reflectValue.Len()) case AddressTy: if reflectValue.Kind() == reflect.Array { reflectValue = mustArrayToByteSlice(reflectValue) } return common.LeftPadBytes(reflectValue.Bytes(), 32) case BoolTy: if reflectValue.Bool() { return common.LeftPadBytes(common.Big1.Bytes(), 32) } else { return common.LeftPadBytes(common.Big0.Bytes(), 32) } case BytesTy: if reflectValue.Kind() == reflect.Array { reflectValue = mustArrayToByteSlice(reflectValue) } return packBytesSlice(reflectValue.Bytes(), reflectValue.Len()) case FixedBytesTy: if reflectValue.Kind() == reflect.Array { reflectValue = mustArrayToByteSlice(reflectValue) } return common.RightPadBytes(reflectValue.Bytes(), 32) } panic("abi: fatal error") }
func (self *Object) StorageString(str string) []byte { if common.IsHex(str) { return self.storage(common.Hex2Bytes(str[2:])) } else { return self.storage(common.RightPadBytes([]byte(str), 32)) } }
func ecrecoverFunc(in []byte) []byte { in = common.RightPadBytes(in, 128) // "in" is (hash, v, r, s), each 32 bytes // but for ecrecover we want (r, s, v) r := common.BytesToBig(in[64:96]) s := common.BytesToBig(in[96:128]) // Treat V as a 256bit integer vbig := common.Bytes2Big(in[32:64]) v := byte(vbig.Uint64()) if !crypto.ValidateSignatureValues(v, r, s) { glog.V(logger.Debug).Infof("EC RECOVER FAIL: v, r or s value invalid") return nil } // v needs to be at the end and normalized for libsecp256k1 vbignormal := new(big.Int).Sub(vbig, big.NewInt(27)) vnormal := byte(vbignormal.Uint64()) rsv := append(in[64:128], vnormal) pubKey, err := crypto.Ecrecover(in[:32], rsv) // make sure the public key is a valid one if err != nil { glog.V(logger.Error).Infof("EC RECOVER FAIL: ", err) return nil } // the first byte of pubkey is bitcoin heritage return common.LeftPadBytes(crypto.Sha3(pubKey[1:])[12:], 32) }
func TestMultiReturnWithSlice(t *testing.T) { const definition = `[ { "name" : "multi", "constant" : false, "outputs": [ { "name": "Int", "type": "uint256" }, { "name": "String", "type": "string" } ] }]` abi, err := JSON(strings.NewReader(definition)) if err != nil { t.Fatal(err) } // using buff to make the code readable buff := new(bytes.Buffer) buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000001")) buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000040")) buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000005")) stringOut := "hello" buff.Write(common.RightPadBytes([]byte(stringOut), 32)) var inter []interface{} err = abi.Unpack(&inter, "multi", buff.Bytes()) if err != nil { t.Error(err) } if len(inter) != 2 { t.Fatal("expected 2 results got", len(inter)) } if num, ok := inter[0].(*big.Int); !ok || num.Cmp(big.NewInt(1)) != 0 { t.Error("expected index 0 to be 1 got", num) } if str, ok := inter[1].(string); !ok || str != stringOut { t.Error("expected index 1 to be", stringOut, "got", str) } }
// getData returns a slice from the data based on the start and size and pads // up to size with zero's. This function is overflow safe. func getData(data []byte, start, size *big.Int) []byte { dlen := big.NewInt(int64(len(data))) s := common.BigMin(start, dlen) e := common.BigMin(new(big.Int).Add(s, size), dlen) return common.RightPadBytes(data[s.Uint64():e.Uint64()], int(size.Uint64())) }
func TestMultiReturnWithStruct(t *testing.T) { const definition = `[ { "name" : "multi", "constant" : false, "outputs": [ { "name": "Int", "type": "uint256" }, { "name": "String", "type": "string" } ] }]` abi, err := JSON(strings.NewReader(definition)) if err != nil { t.Fatal(err) } // using buff to make the code readable buff := new(bytes.Buffer) buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000001")) buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000040")) buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000005")) stringOut := "hello" buff.Write(common.RightPadBytes([]byte(stringOut), 32)) var inter struct { Int *big.Int String string } err = abi.Unpack(&inter, "multi", buff.Bytes()) if err != nil { t.Error(err) } if inter.Int == nil || inter.Int.Cmp(big.NewInt(1)) != 0 { t.Error("expected Int to be 1 got", inter.Int) } if inter.String != stringOut { t.Error("expected String to be", stringOut, "got", inter.String) } var reversed struct { String string Int *big.Int } err = abi.Unpack(&reversed, "multi", buff.Bytes()) if err != nil { t.Error(err) } if reversed.Int == nil || reversed.Int.Cmp(big.NewInt(1)) != 0 { t.Error("expected Int to be 1 got", reversed.Int) } if reversed.String != stringOut { t.Error("expected String to be", stringOut, "got", reversed.String) } }
// packBytesSlice packs the given bytes as [L, V] as the canonical representation // bytes slice func packBytesSlice(bytes []byte, l int) []byte { len := packNum(reflect.ValueOf(l)) return append(len, common.RightPadBytes(bytes, (l+31)/32*32)...) }
func TestUnmarshal(t *testing.T) { const definition = `[ { "name" : "int", "constant" : false, "outputs": [ { "type": "uint256" } ] }, { "name" : "bool", "constant" : false, "outputs": [ { "type": "bool" } ] }, { "name" : "bytes", "constant" : false, "outputs": [ { "type": "bytes" } ] }, { "name" : "fixed", "constant" : false, "outputs": [ { "type": "bytes32" } ] }, { "name" : "multi", "constant" : false, "outputs": [ { "type": "bytes" }, { "type": "bytes" } ] }, { "name" : "addressSliceSingle", "constant" : false, "outputs": [ { "type": "address[]" } ] }, { "name" : "addressSliceDouble", "constant" : false, "outputs": [ { "name": "a", "type": "address[]" }, { "name": "b", "type": "address[]" } ] }, { "name" : "mixedBytes", "constant" : true, "outputs": [ { "name": "a", "type": "bytes" }, { "name": "b", "type": "bytes32" } ] }]` abi, err := JSON(strings.NewReader(definition)) if err != nil { t.Fatal(err) } buff := new(bytes.Buffer) // marshal int var Int *big.Int err = abi.Unpack(&Int, "int", common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000001")) if err != nil { t.Error(err) } if Int == nil || Int.Cmp(big.NewInt(1)) != 0 { t.Error("expected Int to be 1 got", Int) } // marshal bool var Bool bool err = abi.Unpack(&Bool, "bool", common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000001")) if err != nil { t.Error(err) } if !Bool { t.Error("expected Bool to be true") } // marshal dynamic bytes max length 32 buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020")) buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020")) bytesOut := common.RightPadBytes([]byte("hello"), 32) buff.Write(bytesOut) var Bytes []byte err = abi.Unpack(&Bytes, "bytes", buff.Bytes()) if err != nil { t.Error(err) } if !bytes.Equal(Bytes, bytesOut) { t.Errorf("expected %x got %x", bytesOut, Bytes) } // marshall dynamic bytes max length 64 buff.Reset() buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020")) buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000040")) bytesOut = common.RightPadBytes([]byte("hello"), 64) buff.Write(bytesOut) err = abi.Unpack(&Bytes, "bytes", buff.Bytes()) if err != nil { t.Error(err) } if !bytes.Equal(Bytes, bytesOut) { t.Errorf("expected %x got %x", bytesOut, Bytes) } // marshall dynamic bytes max length 63 buff.Reset() buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020")) buff.Write(common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000003f")) bytesOut = common.RightPadBytes([]byte("hello"), 63) buff.Write(bytesOut) err = abi.Unpack(&Bytes, "bytes", buff.Bytes()) if err != nil { t.Error(err) } if !bytes.Equal(Bytes, bytesOut) { t.Errorf("expected %x got %x", bytesOut, Bytes) } // marshal dynamic bytes output empty err = abi.Unpack(&Bytes, "bytes", nil) if err == nil { t.Error("expected error") } // marshal dynamic bytes length 5 buff.Reset() buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020")) buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000005")) buff.Write(common.RightPadBytes([]byte("hello"), 32)) err = abi.Unpack(&Bytes, "bytes", buff.Bytes()) if err != nil { t.Error(err) } if !bytes.Equal(Bytes, []byte("hello")) { t.Errorf("expected %x got %x", bytesOut, Bytes) } // marshal dynamic bytes length 5 buff.Reset() buff.Write(common.RightPadBytes([]byte("hello"), 32)) var hash common.Hash err = abi.Unpack(&hash, "fixed", buff.Bytes()) if err != nil { t.Error(err) } helloHash := common.BytesToHash(common.RightPadBytes([]byte("hello"), 32)) if hash != helloHash { t.Errorf("Expected %x to equal %x", hash, helloHash) } // marshal error buff.Reset() buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020")) err = abi.Unpack(&Bytes, "bytes", buff.Bytes()) if err == nil { t.Error("expected error") } err = abi.Unpack(&Bytes, "multi", make([]byte, 64)) if err == nil { t.Error("expected error") } // marshal mixed bytes buff.Reset() buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000040")) fixed := common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000001") buff.Write(fixed) buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020")) bytesOut = common.RightPadBytes([]byte("hello"), 32) buff.Write(bytesOut) var out []interface{} err = abi.Unpack(&out, "mixedBytes", buff.Bytes()) if err != nil { t.Fatal("didn't expect error:", err) } if !bytes.Equal(bytesOut, out[0].([]byte)) { t.Errorf("expected %x, got %x", bytesOut, out[0]) } if !bytes.Equal(fixed, out[1].([]byte)) { t.Errorf("expected %x, got %x", fixed, out[1]) } // marshal address slice buff.Reset() buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020")) // offset buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000001")) // size buff.Write(common.Hex2Bytes("0000000000000000000000000100000000000000000000000000000000000000")) var outAddr []common.Address err = abi.Unpack(&outAddr, "addressSliceSingle", buff.Bytes()) if err != nil { t.Fatal("didn't expect error:", err) } if len(outAddr) != 1 { t.Fatal("expected 1 item, got", len(outAddr)) } if outAddr[0] != (common.Address{1}) { t.Errorf("expected %x, got %x", common.Address{1}, outAddr[0]) } // marshal multiple address slice buff.Reset() buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000040")) // offset buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000080")) // offset buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000001")) // size buff.Write(common.Hex2Bytes("0000000000000000000000000100000000000000000000000000000000000000")) buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000002")) // size buff.Write(common.Hex2Bytes("0000000000000000000000000200000000000000000000000000000000000000")) buff.Write(common.Hex2Bytes("0000000000000000000000000300000000000000000000000000000000000000")) var outAddrStruct struct { A []common.Address B []common.Address } err = abi.Unpack(&outAddrStruct, "addressSliceDouble", buff.Bytes()) if err != nil { t.Fatal("didn't expect error:", err) } if len(outAddrStruct.A) != 1 { t.Fatal("expected 1 item, got", len(outAddrStruct.A)) } if outAddrStruct.A[0] != (common.Address{1}) { t.Errorf("expected %x, got %x", common.Address{1}, outAddrStruct.A[0]) } if len(outAddrStruct.B) != 2 { t.Fatal("expected 1 item, got", len(outAddrStruct.B)) } if outAddrStruct.B[0] != (common.Address{2}) { t.Errorf("expected %x, got %x", common.Address{2}, outAddrStruct.B[0]) } if outAddrStruct.B[1] != (common.Address{3}) { t.Errorf("expected %x, got %x", common.Address{3}, outAddrStruct.B[1]) } // marshal invalid address slice buff.Reset() buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000100")) err = abi.Unpack(&outAddr, "addressSliceSingle", buff.Bytes()) if err == nil { t.Fatal("expected error:", err) } }
func TestInputVariableInputLength(t *testing.T) { const definition = `[ { "type" : "function", "name" : "strOne", "constant" : true, "inputs" : [ { "name" : "str", "type" : "string" } ] }, { "type" : "function", "name" : "bytesOne", "constant" : true, "inputs" : [ { "name" : "str", "type" : "bytes" } ] }, { "type" : "function", "name" : "strTwo", "constant" : true, "inputs" : [ { "name" : "str", "type" : "string" }, { "name" : "str1", "type" : "string" } ] } ]` abi, err := JSON(strings.NewReader(definition)) if err != nil { t.Fatal(err) } // test one string strin := "hello world" strpack, err := abi.Pack("strOne", strin) if err != nil { t.Error(err) } offset := make([]byte, 32) offset[31] = 32 length := make([]byte, 32) length[31] = byte(len(strin)) value := common.RightPadBytes([]byte(strin), 32) exp := append(offset, append(length, value...)...) // ignore first 4 bytes of the output. This is the function identifier strpack = strpack[4:] if !bytes.Equal(strpack, exp) { t.Errorf("expected %x, got %x\n", exp, strpack) } // test one bytes btspack, err := abi.Pack("bytesOne", []byte(strin)) if err != nil { t.Error(err) } // ignore first 4 bytes of the output. This is the function identifier btspack = btspack[4:] if !bytes.Equal(btspack, exp) { t.Errorf("expected %x, got %x\n", exp, btspack) } // test two strings str1 := "hello" str2 := "world" str2pack, err := abi.Pack("strTwo", str1, str2) if err != nil { t.Error(err) } offset1 := make([]byte, 32) offset1[31] = 64 length1 := make([]byte, 32) length1[31] = byte(len(str1)) value1 := common.RightPadBytes([]byte(str1), 32) offset2 := make([]byte, 32) offset2[31] = 128 length2 := make([]byte, 32) length2[31] = byte(len(str2)) value2 := common.RightPadBytes([]byte(str2), 32) exp2 := append(offset1, offset2...) exp2 = append(exp2, append(length1, value1...)...) exp2 = append(exp2, append(length2, value2...)...) // ignore first 4 bytes of the output. This is the function identifier str2pack = str2pack[4:] if !bytes.Equal(str2pack, exp2) { t.Errorf("expected %x, got %x\n", exp, str2pack) } // test two strings, first > 32, second < 32 str1 = strings.Repeat("a", 33) str2pack, err = abi.Pack("strTwo", str1, str2) if err != nil { t.Error(err) } offset1 = make([]byte, 32) offset1[31] = 64 length1 = make([]byte, 32) length1[31] = byte(len(str1)) value1 = common.RightPadBytes([]byte(str1), 64) offset2[31] = 160 exp2 = append(offset1, offset2...) exp2 = append(exp2, append(length1, value1...)...) exp2 = append(exp2, append(length2, value2...)...) // ignore first 4 bytes of the output. This is the function identifier str2pack = str2pack[4:] if !bytes.Equal(str2pack, exp2) { t.Errorf("expected %x, got %x\n", exp, str2pack) } // test two strings, first > 32, second >32 str1 = strings.Repeat("a", 33) str2 = strings.Repeat("a", 33) str2pack, err = abi.Pack("strTwo", str1, str2) if err != nil { t.Error(err) } offset1 = make([]byte, 32) offset1[31] = 64 length1 = make([]byte, 32) length1[31] = byte(len(str1)) value1 = common.RightPadBytes([]byte(str1), 64) offset2 = make([]byte, 32) offset2[31] = 160 length2 = make([]byte, 32) length2[31] = byte(len(str2)) value2 = common.RightPadBytes([]byte(str2), 64) exp2 = append(offset1, offset2...) exp2 = append(exp2, append(length1, value1...)...) exp2 = append(exp2, append(length2, value2...)...) // ignore first 4 bytes of the output. This is the function identifier str2pack = str2pack[4:] if !bytes.Equal(str2pack, exp2) { t.Errorf("expected %x, got %x\n", exp, str2pack) } }
// quick helper padding func pad(input []byte, size int, left bool) []byte { if left { return common.LeftPadBytes(input, size) } return common.RightPadBytes(input, size) }
func (self *XEth) ToAscii(str string) string { padded := common.RightPadBytes([]byte(str), 32) return "0x" + common.ToHex(padded) }