From a5330fe0c569b75cb8a524f60f7e8dc06498262b Mon Sep 17 00:00:00 2001 From: Yondon Fu Date: Thu, 12 Oct 2017 10:58:53 -0400 Subject: [PATCH] accounts/abi: include fixed array size in offset for dynamic type --- accounts/abi/abi_test.go | 50 ++++++++++++++++++++++++++++++++++++++++ accounts/abi/method.go | 13 ++++++++++- 2 files changed, 62 insertions(+), 1 deletion(-) diff --git a/accounts/abi/abi_test.go b/accounts/abi/abi_test.go index a3aa9446e..5420eb19a 100644 --- a/accounts/abi/abi_test.go +++ b/accounts/abi/abi_test.go @@ -367,6 +367,56 @@ func TestInputVariableInputLength(t *testing.T) { } } +func TestInputFixedArrayAndVariableInputLength(t *testing.T) { + const definition = `[ + { "type" : "function", "name" : "fixedArrStr", "constant" : true, "inputs" : [ { "name" : "str", "type" : "string" }, { "name" : "fixedArr", "type" : "uint256[2]" } ] }, + { "type" : "function", "name" : "fixedArrBytes", "constant" : true, "inputs" : [ { "name" : "str", "type" : "bytes" }, { "name" : "fixedArr", "type" : "uint256[2]" } ] } + ]` + + abi, err := JSON(strings.NewReader(definition)) + if err != nil { + t.Error(err) + } + + // test fixed array of uint256 and a string + arrin := [2]*big.Int{big.NewInt(1), big.NewInt(2)} + strin := "hello world" + fixedArrStrPack, err := abi.Pack("fixedArrStr", strin, arrin) + if err != nil { + t.Error(err) + } + + offset := make([]byte, 32) + offset[31] = 96 + length := make([]byte, 32) + length[31] = byte(len(strin)) + strvalue := common.RightPadBytes([]byte(strin), 32) + arrinvalue1 := common.LeftPadBytes(arrin[0].Bytes(), 32) + arrinvalue2 := common.LeftPadBytes(arrin[1].Bytes(), 32) + exp := append(offset, arrinvalue1...) + exp = append(exp, arrinvalue2...) + exp = append(exp, append(length, strvalue...)...) + + // ignore first 4 bytes of the output. This is the function identifier + fixedArrStrPack = fixedArrStrPack[4:] + if !bytes.Equal(fixedArrStrPack, exp) { + t.Errorf("expected %x, got %x\n", exp, fixedArrStrPack) + } + + // test fixed array of uint256 and a byte array + bytesin := []byte(strin) + fixedArrBytesPack, err := abi.Pack("fixedArrBytes", bytesin, arrin) + if err != nil { + t.Error(err) + } + + // ignore first 4 bytes of the output. This is the function identifier + fixedArrBytesPack = fixedArrBytesPack[4:] + if !bytes.Equal(fixedArrBytesPack, exp) { + t.Errorf("expected %x, got %x\n", exp, fixedArrBytesPack) + } +} + func TestDefaultFunctionParsing(t *testing.T) { const definition = `[{ "name" : "balance" }]` diff --git a/accounts/abi/method.go b/accounts/abi/method.go index 62b3d2957..32077e8a6 100644 --- a/accounts/abi/method.go +++ b/accounts/abi/method.go @@ -48,6 +48,16 @@ func (method Method) pack(args ...interface{}) ([]byte, error) { // output. This is used for strings and bytes types input. var variableInput []byte + // input offset is the bytes offset for packed output + inputOffset := 0 + for _, input := range method.Inputs { + if input.Type.IsArray { + inputOffset += (32 * input.Type.SliceSize) + } else { + inputOffset += 32 + } + } + var ret []byte for i, a := range args { input := method.Inputs[i] @@ -60,7 +70,8 @@ func (method Method) pack(args ...interface{}) ([]byte, error) { // check for a slice type (string, bytes, slice) if input.Type.requiresLengthPrefix() { // calculate the offset - offset := len(method.Inputs)*32 + len(variableInput) + offset := inputOffset + len(variableInput) + // set the offset ret = append(ret, packNum(reflect.ValueOf(offset))...) // Append the packed output to the variable input. The variable input