Bladeren bron

accounts/abi: include fixed array size in offset for dynamic type

Yondon Fu 8 jaren geleden
bovenliggende
commit
a5330fe0c5
2 gewijzigde bestanden met toevoegingen van 62 en 1 verwijderingen
  1. 50 0
      accounts/abi/abi_test.go
  2. 12 1
      accounts/abi/method.go

+ 50 - 0
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" }]`
 

+ 12 - 1
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