Browse Source

accounts/abi: added abi test cases, minor bug fixes (#20903)

* accounts/abi: added documentation

* accounts/abi: reduced usage of arguments.LengthNonIndexed

* accounts/abi: simplified reflection logic

* accounts/abi: moved testjson data into global declaration

* accounts/abi: removed duplicate test cases

* accounts/abi: reworked abi tests

* accounts/abi: added more tests for abi packing

* accounts/abi/bind: refactored base tests

* accounts/abi: run pack tests as subtests

* accounts/abi: removed duplicate tests

* accounts/abi: removed unnused arguments.LengthNonIndexed

Due to refactors to the code, we do not need the arguments.LengthNonIndexed function anymore.
You can still get the length by calling len(arguments.NonIndexed())

* accounts/abi: added type test

* accounts/abi: modified unpack test to pack test

* accounts/abi: length check on arrayTy

* accounts/abi: test invalid abi

* accounts/abi: fixed rebase error

* accounts/abi: fixed rebase errors

* accounts/abi: removed unused definition

* accounts/abi: merged packing/unpacking tests

* accounts/abi: fixed [][][32]bytes encoding

* accounts/abi: added tuple test cases

* accounts/abi: renamed getMockLog -> newMockLog

* accounts/abi: removed duplicate test

* accounts/abi: bools -> booleans
Marius van der Wijden 5 years ago
parent
commit
e32ee6ac05

+ 144 - 107
accounts/abi/abi_test.go

@@ -32,12 +32,7 @@ import (
 
 const jsondata = `
 [
-	{ "type" : "function", "name" : "balance", "stateMutability" : "view" },
-	{ "type" : "function", "name" : "send", "inputs" : [ { "name" : "amount", "type" : "uint256" } ] }
-]`
-
-const jsondata2 = `
-[
+	{ "type" : "function", "name" : "", "stateMutability" : "view" },
 	{ "type" : "function", "name" : "balance", "stateMutability" : "view" },
 	{ "type" : "function", "name" : "send", "inputs" : [ { "name" : "amount", "type" : "uint256" } ] },
 	{ "type" : "function", "name" : "test", "inputs" : [ { "name" : "number", "type" : "uint32" } ] },
@@ -46,6 +41,7 @@ const jsondata2 = `
 	{ "type" : "function", "name" : "address", "inputs" : [ { "name" : "inputs", "type" : "address" } ] },
 	{ "type" : "function", "name" : "uint64[2]", "inputs" : [ { "name" : "inputs", "type" : "uint64[2]" } ] },
 	{ "type" : "function", "name" : "uint64[]", "inputs" : [ { "name" : "inputs", "type" : "uint64[]" } ] },
+	{ "type" : "function", "name" : "int8", "inputs" : [ { "name" : "inputs", "type" : "int8" } ] },
 	{ "type" : "function", "name" : "foo", "inputs" : [ { "name" : "inputs", "type" : "uint32" } ] },
 	{ "type" : "function", "name" : "bar", "inputs" : [ { "name" : "inputs", "type" : "uint32" }, { "name" : "string", "type" : "uint16" } ] },
 	{ "type" : "function", "name" : "slice", "inputs" : [ { "name" : "inputs", "type" : "uint32[2]" } ] },
@@ -54,16 +50,68 @@ const jsondata2 = `
 	{ "type" : "function", "name" : "sliceMultiAddress", "inputs" : [ { "name" : "a", "type" : "address[]" }, { "name" : "b", "type" : "address[]" } ] },
 	{ "type" : "function", "name" : "nestedArray", "inputs" : [ { "name" : "a", "type" : "uint256[2][2]" }, { "name" : "b", "type" : "address[]" } ] },
 	{ "type" : "function", "name" : "nestedArray2", "inputs" : [ { "name" : "a", "type" : "uint8[][2]" } ] },
-	{ "type" : "function", "name" : "nestedSlice", "inputs" : [ { "name" : "a", "type" : "uint8[][]" } ] }
+	{ "type" : "function", "name" : "nestedSlice", "inputs" : [ { "name" : "a", "type" : "uint8[][]" } ] },
+	{ "type" : "function", "name" : "receive", "inputs" : [ { "name" : "memo", "type" : "bytes" }], "outputs" : [], "payable" : true, "stateMutability" : "payable" },
+	{ "type" : "function", "name" : "fixedArrStr", "stateMutability" : "view", "inputs" : [ { "name" : "str", "type" : "string" }, { "name" : "fixedArr", "type" : "uint256[2]" } ] },
+	{ "type" : "function", "name" : "fixedArrBytes", "stateMutability" : "view", "inputs" : [ { "name" : "bytes", "type" : "bytes" }, { "name" : "fixedArr", "type" : "uint256[2]" } ] },
+	{ "type" : "function", "name" : "mixedArrStr", "stateMutability" : "view", "inputs" : [ { "name" : "str", "type" : "string" }, { "name" : "fixedArr", "type" : "uint256[2]" }, { "name" : "dynArr", "type" : "uint256[]" } ] },
+	{ "type" : "function", "name" : "doubleFixedArrStr", "stateMutability" : "view", "inputs" : [ { "name" : "str", "type" : "string" }, { "name" : "fixedArr1", "type" : "uint256[2]" }, { "name" : "fixedArr2", "type" : "uint256[3]" } ] },
+	{ "type" : "function", "name" : "multipleMixedArrStr", "stateMutability" : "view", "inputs" : [ { "name" : "str", "type" : "string" }, { "name" : "fixedArr1", "type" : "uint256[2]" }, { "name" : "dynArr", "type" : "uint256[]" }, { "name" : "fixedArr2", "type" : "uint256[3]" } ] }
 ]`
 
+var (
+	Uint256, _    = NewType("uint256", "", nil)
+	Uint32, _     = NewType("uint32", "", nil)
+	Uint16, _     = NewType("uint16", "", nil)
+	String, _     = NewType("string", "", nil)
+	Bool, _       = NewType("bool", "", nil)
+	Bytes, _      = NewType("bytes", "", nil)
+	Address, _    = NewType("address", "", nil)
+	Uint64Arr, _  = NewType("uint64[]", "", nil)
+	AddressArr, _ = NewType("address[]", "", nil)
+	Int8, _       = NewType("int8", "", nil)
+	// Special types for testing
+	Uint32Arr2, _       = NewType("uint32[2]", "", nil)
+	Uint64Arr2, _       = NewType("uint64[2]", "", nil)
+	Uint256Arr, _       = NewType("uint256[]", "", nil)
+	Uint256Arr2, _      = NewType("uint256[2]", "", nil)
+	Uint256Arr3, _      = NewType("uint256[3]", "", nil)
+	Uint256ArrNested, _ = NewType("uint256[2][2]", "", nil)
+	Uint8ArrNested, _   = NewType("uint8[][2]", "", nil)
+	Uint8SliceNested, _ = NewType("uint8[][]", "", nil)
+)
+
+var methods = map[string]Method{
+	"":                    NewMethod("", "", Function, "view", false, false, nil, nil),
+	"balance":             NewMethod("balance", "balance", Function, "view", false, false, nil, nil),
+	"send":                NewMethod("send", "send", Function, "", false, false, []Argument{{"amount", Uint256, false}}, nil),
+	"test":                NewMethod("test", "test", Function, "", false, false, []Argument{{"number", Uint32, false}}, nil),
+	"string":              NewMethod("string", "string", Function, "", false, false, []Argument{{"inputs", String, false}}, nil),
+	"bool":                NewMethod("bool", "bool", Function, "", false, false, []Argument{{"inputs", Bool, false}}, nil),
+	"address":             NewMethod("address", "address", Function, "", false, false, []Argument{{"inputs", Address, false}}, nil),
+	"uint64[]":            NewMethod("uint64[]", "uint64[]", Function, "", false, false, []Argument{{"inputs", Uint64Arr, false}}, nil),
+	"uint64[2]":           NewMethod("uint64[2]", "uint64[2]", Function, "", false, false, []Argument{{"inputs", Uint64Arr2, false}}, nil),
+	"int8":                NewMethod("int8", "int8", Function, "", false, false, []Argument{{"inputs", Int8, false}}, nil),
+	"foo":                 NewMethod("foo", "foo", Function, "", false, false, []Argument{{"inputs", Uint32, false}}, nil),
+	"bar":                 NewMethod("bar", "bar", Function, "", false, false, []Argument{{"inputs", Uint32, false}, {"string", Uint16, false}}, nil),
+	"slice":               NewMethod("slice", "slice", Function, "", false, false, []Argument{{"inputs", Uint32Arr2, false}}, nil),
+	"slice256":            NewMethod("slice256", "slice256", Function, "", false, false, []Argument{{"inputs", Uint256Arr2, false}}, nil),
+	"sliceAddress":        NewMethod("sliceAddress", "sliceAddress", Function, "", false, false, []Argument{{"inputs", AddressArr, false}}, nil),
+	"sliceMultiAddress":   NewMethod("sliceMultiAddress", "sliceMultiAddress", Function, "", false, false, []Argument{{"a", AddressArr, false}, {"b", AddressArr, false}}, nil),
+	"nestedArray":         NewMethod("nestedArray", "nestedArray", Function, "", false, false, []Argument{{"a", Uint256ArrNested, false}, {"b", AddressArr, false}}, nil),
+	"nestedArray2":        NewMethod("nestedArray2", "nestedArray2", Function, "", false, false, []Argument{{"a", Uint8ArrNested, false}}, nil),
+	"nestedSlice":         NewMethod("nestedSlice", "nestedSlice", Function, "", false, false, []Argument{{"a", Uint8SliceNested, false}}, nil),
+	"receive":             NewMethod("receive", "receive", Function, "payable", false, true, []Argument{{"memo", Bytes, false}}, []Argument{}),
+	"fixedArrStr":         NewMethod("fixedArrStr", "fixedArrStr", Function, "view", false, false, []Argument{{"str", String, false}, {"fixedArr", Uint256Arr2, false}}, nil),
+	"fixedArrBytes":       NewMethod("fixedArrBytes", "fixedArrBytes", Function, "view", false, false, []Argument{{"bytes", Bytes, false}, {"fixedArr", Uint256Arr2, false}}, nil),
+	"mixedArrStr":         NewMethod("mixedArrStr", "mixedArrStr", Function, "view", false, false, []Argument{{"str", String, false}, {"fixedArr", Uint256Arr2, false}, {"dynArr", Uint256Arr, false}}, nil),
+	"doubleFixedArrStr":   NewMethod("doubleFixedArrStr", "doubleFixedArrStr", Function, "view", false, false, []Argument{{"str", String, false}, {"fixedArr1", Uint256Arr2, false}, {"fixedArr2", Uint256Arr3, false}}, nil),
+	"multipleMixedArrStr": NewMethod("multipleMixedArrStr", "multipleMixedArrStr", Function, "view", false, false, []Argument{{"str", String, false}, {"fixedArr1", Uint256Arr2, false}, {"dynArr", Uint256Arr, false}, {"fixedArr2", Uint256Arr3, false}}, nil),
+}
+
 func TestReader(t *testing.T) {
-	Uint256, _ := NewType("uint256", "", nil)
 	abi := ABI{
-		Methods: map[string]Method{
-			"balance": NewMethod("balance", "balance", Function, "view", false, false, nil, nil),
-			"send":    NewMethod("send", "send", Function, "", false, false, []Argument{{"amount", Uint256, false}}, nil),
-		},
+		Methods: methods,
 	}
 
 	exp, err := JSON(strings.NewReader(jsondata))
@@ -71,7 +119,6 @@ func TestReader(t *testing.T) {
 		t.Error(err)
 	}
 
-	// deep equal fails for some reason
 	for name, expM := range exp.Methods {
 		gotM, exist := abi.Methods[name]
 		if !exist {
@@ -93,8 +140,58 @@ func TestReader(t *testing.T) {
 	}
 }
 
+func TestInvalidABI(t *testing.T) {
+	json := `[{ "type" : "function", "name" : "", "constant" : fals }]`
+	_, err := JSON(strings.NewReader(json))
+	if err == nil {
+		t.Fatal("invalid json should produce error")
+	}
+	json2 := `[{ "type" : "function", "name" : "send", "constant" : false, "inputs" : [ { "name" : "amount", "typ" : "uint256" } ] }]`
+	_, err = JSON(strings.NewReader(json2))
+	if err == nil {
+		t.Fatal("invalid json should produce error")
+	}
+}
+
+// TestConstructor tests a constructor function.
+// The test is based on the following contract:
+// 	contract TestConstructor {
+// 		constructor(uint256 a, uint256 b) public{}
+//	}
+func TestConstructor(t *testing.T) {
+	json := `[{	"inputs": [{"internalType": "uint256","name": "a","type": "uint256"	},{	"internalType": "uint256","name": "b","type": "uint256"}],"stateMutability": "nonpayable","type": "constructor"}]`
+	method := NewMethod("", "", Constructor, "nonpayable", false, false, []Argument{{"a", Uint256, false}, {"b", Uint256, false}}, nil)
+	// Test from JSON
+	abi, err := JSON(strings.NewReader(json))
+	if err != nil {
+		t.Fatal(err)
+	}
+	if !reflect.DeepEqual(abi.Constructor, method) {
+		t.Error("Missing expected constructor")
+	}
+	// Test pack/unpack
+	packed, err := abi.Pack("", big.NewInt(1), big.NewInt(2))
+	if err != nil {
+		t.Error(err)
+	}
+	v := struct {
+		A *big.Int
+		B *big.Int
+	}{new(big.Int), new(big.Int)}
+	//abi.Unpack(&v, "", packed)
+	if err := abi.Constructor.Inputs.Unpack(&v, packed); err != nil {
+		t.Error(err)
+	}
+	if !reflect.DeepEqual(v.A, big.NewInt(1)) {
+		t.Error("Unable to pack/unpack from constructor")
+	}
+	if !reflect.DeepEqual(v.B, big.NewInt(2)) {
+		t.Error("Unable to pack/unpack from constructor")
+	}
+}
+
 func TestTestNumbers(t *testing.T) {
-	abi, err := JSON(strings.NewReader(jsondata2))
+	abi, err := JSON(strings.NewReader(jsondata))
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -130,44 +227,7 @@ func TestTestNumbers(t *testing.T) {
 	}
 }
 
-func TestTestString(t *testing.T) {
-	abi, err := JSON(strings.NewReader(jsondata2))
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	if _, err := abi.Pack("string", "hello world"); err != nil {
-		t.Error(err)
-	}
-}
-
-func TestTestBool(t *testing.T) {
-	abi, err := JSON(strings.NewReader(jsondata2))
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	if _, err := abi.Pack("bool", true); err != nil {
-		t.Error(err)
-	}
-}
-
-func TestTestSlice(t *testing.T) {
-	abi, err := JSON(strings.NewReader(jsondata2))
-	if err != nil {
-		t.Fatal(err)
-	}
-	slice := make([]uint64, 2)
-	if _, err := abi.Pack("uint64[2]", slice); err != nil {
-		t.Error(err)
-	}
-	if _, err := abi.Pack("uint64[]", slice); err != nil {
-		t.Error(err)
-	}
-}
-
 func TestMethodSignature(t *testing.T) {
-	String, _ := NewType("string", "", nil)
 	m := NewMethod("foo", "foo", Function, "", false, false, []Argument{{"bar", String, false}, {"baz", String, false}}, nil)
 	exp := "foo(string,string)"
 	if m.Sig != exp {
@@ -179,8 +239,7 @@ func TestMethodSignature(t *testing.T) {
 		t.Errorf("expected ids to match %x != %x", m.ID, idexp)
 	}
 
-	uintt, _ := NewType("uint256", "", nil)
-	m = NewMethod("foo", "foo", Function, "", false, false, []Argument{{"bar", uintt, false}}, nil)
+	m = NewMethod("foo", "foo", Function, "", false, false, []Argument{{"bar", Uint256, false}}, nil)
 	exp = "foo(uint256)"
 	if m.Sig != exp {
 		t.Error("signature mismatch", exp, "!=", m.Sig)
@@ -230,7 +289,7 @@ func TestOverloadedMethodSignature(t *testing.T) {
 }
 
 func TestMultiPack(t *testing.T) {
-	abi, err := JSON(strings.NewReader(jsondata2))
+	abi, err := JSON(strings.NewReader(jsondata))
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -395,15 +454,7 @@ 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]" } ] },
-    { "type" : "function", "name" : "mixedArrStr", "constant" : true, "inputs" : [ { "name" : "str", "type" : "string" }, { "name" : "fixedArr", "type": "uint256[2]" }, { "name" : "dynArr", "type": "uint256[]" } ] },
-    { "type" : "function", "name" : "doubleFixedArrStr", "constant" : true, "inputs" : [ { "name" : "str", "type" : "string" }, { "name" : "fixedArr1", "type": "uint256[2]" }, { "name" : "fixedArr2", "type": "uint256[3]" } ] },
-    { "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]" } ] }
-	]`
-
-	abi, err := JSON(strings.NewReader(definition))
+	abi, err := JSON(strings.NewReader(jsondata))
 	if err != nil {
 		t.Error(err)
 	}
@@ -597,8 +648,6 @@ func TestBareEvents(t *testing.T) {
 	{ "type" : "event", "name" : "tuple", "inputs" : [{ "indexed":false, "name":"t", "type":"tuple", "components":[{"name":"a", "type":"uint256"}] }, { "indexed":true, "name":"arg1", "type":"address" }] }
 	]`
 
-	arg0, _ := NewType("uint256", "", nil)
-	arg1, _ := NewType("address", "", nil)
 	tuple, _ := NewType("tuple", "", []ArgumentMarshaling{{Name: "a", Type: "uint256"}})
 
 	expectedEvents := map[string]struct {
@@ -608,12 +657,12 @@ func TestBareEvents(t *testing.T) {
 		"balance": {false, nil},
 		"anon":    {true, nil},
 		"args": {false, []Argument{
-			{Name: "arg0", Type: arg0, Indexed: false},
-			{Name: "arg1", Type: arg1, Indexed: true},
+			{Name: "arg0", Type: Uint256, Indexed: false},
+			{Name: "arg1", Type: Address, Indexed: true},
 		}},
 		"tuple": {false, []Argument{
 			{Name: "t", Type: tuple, Indexed: false},
-			{Name: "arg1", Type: arg1, Indexed: true},
+			{Name: "arg1", Type: Address, Indexed: true},
 		}},
 	}
 
@@ -886,31 +935,7 @@ func TestUnpackIntoMapNamingConflict(t *testing.T) {
 }
 
 func TestABI_MethodById(t *testing.T) {
-	const abiJSON = `[
-		{"type":"function","name":"receive","constant":false,"inputs":[{"name":"memo","type":"bytes"}],"outputs":[],"payable":true,"stateMutability":"payable"},
-		{"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"}]},
-		{"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]"}]},
-		{"type":"function","name":"mixedArrStr","constant":true,"inputs":[{"name":"str","type":"string"},{"name":"fixedArr","type":"uint256[2]"},{"name":"dynArr","type":"uint256[]"}]},
-		{"type":"function","name":"doubleFixedArrStr","constant":true,"inputs":[{"name":"str","type":"string"},{"name":"fixedArr1","type":"uint256[2]"},{"name":"fixedArr2","type":"uint256[3]"}]},
-		{"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]"}]},
-		{"type":"function","name":"balance","constant":true},
-		{"type":"function","name":"send","constant":false,"inputs":[{"name":"amount","type":"uint256"}]},
-		{"type":"function","name":"test","constant":false,"inputs":[{"name":"number","type":"uint32"}]},
-		{"type":"function","name":"string","constant":false,"inputs":[{"name":"inputs","type":"string"}]},
-		{"type":"function","name":"bool","constant":false,"inputs":[{"name":"inputs","type":"bool"}]},
-		{"type":"function","name":"address","constant":false,"inputs":[{"name":"inputs","type":"address"}]},
-		{"type":"function","name":"uint64[2]","constant":false,"inputs":[{"name":"inputs","type":"uint64[2]"}]},
-		{"type":"function","name":"uint64[]","constant":false,"inputs":[{"name":"inputs","type":"uint64[]"}]},
-		{"type":"function","name":"foo","constant":false,"inputs":[{"name":"inputs","type":"uint32"}]},
-		{"type":"function","name":"bar","constant":false,"inputs":[{"name":"inputs","type":"uint32"},{"name":"string","type":"uint16"}]},
-		{"type":"function","name":"_slice","constant":false,"inputs":[{"name":"inputs","type":"uint32[2]"}]},
-		{"type":"function","name":"__slice256","constant":false,"inputs":[{"name":"inputs","type":"uint256[2]"}]},
-		{"type":"function","name":"sliceAddress","constant":false,"inputs":[{"name":"inputs","type":"address[]"}]},
-		{"type":"function","name":"sliceMultiAddress","constant":false,"inputs":[{"name":"a","type":"address[]"},{"name":"b","type":"address[]"}]}
-	]
-`
-	abi, err := JSON(strings.NewReader(abiJSON))
+	abi, err := JSON(strings.NewReader(jsondata))
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -925,6 +950,10 @@ func TestABI_MethodById(t *testing.T) {
 			t.Errorf("Method %v (id %x) not 'findable' by id in ABI", name, m.ID)
 		}
 	}
+	// test unsuccessful lookups
+	if _, err = abi.MethodById(crypto.Keccak256()); err == nil {
+		t.Error("Expected error: no method with this id")
+	}
 	// Also test empty
 	if _, err := abi.MethodById([]byte{0x00}); err == nil {
 		t.Errorf("Expected error, too short to decode data")
@@ -1005,8 +1034,10 @@ func TestABI_EventById(t *testing.T) {
 	}
 }
 
-func TestDuplicateMethodNames(t *testing.T) {
-	abiJSON := `[{"constant":false,"inputs":[{"name":"to","type":"address"},{"name":"value","type":"uint256"}],"name":"transfer","outputs":[{"name":"ok","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"to","type":"address"},{"name":"value","type":"uint256"},{"name":"data","type":"bytes"}],"name":"transfer","outputs":[{"name":"ok","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"to","type":"address"},{"name":"value","type":"uint256"},{"name":"data","type":"bytes"},{"name":"customFallback","type":"string"}],"name":"transfer","outputs":[{"name":"ok","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"}]`
+// TestDoubleDuplicateMethodNames checks that if transfer0 already exists, there won't be a name
+// conflict and that the second transfer method will be renamed transfer1.
+func TestDoubleDuplicateMethodNames(t *testing.T) {
+	abiJSON := `[{"constant":false,"inputs":[{"name":"to","type":"address"},{"name":"value","type":"uint256"}],"name":"transfer","outputs":[{"name":"ok","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"to","type":"address"},{"name":"value","type":"uint256"},{"name":"data","type":"bytes"}],"name":"transfer0","outputs":[{"name":"ok","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"to","type":"address"},{"name":"value","type":"uint256"},{"name":"data","type":"bytes"},{"name":"customFallback","type":"string"}],"name":"transfer","outputs":[{"name":"ok","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"}]`
 	contractAbi, err := JSON(strings.NewReader(abiJSON))
 	if err != nil {
 		t.Fatal(err)
@@ -1025,25 +1056,31 @@ func TestDuplicateMethodNames(t *testing.T) {
 	}
 }
 
-// TestDoubleDuplicateMethodNames checks that if transfer0 already exists, there won't be a name
-// conflict and that the second transfer method will be renamed transfer1.
-func TestDoubleDuplicateMethodNames(t *testing.T) {
-	abiJSON := `[{"constant":false,"inputs":[{"name":"to","type":"address"},{"name":"value","type":"uint256"}],"name":"transfer","outputs":[{"name":"ok","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"to","type":"address"},{"name":"value","type":"uint256"},{"name":"data","type":"bytes"}],"name":"transfer0","outputs":[{"name":"ok","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"to","type":"address"},{"name":"value","type":"uint256"},{"name":"data","type":"bytes"},{"name":"customFallback","type":"string"}],"name":"transfer","outputs":[{"name":"ok","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"}]`
+// TestDoubleDuplicateEventNames checks that if send0 already exists, there won't be a name
+// conflict and that the second send event will be renamed send1.
+// The test runs the abi of the following contract.
+// 	contract DuplicateEvent {
+// 		event send(uint256 a);
+//		event send0();
+//		event send();
+//	}
+func TestDoubleDuplicateEventNames(t *testing.T) {
+	abiJSON := `[{"anonymous": false,"inputs": [{"indexed": false,"internalType": "uint256","name": "a","type": "uint256"}],"name": "send","type": "event"},{"anonymous": false,"inputs": [],"name": "send0","type": "event"},{	"anonymous": false,	"inputs": [],"name": "send","type": "event"}]`
 	contractAbi, err := JSON(strings.NewReader(abiJSON))
 	if err != nil {
 		t.Fatal(err)
 	}
-	if _, ok := contractAbi.Methods["transfer"]; !ok {
-		t.Fatalf("Could not find original method")
+	if _, ok := contractAbi.Events["send"]; !ok {
+		t.Fatalf("Could not find original event")
 	}
-	if _, ok := contractAbi.Methods["transfer0"]; !ok {
-		t.Fatalf("Could not find duplicate method")
+	if _, ok := contractAbi.Events["send0"]; !ok {
+		t.Fatalf("Could not find duplicate event")
 	}
-	if _, ok := contractAbi.Methods["transfer1"]; !ok {
-		t.Fatalf("Could not find duplicate method")
+	if _, ok := contractAbi.Events["send1"]; !ok {
+		t.Fatalf("Could not find duplicate event")
 	}
-	if _, ok := contractAbi.Methods["transfer2"]; ok {
-		t.Fatalf("Should not have found extra method")
+	if _, ok := contractAbi.Events["send2"]; ok {
+		t.Fatalf("Should not have found extra event")
 	}
 }
 

+ 6 - 16
accounts/abi/argument.go

@@ -59,18 +59,6 @@ func (argument *Argument) UnmarshalJSON(data []byte) error {
 	return nil
 }
 
-// LengthNonIndexed returns the number of arguments when not counting 'indexed' ones. Only events
-// can ever have 'indexed' arguments, it should always be false on arguments for method input/output
-func (arguments Arguments) LengthNonIndexed() int {
-	out := 0
-	for _, arg := range arguments {
-		if !arg.Indexed {
-			out++
-		}
-	}
-	return out
-}
-
 // NonIndexed returns the arguments with indexed arguments filtered out
 func (arguments Arguments) NonIndexed() Arguments {
 	var ret []Argument
@@ -205,10 +193,11 @@ func unpack(t *Type, dst interface{}, src interface{}) error {
 
 // unpackAtomic unpacks ( hexdata -> go ) a single value
 func (arguments Arguments) unpackAtomic(v interface{}, marshalledValues interface{}) error {
-	if arguments.LengthNonIndexed() == 0 {
+	nonIndexedArgs := arguments.NonIndexed()
+	if len(nonIndexedArgs) == 0 {
 		return nil
 	}
-	argument := arguments.NonIndexed()[0]
+	argument := nonIndexedArgs[0]
 	elem := reflect.ValueOf(v).Elem()
 
 	if elem.Kind() == reflect.Struct && argument.Type.T != TupleTy {
@@ -282,9 +271,10 @@ func (arguments Arguments) unpackTuple(v interface{}, marshalledValues []interfa
 // without supplying a struct to unpack into. Instead, this method returns a list containing the
 // values. An atomic argument will be a list with one element.
 func (arguments Arguments) UnpackValues(data []byte) ([]interface{}, error) {
-	retval := make([]interface{}, 0, arguments.LengthNonIndexed())
+	nonIndexedArgs := arguments.NonIndexed()
+	retval := make([]interface{}, 0, len(nonIndexedArgs))
 	virtualArgs := 0
-	for index, arg := range arguments.NonIndexed() {
+	for index, arg := range nonIndexedArgs {
 		marshalledValue, err := ToGoType((index+virtualArgs)*32, arg.Type, data)
 		if arg.Type.T == ArrayTy && !isDynamicType(arg.Type) {
 			// If we have a static array, like [3]uint256, these are coded as

+ 52 - 163
accounts/abi/bind/base_test.go

@@ -17,9 +17,9 @@
 package bind_test
 
 import (
-	"bytes"
 	"context"
 	"math/big"
+	"reflect"
 	"strings"
 	"testing"
 
@@ -88,51 +88,23 @@ const hexData = "0x000000000000000000000000376c47978271565f56deb45495afa69e59c16
 
 func TestUnpackIndexedStringTyLogIntoMap(t *testing.T) {
 	hash := crypto.Keccak256Hash([]byte("testName"))
-	mockLog := types.Log{
-		Address: common.HexToAddress("0x0"),
-		Topics: []common.Hash{
-			common.HexToHash("0x0"),
-			hash,
-		},
-		Data:        hexutil.MustDecode(hexData),
-		BlockNumber: uint64(26),
-		TxHash:      common.HexToHash("0x0"),
-		TxIndex:     111,
-		BlockHash:   common.BytesToHash([]byte{1, 2, 3, 4, 5}),
-		Index:       7,
-		Removed:     false,
+	topics := []common.Hash{
+		common.HexToHash("0x0"),
+		hash,
 	}
+	mockLog := newMockLog(topics, common.HexToHash("0x0"))
 
 	abiString := `[{"anonymous":false,"inputs":[{"indexed":true,"name":"name","type":"string"},{"indexed":false,"name":"sender","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"memo","type":"bytes"}],"name":"received","type":"event"}]`
 	parsedAbi, _ := abi.JSON(strings.NewReader(abiString))
 	bc := bind.NewBoundContract(common.HexToAddress("0x0"), parsedAbi, nil, nil, nil)
 
-	receivedMap := make(map[string]interface{})
 	expectedReceivedMap := map[string]interface{}{
 		"name":   hash,
 		"sender": common.HexToAddress("0x376c47978271565f56DEB45495afa69E59c16Ab2"),
 		"amount": big.NewInt(1),
 		"memo":   []byte{88},
 	}
-	if err := bc.UnpackLogIntoMap(receivedMap, "received", mockLog); err != nil {
-		t.Error(err)
-	}
-
-	if len(receivedMap) != 4 {
-		t.Fatal("unpacked map expected to have length 4")
-	}
-	if receivedMap["name"] != expectedReceivedMap["name"] {
-		t.Error("unpacked map does not match expected map")
-	}
-	if receivedMap["sender"] != expectedReceivedMap["sender"] {
-		t.Error("unpacked map does not match expected map")
-	}
-	if receivedMap["amount"].(*big.Int).Cmp(expectedReceivedMap["amount"].(*big.Int)) != 0 {
-		t.Error("unpacked map does not match expected map")
-	}
-	if !bytes.Equal(receivedMap["memo"].([]byte), expectedReceivedMap["memo"].([]byte)) {
-		t.Error("unpacked map does not match expected map")
-	}
+	unpackAndCheck(t, bc, expectedReceivedMap, mockLog)
 }
 
 func TestUnpackIndexedSliceTyLogIntoMap(t *testing.T) {
@@ -141,51 +113,23 @@ func TestUnpackIndexedSliceTyLogIntoMap(t *testing.T) {
 		t.Fatal(err)
 	}
 	hash := crypto.Keccak256Hash(sliceBytes)
-	mockLog := types.Log{
-		Address: common.HexToAddress("0x0"),
-		Topics: []common.Hash{
-			common.HexToHash("0x0"),
-			hash,
-		},
-		Data:        hexutil.MustDecode(hexData),
-		BlockNumber: uint64(26),
-		TxHash:      common.HexToHash("0x0"),
-		TxIndex:     111,
-		BlockHash:   common.BytesToHash([]byte{1, 2, 3, 4, 5}),
-		Index:       7,
-		Removed:     false,
+	topics := []common.Hash{
+		common.HexToHash("0x0"),
+		hash,
 	}
+	mockLog := newMockLog(topics, common.HexToHash("0x0"))
 
 	abiString := `[{"anonymous":false,"inputs":[{"indexed":true,"name":"names","type":"string[]"},{"indexed":false,"name":"sender","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"memo","type":"bytes"}],"name":"received","type":"event"}]`
 	parsedAbi, _ := abi.JSON(strings.NewReader(abiString))
 	bc := bind.NewBoundContract(common.HexToAddress("0x0"), parsedAbi, nil, nil, nil)
 
-	receivedMap := make(map[string]interface{})
 	expectedReceivedMap := map[string]interface{}{
 		"names":  hash,
 		"sender": common.HexToAddress("0x376c47978271565f56DEB45495afa69E59c16Ab2"),
 		"amount": big.NewInt(1),
 		"memo":   []byte{88},
 	}
-	if err := bc.UnpackLogIntoMap(receivedMap, "received", mockLog); err != nil {
-		t.Error(err)
-	}
-
-	if len(receivedMap) != 4 {
-		t.Fatal("unpacked map expected to have length 4")
-	}
-	if receivedMap["names"] != expectedReceivedMap["names"] {
-		t.Error("unpacked map does not match expected map")
-	}
-	if receivedMap["sender"] != expectedReceivedMap["sender"] {
-		t.Error("unpacked map does not match expected map")
-	}
-	if receivedMap["amount"].(*big.Int).Cmp(expectedReceivedMap["amount"].(*big.Int)) != 0 {
-		t.Error("unpacked map does not match expected map")
-	}
-	if !bytes.Equal(receivedMap["memo"].([]byte), expectedReceivedMap["memo"].([]byte)) {
-		t.Error("unpacked map does not match expected map")
-	}
+	unpackAndCheck(t, bc, expectedReceivedMap, mockLog)
 }
 
 func TestUnpackIndexedArrayTyLogIntoMap(t *testing.T) {
@@ -194,51 +138,23 @@ func TestUnpackIndexedArrayTyLogIntoMap(t *testing.T) {
 		t.Fatal(err)
 	}
 	hash := crypto.Keccak256Hash(arrBytes)
-	mockLog := types.Log{
-		Address: common.HexToAddress("0x0"),
-		Topics: []common.Hash{
-			common.HexToHash("0x0"),
-			hash,
-		},
-		Data:        hexutil.MustDecode(hexData),
-		BlockNumber: uint64(26),
-		TxHash:      common.HexToHash("0x0"),
-		TxIndex:     111,
-		BlockHash:   common.BytesToHash([]byte{1, 2, 3, 4, 5}),
-		Index:       7,
-		Removed:     false,
+	topics := []common.Hash{
+		common.HexToHash("0x0"),
+		hash,
 	}
+	mockLog := newMockLog(topics, common.HexToHash("0x0"))
 
 	abiString := `[{"anonymous":false,"inputs":[{"indexed":true,"name":"addresses","type":"address[2]"},{"indexed":false,"name":"sender","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"memo","type":"bytes"}],"name":"received","type":"event"}]`
 	parsedAbi, _ := abi.JSON(strings.NewReader(abiString))
 	bc := bind.NewBoundContract(common.HexToAddress("0x0"), parsedAbi, nil, nil, nil)
 
-	receivedMap := make(map[string]interface{})
 	expectedReceivedMap := map[string]interface{}{
 		"addresses": hash,
 		"sender":    common.HexToAddress("0x376c47978271565f56DEB45495afa69E59c16Ab2"),
 		"amount":    big.NewInt(1),
 		"memo":      []byte{88},
 	}
-	if err := bc.UnpackLogIntoMap(receivedMap, "received", mockLog); err != nil {
-		t.Error(err)
-	}
-
-	if len(receivedMap) != 4 {
-		t.Fatal("unpacked map expected to have length 4")
-	}
-	if receivedMap["addresses"] != expectedReceivedMap["addresses"] {
-		t.Error("unpacked map does not match expected map")
-	}
-	if receivedMap["sender"] != expectedReceivedMap["sender"] {
-		t.Error("unpacked map does not match expected map")
-	}
-	if receivedMap["amount"].(*big.Int).Cmp(expectedReceivedMap["amount"].(*big.Int)) != 0 {
-		t.Error("unpacked map does not match expected map")
-	}
-	if !bytes.Equal(receivedMap["memo"].([]byte), expectedReceivedMap["memo"].([]byte)) {
-		t.Error("unpacked map does not match expected map")
-	}
+	unpackAndCheck(t, bc, expectedReceivedMap, mockLog)
 }
 
 func TestUnpackIndexedFuncTyLogIntoMap(t *testing.T) {
@@ -249,99 +165,72 @@ func TestUnpackIndexedFuncTyLogIntoMap(t *testing.T) {
 	functionTyBytes := append(addrBytes, functionSelector...)
 	var functionTy [24]byte
 	copy(functionTy[:], functionTyBytes[0:24])
-	mockLog := types.Log{
-		Address: common.HexToAddress("0x0"),
-		Topics: []common.Hash{
-			common.HexToHash("0x99b5620489b6ef926d4518936cfec15d305452712b88bd59da2d9c10fb0953e8"),
-			common.BytesToHash(functionTyBytes),
-		},
-		Data:        hexutil.MustDecode(hexData),
-		BlockNumber: uint64(26),
-		TxHash:      common.HexToHash("0x5c698f13940a2153440c6d19660878bc90219d9298fdcf37365aa8d88d40fc42"),
-		TxIndex:     111,
-		BlockHash:   common.BytesToHash([]byte{1, 2, 3, 4, 5}),
-		Index:       7,
-		Removed:     false,
+	topics := []common.Hash{
+		common.HexToHash("0x99b5620489b6ef926d4518936cfec15d305452712b88bd59da2d9c10fb0953e8"),
+		common.BytesToHash(functionTyBytes),
 	}
-
+	mockLog := newMockLog(topics, common.HexToHash("0x5c698f13940a2153440c6d19660878bc90219d9298fdcf37365aa8d88d40fc42"))
 	abiString := `[{"anonymous":false,"inputs":[{"indexed":true,"name":"function","type":"function"},{"indexed":false,"name":"sender","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"memo","type":"bytes"}],"name":"received","type":"event"}]`
 	parsedAbi, _ := abi.JSON(strings.NewReader(abiString))
 	bc := bind.NewBoundContract(common.HexToAddress("0x0"), parsedAbi, nil, nil, nil)
 
-	receivedMap := make(map[string]interface{})
 	expectedReceivedMap := map[string]interface{}{
 		"function": functionTy,
 		"sender":   common.HexToAddress("0x376c47978271565f56DEB45495afa69E59c16Ab2"),
 		"amount":   big.NewInt(1),
 		"memo":     []byte{88},
 	}
-	if err := bc.UnpackLogIntoMap(receivedMap, "received", mockLog); err != nil {
-		t.Error(err)
-	}
-
-	if len(receivedMap) != 4 {
-		t.Fatal("unpacked map expected to have length 4")
-	}
-	if receivedMap["function"] != expectedReceivedMap["function"] {
-		t.Error("unpacked map does not match expected map")
-	}
-	if receivedMap["sender"] != expectedReceivedMap["sender"] {
-		t.Error("unpacked map does not match expected map")
-	}
-	if receivedMap["amount"].(*big.Int).Cmp(expectedReceivedMap["amount"].(*big.Int)) != 0 {
-		t.Error("unpacked map does not match expected map")
-	}
-	if !bytes.Equal(receivedMap["memo"].([]byte), expectedReceivedMap["memo"].([]byte)) {
-		t.Error("unpacked map does not match expected map")
-	}
+	unpackAndCheck(t, bc, expectedReceivedMap, mockLog)
 }
 
 func TestUnpackIndexedBytesTyLogIntoMap(t *testing.T) {
-	byts := []byte{1, 2, 3, 4, 5}
-	hash := crypto.Keccak256Hash(byts)
-	mockLog := types.Log{
-		Address: common.HexToAddress("0x0"),
-		Topics: []common.Hash{
-			common.HexToHash("0x99b5620489b6ef926d4518936cfec15d305452712b88bd59da2d9c10fb0953e8"),
-			hash,
-		},
-		Data:        hexutil.MustDecode(hexData),
-		BlockNumber: uint64(26),
-		TxHash:      common.HexToHash("0x5c698f13940a2153440c6d19660878bc90219d9298fdcf37365aa8d88d40fc42"),
-		TxIndex:     111,
-		BlockHash:   common.BytesToHash([]byte{1, 2, 3, 4, 5}),
-		Index:       7,
-		Removed:     false,
+	bytes := []byte{1, 2, 3, 4, 5}
+	hash := crypto.Keccak256Hash(bytes)
+	topics := []common.Hash{
+		common.HexToHash("0x99b5620489b6ef926d4518936cfec15d305452712b88bd59da2d9c10fb0953e8"),
+		hash,
 	}
+	mockLog := newMockLog(topics, common.HexToHash("0x5c698f13940a2153440c6d19660878bc90219d9298fdcf37365aa8d88d40fc42"))
 
 	abiString := `[{"anonymous":false,"inputs":[{"indexed":true,"name":"content","type":"bytes"},{"indexed":false,"name":"sender","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"memo","type":"bytes"}],"name":"received","type":"event"}]`
 	parsedAbi, _ := abi.JSON(strings.NewReader(abiString))
 	bc := bind.NewBoundContract(common.HexToAddress("0x0"), parsedAbi, nil, nil, nil)
 
-	receivedMap := make(map[string]interface{})
 	expectedReceivedMap := map[string]interface{}{
 		"content": hash,
 		"sender":  common.HexToAddress("0x376c47978271565f56DEB45495afa69E59c16Ab2"),
 		"amount":  big.NewInt(1),
 		"memo":    []byte{88},
 	}
-	if err := bc.UnpackLogIntoMap(receivedMap, "received", mockLog); err != nil {
+	unpackAndCheck(t, bc, expectedReceivedMap, mockLog)
+}
+
+func unpackAndCheck(t *testing.T, bc *bind.BoundContract, expected map[string]interface{}, mockLog types.Log) {
+	received := make(map[string]interface{})
+	if err := bc.UnpackLogIntoMap(received, "received", mockLog); err != nil {
 		t.Error(err)
 	}
 
-	if len(receivedMap) != 4 {
-		t.Fatal("unpacked map expected to have length 4")
+	if len(received) != len(expected) {
+		t.Fatalf("unpacked map length %v not equal expected length of %v", len(received), len(expected))
 	}
-	if receivedMap["content"] != expectedReceivedMap["content"] {
-		t.Error("unpacked map does not match expected map")
+	for name, elem := range expected {
+		if !reflect.DeepEqual(elem, received[name]) {
+			t.Errorf("field %v does not match expected, want %v, got %v", name, elem, received[name])
+		}
 	}
-	if receivedMap["sender"] != expectedReceivedMap["sender"] {
-		t.Error("unpacked map does not match expected map")
-	}
-	if receivedMap["amount"].(*big.Int).Cmp(expectedReceivedMap["amount"].(*big.Int)) != 0 {
-		t.Error("unpacked map does not match expected map")
-	}
-	if !bytes.Equal(receivedMap["memo"].([]byte), expectedReceivedMap["memo"].([]byte)) {
-		t.Error("unpacked map does not match expected map")
+}
+
+func newMockLog(topics []common.Hash, txHash common.Hash) types.Log {
+	return types.Log{
+		Address:     common.HexToAddress("0x0"),
+		Topics:      topics,
+		Data:        hexutil.MustDecode(hexData),
+		BlockNumber: uint64(26),
+		TxHash:      txHash,
+		TxIndex:     111,
+		BlockHash:   common.BytesToHash([]byte{1, 2, 3, 4, 5}),
+		Index:       7,
+		Removed:     false,
 	}
 }

+ 1 - 3
accounts/abi/error.go

@@ -46,12 +46,10 @@ func sliceTypeCheck(t Type, val reflect.Value) error {
 		return typeErr(formatSliceString(t.Elem.Kind, t.Size), formatSliceString(val.Type().Elem().Kind(), val.Len()))
 	}
 
-	if t.Elem.T == SliceTy {
+	if t.Elem.T == SliceTy || t.Elem.T == ArrayTy {
 		if val.Len() > 0 {
 			return sliceTypeCheck(*t.Elem, val.Index(0))
 		}
-	} else if t.Elem.T == ArrayTy {
-		return sliceTypeCheck(*t.Elem, val.Index(0))
 	}
 
 	if elemKind := val.Type().Elem().Kind(); elemKind != t.Elem.Kind {

+ 1 - 0
accounts/abi/numbers.go

@@ -39,6 +39,7 @@ var (
 )
 
 // U256 converts a big Int into a 256bit EVM number.
+// This operation is destructive.
 func U256(n *big.Int) []byte {
 	return math.PaddedBigBytes(math.U256(n), 32)
 }

+ 35 - 596
accounts/abi/pack_test.go

@@ -18,618 +18,57 @@ package abi
 
 import (
 	"bytes"
+	"encoding/hex"
+	"fmt"
 	"math"
 	"math/big"
 	"reflect"
+	"strconv"
 	"strings"
 	"testing"
 
 	"github.com/ethereum/go-ethereum/common"
 )
 
+// TestPack tests the general pack/unpack tests in packing_test.go
 func TestPack(t *testing.T) {
-	for i, test := range []struct {
-		typ        string
-		components []ArgumentMarshaling
-		input      interface{}
-		output     []byte
-	}{
-		{
-			"uint8",
-			nil,
-			uint8(2),
-			common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000002"),
-		},
-		{
-			"uint8[]",
-			nil,
-			[]uint8{1, 2},
-			common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"),
-		},
-		{
-			"uint16",
-			nil,
-			uint16(2),
-			common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000002"),
-		},
-		{
-			"uint16[]",
-			nil,
-			[]uint16{1, 2},
-			common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"),
-		},
-		{
-			"uint32",
-			nil,
-			uint32(2),
-			common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000002"),
-		},
-		{
-			"uint32[]",
-			nil,
-			[]uint32{1, 2},
-			common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"),
-		},
-		{
-			"uint64",
-			nil,
-			uint64(2),
-			common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000002"),
-		},
-		{
-			"uint64[]",
-			nil,
-			[]uint64{1, 2},
-			common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"),
-		},
-		{
-			"uint256",
-			nil,
-			big.NewInt(2),
-			common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000002"),
-		},
-		{
-			"uint256[]",
-			nil,
-			[]*big.Int{big.NewInt(1), big.NewInt(2)},
-			common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"),
-		},
-		{
-			"int8",
-			nil,
-			int8(2),
-			common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000002"),
-		},
-		{
-			"int8[]",
-			nil,
-			[]int8{1, 2},
-			common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"),
-		},
-		{
-			"int16",
-			nil,
-			int16(2),
-			common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000002"),
-		},
-		{
-			"int16[]",
-			nil,
-			[]int16{1, 2},
-			common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"),
-		},
-		{
-			"int32",
-			nil,
-			int32(2),
-			common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000002"),
-		},
-		{
-			"int32[]",
-			nil,
-			[]int32{1, 2},
-			common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"),
-		},
-		{
-			"int64",
-			nil,
-			int64(2),
-			common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000002"),
-		},
-		{
-			"int64[]",
-			nil,
-			[]int64{1, 2},
-			common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"),
-		},
-		{
-			"int256",
-			nil,
-			big.NewInt(2),
-			common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000002"),
-		},
-		{
-			"int256[]",
-			nil,
-			[]*big.Int{big.NewInt(1), big.NewInt(2)},
-			common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"),
-		},
-		{
-			"bytes1",
-			nil,
-			[1]byte{1},
-			common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"),
-		},
-		{
-			"bytes2",
-			nil,
-			[2]byte{1},
-			common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"),
-		},
-		{
-			"bytes3",
-			nil,
-			[3]byte{1},
-			common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"),
-		},
-		{
-			"bytes4",
-			nil,
-			[4]byte{1},
-			common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"),
-		},
-		{
-			"bytes5",
-			nil,
-			[5]byte{1},
-			common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"),
-		},
-		{
-			"bytes6",
-			nil,
-			[6]byte{1},
-			common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"),
-		},
-		{
-			"bytes7",
-			nil,
-			[7]byte{1},
-			common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"),
-		},
-		{
-			"bytes8",
-			nil,
-			[8]byte{1},
-			common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"),
-		},
-		{
-			"bytes9",
-			nil,
-			[9]byte{1},
-			common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"),
-		},
-		{
-			"bytes10",
-			nil,
-			[10]byte{1},
-			common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"),
-		},
-		{
-			"bytes11",
-			nil,
-			[11]byte{1},
-			common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"),
-		},
-		{
-			"bytes12",
-			nil,
-			[12]byte{1},
-			common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"),
-		},
-		{
-			"bytes13",
-			nil,
-			[13]byte{1},
-			common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"),
-		},
-		{
-			"bytes14",
-			nil,
-			[14]byte{1},
-			common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"),
-		},
-		{
-			"bytes15",
-			nil,
-			[15]byte{1},
-			common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"),
-		},
-		{
-			"bytes16",
-			nil,
-			[16]byte{1},
-			common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"),
-		},
-		{
-			"bytes17",
-			nil,
-			[17]byte{1},
-			common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"),
-		},
-		{
-			"bytes18",
-			nil,
-			[18]byte{1},
-			common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"),
-		},
-		{
-			"bytes19",
-			nil,
-			[19]byte{1},
-			common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"),
-		},
-		{
-			"bytes20",
-			nil,
-			[20]byte{1},
-			common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"),
-		},
-		{
-			"bytes21",
-			nil,
-			[21]byte{1},
-			common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"),
-		},
-		{
-			"bytes22",
-			nil,
-			[22]byte{1},
-			common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"),
-		},
-		{
-			"bytes23",
-			nil,
-			[23]byte{1},
-			common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"),
-		},
-		{
-			"bytes24",
-			nil,
-			[24]byte{1},
-			common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"),
-		},
-		{
-			"bytes25",
-			nil,
-			[25]byte{1},
-			common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"),
-		},
-		{
-			"bytes26",
-			nil,
-			[26]byte{1},
-			common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"),
-		},
-		{
-			"bytes27",
-			nil,
-			[27]byte{1},
-			common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"),
-		},
-		{
-			"bytes28",
-			nil,
-			[28]byte{1},
-			common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"),
-		},
-		{
-			"bytes29",
-			nil,
-			[29]byte{1},
-			common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"),
-		},
-		{
-			"bytes30",
-			nil,
-			[30]byte{1},
-			common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"),
-		},
-		{
-			"bytes31",
-			nil,
-			[31]byte{1},
-			common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"),
-		},
-		{
-			"bytes32",
-			nil,
-			[32]byte{1},
-			common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"),
-		},
-		{
-			"uint32[2][3][4]",
-			nil,
-			[4][3][2]uint32{{{1, 2}, {3, 4}, {5, 6}}, {{7, 8}, {9, 10}, {11, 12}}, {{13, 14}, {15, 16}, {17, 18}}, {{19, 20}, {21, 22}, {23, 24}}},
-			common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000110000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000001300000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000015000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000170000000000000000000000000000000000000000000000000000000000000018"),
-		},
-		{
-			"address[]",
-			nil,
-			[]common.Address{{1}, {2}},
-			common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000"),
-		},
-		{
-			"bytes32[]",
-			nil,
-			[]common.Hash{{1}, {2}},
-			common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000201000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000"),
-		},
-		{
-			"function",
-			nil,
-			[24]byte{1},
-			common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"),
-		},
-		{
-			"string",
-			nil,
-			"foobar",
-			common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000006666f6f6261720000000000000000000000000000000000000000000000000000"),
-		},
-		{
-			"string[]",
-			nil,
-			[]string{"hello", "foobar"},
-			common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000002" + // len(array) = 2
-				"0000000000000000000000000000000000000000000000000000000000000040" + // offset 64 to i = 0
-				"0000000000000000000000000000000000000000000000000000000000000080" + // offset 128 to i = 1
-				"0000000000000000000000000000000000000000000000000000000000000005" + // len(str[0]) = 5
-				"68656c6c6f000000000000000000000000000000000000000000000000000000" + // str[0]
-				"0000000000000000000000000000000000000000000000000000000000000006" + // len(str[1]) = 6
-				"666f6f6261720000000000000000000000000000000000000000000000000000"), // str[1]
-		},
-		{
-			"string[2]",
-			nil,
-			[]string{"hello", "foobar"},
-			common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000040" + // offset to i = 0
-				"0000000000000000000000000000000000000000000000000000000000000080" + // offset to i = 1
-				"0000000000000000000000000000000000000000000000000000000000000005" + // len(str[0]) = 5
-				"68656c6c6f000000000000000000000000000000000000000000000000000000" + // str[0]
-				"0000000000000000000000000000000000000000000000000000000000000006" + // len(str[1]) = 6
-				"666f6f6261720000000000000000000000000000000000000000000000000000"), // str[1]
-		},
-		{
-			"bytes32[][]",
-			nil,
-			[][]common.Hash{{{1}, {2}}, {{3}, {4}, {5}}},
-			common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000002" + // len(array) = 2
-				"0000000000000000000000000000000000000000000000000000000000000040" + // offset 64 to i = 0
-				"00000000000000000000000000000000000000000000000000000000000000a0" + // offset 160 to i = 1
-				"0000000000000000000000000000000000000000000000000000000000000002" + // len(array[0]) = 2
-				"0100000000000000000000000000000000000000000000000000000000000000" + // array[0][0]
-				"0200000000000000000000000000000000000000000000000000000000000000" + // array[0][1]
-				"0000000000000000000000000000000000000000000000000000000000000003" + // len(array[1]) = 3
-				"0300000000000000000000000000000000000000000000000000000000000000" + // array[1][0]
-				"0400000000000000000000000000000000000000000000000000000000000000" + // array[1][1]
-				"0500000000000000000000000000000000000000000000000000000000000000"), // array[1][2]
-		},
-
-		{
-			"bytes32[][2]",
-			nil,
-			[][]common.Hash{{{1}, {2}}, {{3}, {4}, {5}}},
-			common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000040" + // offset 64 to i = 0
-				"00000000000000000000000000000000000000000000000000000000000000a0" + // offset 160 to i = 1
-				"0000000000000000000000000000000000000000000000000000000000000002" + // len(array[0]) = 2
-				"0100000000000000000000000000000000000000000000000000000000000000" + // array[0][0]
-				"0200000000000000000000000000000000000000000000000000000000000000" + // array[0][1]
-				"0000000000000000000000000000000000000000000000000000000000000003" + // len(array[1]) = 3
-				"0300000000000000000000000000000000000000000000000000000000000000" + // array[1][0]
-				"0400000000000000000000000000000000000000000000000000000000000000" + // array[1][1]
-				"0500000000000000000000000000000000000000000000000000000000000000"), // array[1][2]
-		},
-
-		{
-			"bytes32[3][2]",
-			nil,
-			[][]common.Hash{{{1}, {2}, {3}}, {{3}, {4}, {5}}},
-			common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000" + // array[0][0]
-				"0200000000000000000000000000000000000000000000000000000000000000" + // array[0][1]
-				"0300000000000000000000000000000000000000000000000000000000000000" + // array[0][2]
-				"0300000000000000000000000000000000000000000000000000000000000000" + // array[1][0]
-				"0400000000000000000000000000000000000000000000000000000000000000" + // array[1][1]
-				"0500000000000000000000000000000000000000000000000000000000000000"), // array[1][2]
-		},
-		{
-			// static tuple
-			"tuple",
-			[]ArgumentMarshaling{
-				{Name: "a", Type: "int64"},
-				{Name: "b", Type: "int256"},
-				{Name: "c", Type: "int256"},
-				{Name: "d", Type: "bool"},
-				{Name: "e", Type: "bytes32[3][2]"},
-			},
-			struct {
-				A int64
-				B *big.Int
-				C *big.Int
-				D bool
-				E [][]common.Hash
-			}{1, big.NewInt(1), big.NewInt(-1), true, [][]common.Hash{{{1}, {2}, {3}}, {{3}, {4}, {5}}}},
-			common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000001" + // struct[a]
-				"0000000000000000000000000000000000000000000000000000000000000001" + // struct[b]
-				"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + // struct[c]
-				"0000000000000000000000000000000000000000000000000000000000000001" + // struct[d]
-				"0100000000000000000000000000000000000000000000000000000000000000" + // struct[e] array[0][0]
-				"0200000000000000000000000000000000000000000000000000000000000000" + // struct[e] array[0][1]
-				"0300000000000000000000000000000000000000000000000000000000000000" + // struct[e] array[0][2]
-				"0300000000000000000000000000000000000000000000000000000000000000" + // struct[e] array[1][0]
-				"0400000000000000000000000000000000000000000000000000000000000000" + // struct[e] array[1][1]
-				"0500000000000000000000000000000000000000000000000000000000000000"), // struct[e] array[1][2]
-		},
-		{
-			// dynamic tuple
-			"tuple",
-			[]ArgumentMarshaling{
-				{Name: "a", Type: "string"},
-				{Name: "b", Type: "int64"},
-				{Name: "c", Type: "bytes"},
-				{Name: "d", Type: "string[]"},
-				{Name: "e", Type: "int256[]"},
-				{Name: "f", Type: "address[]"},
-			},
-			struct {
-				FieldA string `abi:"a"` // Test whether abi tag works
-				FieldB int64  `abi:"b"`
-				C      []byte
-				D      []string
-				E      []*big.Int
-				F      []common.Address
-			}{"foobar", 1, []byte{1}, []string{"foo", "bar"}, []*big.Int{big.NewInt(1), big.NewInt(-1)}, []common.Address{{1}, {2}}},
-			common.Hex2Bytes("00000000000000000000000000000000000000000000000000000000000000c0" + // struct[a] offset
-				"0000000000000000000000000000000000000000000000000000000000000001" + // struct[b]
-				"0000000000000000000000000000000000000000000000000000000000000100" + // struct[c] offset
-				"0000000000000000000000000000000000000000000000000000000000000140" + // struct[d] offset
-				"0000000000000000000000000000000000000000000000000000000000000220" + // struct[e] offset
-				"0000000000000000000000000000000000000000000000000000000000000280" + // struct[f] offset
-				"0000000000000000000000000000000000000000000000000000000000000006" + // struct[a] length
-				"666f6f6261720000000000000000000000000000000000000000000000000000" + // struct[a] "foobar"
-				"0000000000000000000000000000000000000000000000000000000000000001" + // struct[c] length
-				"0100000000000000000000000000000000000000000000000000000000000000" + // []byte{1}
-				"0000000000000000000000000000000000000000000000000000000000000002" + // struct[d] length
-				"0000000000000000000000000000000000000000000000000000000000000040" + // foo offset
-				"0000000000000000000000000000000000000000000000000000000000000080" + // bar offset
-				"0000000000000000000000000000000000000000000000000000000000000003" + // foo length
-				"666f6f0000000000000000000000000000000000000000000000000000000000" + // foo
-				"0000000000000000000000000000000000000000000000000000000000000003" + // bar offset
-				"6261720000000000000000000000000000000000000000000000000000000000" + // bar
-				"0000000000000000000000000000000000000000000000000000000000000002" + // struct[e] length
-				"0000000000000000000000000000000000000000000000000000000000000001" + // 1
-				"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + // -1
-				"0000000000000000000000000000000000000000000000000000000000000002" + // struct[f] length
-				"0000000000000000000000000100000000000000000000000000000000000000" + // common.Address{1}
-				"0000000000000000000000000200000000000000000000000000000000000000"), // common.Address{2}
-		},
-		{
-			// nested tuple
-			"tuple",
-			[]ArgumentMarshaling{
-				{Name: "a", Type: "tuple", Components: []ArgumentMarshaling{{Name: "a", Type: "uint256"}, {Name: "b", Type: "uint256[]"}}},
-				{Name: "b", Type: "int256[]"},
-			},
-			struct {
-				A struct {
-					FieldA *big.Int `abi:"a"`
-					B      []*big.Int
+	for i, test := range packUnpackTests {
+		t.Run(strconv.Itoa(i), func(t *testing.T) {
+			encb, err := hex.DecodeString(test.packed)
+			if err != nil {
+				t.Fatalf("invalid hex %s: %v", test.packed, err)
+			}
+			inDef := fmt.Sprintf(`[{ "name" : "method", "type": "function", "inputs": %s}]`, test.def)
+			inAbi, err := JSON(strings.NewReader(inDef))
+			if err != nil {
+				t.Fatalf("invalid ABI definition %s, %v", inDef, err)
+			}
+			var packed []byte
+			if reflect.TypeOf(test.unpacked).Kind() != reflect.Struct {
+				packed, err = inAbi.Pack("method", test.unpacked)
+			} else {
+				// if want is a struct we need to use the components.
+				elem := reflect.ValueOf(test.unpacked)
+				var values []interface{}
+				for i := 0; i < elem.NumField(); i++ {
+					field := elem.Field(i)
+					values = append(values, field.Interface())
 				}
-				B []*big.Int
-			}{
-				A: struct {
-					FieldA *big.Int `abi:"a"` // Test whether abi tag works for nested tuple
-					B      []*big.Int
-				}{big.NewInt(1), []*big.Int{big.NewInt(1), big.NewInt(0)}},
-				B: []*big.Int{big.NewInt(1), big.NewInt(0)}},
-			common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000040" + // a offset
-				"00000000000000000000000000000000000000000000000000000000000000e0" + // b offset
-				"0000000000000000000000000000000000000000000000000000000000000001" + // a.a value
-				"0000000000000000000000000000000000000000000000000000000000000040" + // a.b offset
-				"0000000000000000000000000000000000000000000000000000000000000002" + // a.b length
-				"0000000000000000000000000000000000000000000000000000000000000001" + // a.b[0] value
-				"0000000000000000000000000000000000000000000000000000000000000000" + // a.b[1] value
-				"0000000000000000000000000000000000000000000000000000000000000002" + // b length
-				"0000000000000000000000000000000000000000000000000000000000000001" + // b[0] value
-				"0000000000000000000000000000000000000000000000000000000000000000"), // b[1] value
-		},
-		{
-			// tuple slice
-			"tuple[]",
-			[]ArgumentMarshaling{
-				{Name: "a", Type: "int256"},
-				{Name: "b", Type: "int256[]"},
-			},
-			[]struct {
-				A *big.Int
-				B []*big.Int
-			}{
-				{big.NewInt(-1), []*big.Int{big.NewInt(1), big.NewInt(0)}},
-				{big.NewInt(1), []*big.Int{big.NewInt(2), big.NewInt(-1)}},
-			},
-			common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000002" + // tuple length
-				"0000000000000000000000000000000000000000000000000000000000000040" + // tuple[0] offset
-				"00000000000000000000000000000000000000000000000000000000000000e0" + // tuple[1] offset
-				"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + // tuple[0].A
-				"0000000000000000000000000000000000000000000000000000000000000040" + // tuple[0].B offset
-				"0000000000000000000000000000000000000000000000000000000000000002" + // tuple[0].B length
-				"0000000000000000000000000000000000000000000000000000000000000001" + // tuple[0].B[0] value
-				"0000000000000000000000000000000000000000000000000000000000000000" + // tuple[0].B[1] value
-				"0000000000000000000000000000000000000000000000000000000000000001" + // tuple[1].A
-				"0000000000000000000000000000000000000000000000000000000000000040" + // tuple[1].B offset
-				"0000000000000000000000000000000000000000000000000000000000000002" + // tuple[1].B length
-				"0000000000000000000000000000000000000000000000000000000000000002" + // tuple[1].B[0] value
-				"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), // tuple[1].B[1] value
-		},
-		{
-			// static tuple array
-			"tuple[2]",
-			[]ArgumentMarshaling{
-				{Name: "a", Type: "int256"},
-				{Name: "b", Type: "int256"},
-			},
-			[2]struct {
-				A *big.Int
-				B *big.Int
-			}{
-				{big.NewInt(-1), big.NewInt(1)},
-				{big.NewInt(1), big.NewInt(-1)},
-			},
-			common.Hex2Bytes("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + // tuple[0].a
-				"0000000000000000000000000000000000000000000000000000000000000001" + // tuple[0].b
-				"0000000000000000000000000000000000000000000000000000000000000001" + // tuple[1].a
-				"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), // tuple[1].b
-		},
-		{
-			// dynamic tuple array
-			"tuple[2]",
-			[]ArgumentMarshaling{
-				{Name: "a", Type: "int256[]"},
-			},
-			[2]struct {
-				A []*big.Int
-			}{
-				{[]*big.Int{big.NewInt(-1), big.NewInt(1)}},
-				{[]*big.Int{big.NewInt(1), big.NewInt(-1)}},
-			},
-			common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000040" + // tuple[0] offset
-				"00000000000000000000000000000000000000000000000000000000000000c0" + // tuple[1] offset
-				"0000000000000000000000000000000000000000000000000000000000000020" + // tuple[0].A offset
-				"0000000000000000000000000000000000000000000000000000000000000002" + // tuple[0].A length
-				"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + // tuple[0].A[0]
-				"0000000000000000000000000000000000000000000000000000000000000001" + // tuple[0].A[1]
-				"0000000000000000000000000000000000000000000000000000000000000020" + // tuple[1].A offset
-				"0000000000000000000000000000000000000000000000000000000000000002" + // tuple[1].A length
-				"0000000000000000000000000000000000000000000000000000000000000001" + // tuple[1].A[0]
-				"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), // tuple[1].A[1]
-		},
-	} {
-		typ, err := NewType(test.typ, "", test.components)
-		if err != nil {
-			t.Fatalf("%v failed. Unexpected parse error: %v", i, err)
-		}
-		output, err := typ.pack(reflect.ValueOf(test.input))
-		if err != nil {
-			t.Fatalf("%v failed. Unexpected pack error: %v", i, err)
-		}
+				packed, err = inAbi.Pack("method", values...)
+			}
 
-		if !bytes.Equal(output, test.output) {
-			t.Errorf("input %d for typ: %v failed. Expected bytes: '%x' Got: '%x'", i, typ.String(), test.output, output)
-		}
+			if err != nil {
+				t.Fatalf("test %d (%v) failed: %v", i, test.def, err)
+			}
+			if !reflect.DeepEqual(packed[4:], encb) {
+				t.Errorf("test %d (%v) failed: expected %v, got %v", i, test.def, encb, packed[4:])
+			}
+		})
 	}
 }
 
 func TestMethodPack(t *testing.T) {
-	abi, err := JSON(strings.NewReader(jsondata2))
+	abi, err := JSON(strings.NewReader(jsondata))
 	if err != nil {
 		t.Fatal(err)
 	}

+ 988 - 0
accounts/abi/packing_test.go

@@ -0,0 +1,988 @@
+// Copyright 2020 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+package abi
+
+import (
+	"math/big"
+
+	"github.com/ethereum/go-ethereum/common"
+)
+
+type packUnpackTest struct {
+	def      string
+	unpacked interface{}
+	packed   string
+}
+
+var packUnpackTests = []packUnpackTest{
+	// Booleans
+	{
+		def:      `[{ "type": "bool" }]`,
+		packed:   "0000000000000000000000000000000000000000000000000000000000000001",
+		unpacked: true,
+	},
+	{
+		def:      `[{ "type": "bool" }]`,
+		packed:   "0000000000000000000000000000000000000000000000000000000000000000",
+		unpacked: false,
+	},
+	// Integers
+	{
+		def:      `[{ "type": "uint8" }]`,
+		unpacked: uint8(2),
+		packed:   "0000000000000000000000000000000000000000000000000000000000000002",
+	},
+	{
+		def:      `[{ "type": "uint8[]" }]`,
+		unpacked: []uint8{1, 2},
+		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
+			"0000000000000000000000000000000000000000000000000000000000000002" +
+			"0000000000000000000000000000000000000000000000000000000000000001" +
+			"0000000000000000000000000000000000000000000000000000000000000002",
+	},
+	{
+		def:      `[{ "type": "uint16" }]`,
+		unpacked: uint16(2),
+		packed:   "0000000000000000000000000000000000000000000000000000000000000002",
+	},
+	{
+		def:      `[{ "type": "uint16[]" }]`,
+		unpacked: []uint16{1, 2},
+		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
+			"0000000000000000000000000000000000000000000000000000000000000002" +
+			"0000000000000000000000000000000000000000000000000000000000000001" +
+			"0000000000000000000000000000000000000000000000000000000000000002",
+	},
+	{
+		def:      `[{"type": "uint17"}]`,
+		packed:   "0000000000000000000000000000000000000000000000000000000000000001",
+		unpacked: big.NewInt(1),
+	},
+	{
+		def:      `[{"type": "uint32"}]`,
+		packed:   "0000000000000000000000000000000000000000000000000000000000000001",
+		unpacked: uint32(1),
+	},
+	{
+		def:      `[{"type": "uint32[]"}]`,
+		unpacked: []uint32{1, 2},
+		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
+			"0000000000000000000000000000000000000000000000000000000000000002" +
+			"0000000000000000000000000000000000000000000000000000000000000001" +
+			"0000000000000000000000000000000000000000000000000000000000000002",
+	},
+	{
+		def:      `[{"type": "uint64"}]`,
+		unpacked: uint64(2),
+		packed:   "0000000000000000000000000000000000000000000000000000000000000002",
+	},
+	{
+		def:      `[{"type": "uint64[]"}]`,
+		unpacked: []uint64{1, 2},
+		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
+			"0000000000000000000000000000000000000000000000000000000000000002" +
+			"0000000000000000000000000000000000000000000000000000000000000001" +
+			"0000000000000000000000000000000000000000000000000000000000000002",
+	},
+	{
+		def:      `[{"type": "uint256"}]`,
+		unpacked: big.NewInt(2),
+		packed:   "0000000000000000000000000000000000000000000000000000000000000002",
+	},
+	{
+		def:      `[{"type": "uint256[]"}]`,
+		unpacked: []*big.Int{big.NewInt(1), big.NewInt(2)},
+		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
+			"0000000000000000000000000000000000000000000000000000000000000002" +
+			"0000000000000000000000000000000000000000000000000000000000000001" +
+			"0000000000000000000000000000000000000000000000000000000000000002",
+	},
+	{
+		def:      `[{"type": "int8"}]`,
+		unpacked: int8(2),
+		packed:   "0000000000000000000000000000000000000000000000000000000000000002",
+	},
+	{
+		def:      `[{"type": "int8[]"}]`,
+		unpacked: []int8{1, 2},
+		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
+			"0000000000000000000000000000000000000000000000000000000000000002" +
+			"0000000000000000000000000000000000000000000000000000000000000001" +
+			"0000000000000000000000000000000000000000000000000000000000000002",
+	},
+	{
+		def:      `[{"type": "int16"}]`,
+		unpacked: int16(2),
+		packed:   "0000000000000000000000000000000000000000000000000000000000000002",
+	},
+	{
+		def:      `[{"type": "int16[]"}]`,
+		unpacked: []int16{1, 2},
+		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
+			"0000000000000000000000000000000000000000000000000000000000000002" +
+			"0000000000000000000000000000000000000000000000000000000000000001" +
+			"0000000000000000000000000000000000000000000000000000000000000002",
+	},
+	{
+		def:      `[{"type": "int17"}]`,
+		packed:   "0000000000000000000000000000000000000000000000000000000000000001",
+		unpacked: big.NewInt(1),
+	},
+	{
+		def:      `[{"type": "int32"}]`,
+		unpacked: int32(2),
+		packed:   "0000000000000000000000000000000000000000000000000000000000000002",
+	},
+	{
+		def:      `[{"type": "int32"}]`,
+		packed:   "0000000000000000000000000000000000000000000000000000000000000001",
+		unpacked: int32(1),
+	},
+	{
+		def:      `[{"type": "int32[]"}]`,
+		unpacked: []int32{1, 2},
+		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
+			"0000000000000000000000000000000000000000000000000000000000000002" +
+			"0000000000000000000000000000000000000000000000000000000000000001" +
+			"0000000000000000000000000000000000000000000000000000000000000002",
+	},
+	{
+		def:      `[{"type": "int64"}]`,
+		unpacked: int64(2),
+		packed:   "0000000000000000000000000000000000000000000000000000000000000002",
+	},
+	{
+		def:      `[{"type": "int64[]"}]`,
+		unpacked: []int64{1, 2},
+		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
+			"0000000000000000000000000000000000000000000000000000000000000002" +
+			"0000000000000000000000000000000000000000000000000000000000000001" +
+			"0000000000000000000000000000000000000000000000000000000000000002",
+	},
+	{
+		def:      `[{"type": "int256"}]`,
+		unpacked: big.NewInt(2),
+		packed:   "0000000000000000000000000000000000000000000000000000000000000002",
+	},
+	{
+		def:      `[{"type": "int256"}]`,
+		packed:   "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+		unpacked: big.NewInt(-1),
+	},
+	{
+		def:      `[{"type": "int256[]"}]`,
+		unpacked: []*big.Int{big.NewInt(1), big.NewInt(2)},
+		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
+			"0000000000000000000000000000000000000000000000000000000000000002" +
+			"0000000000000000000000000000000000000000000000000000000000000001" +
+			"0000000000000000000000000000000000000000000000000000000000000002",
+	},
+	// Address
+	{
+		def:      `[{"type": "address"}]`,
+		packed:   "0000000000000000000000000100000000000000000000000000000000000000",
+		unpacked: common.Address{1},
+	},
+	{
+		def:      `[{"type": "address[]"}]`,
+		unpacked: []common.Address{{1}, {2}},
+		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
+			"0000000000000000000000000000000000000000000000000000000000000002" +
+			"0000000000000000000000000100000000000000000000000000000000000000" +
+			"0000000000000000000000000200000000000000000000000000000000000000",
+	},
+	// Bytes
+	{
+		def:      `[{"type": "bytes1"}]`,
+		unpacked: [1]byte{1},
+		packed:   "0100000000000000000000000000000000000000000000000000000000000000",
+	},
+	{
+		def:      `[{"type": "bytes2"}]`,
+		unpacked: [2]byte{1},
+		packed:   "0100000000000000000000000000000000000000000000000000000000000000",
+	},
+	{
+		def:      `[{"type": "bytes3"}]`,
+		unpacked: [3]byte{1},
+		packed:   "0100000000000000000000000000000000000000000000000000000000000000",
+	},
+	{
+		def:      `[{"type": "bytes4"}]`,
+		unpacked: [4]byte{1},
+		packed:   "0100000000000000000000000000000000000000000000000000000000000000",
+	},
+	{
+		def:      `[{"type": "bytes5"}]`,
+		unpacked: [5]byte{1},
+		packed:   "0100000000000000000000000000000000000000000000000000000000000000",
+	},
+	{
+		def:      `[{"type": "bytes6"}]`,
+		unpacked: [6]byte{1},
+		packed:   "0100000000000000000000000000000000000000000000000000000000000000",
+	},
+	{
+		def:      `[{"type": "bytes7"}]`,
+		unpacked: [7]byte{1},
+		packed:   "0100000000000000000000000000000000000000000000000000000000000000",
+	},
+	{
+		def:      `[{"type": "bytes8"}]`,
+		unpacked: [8]byte{1},
+		packed:   "0100000000000000000000000000000000000000000000000000000000000000",
+	},
+	{
+		def:      `[{"type": "bytes9"}]`,
+		unpacked: [9]byte{1},
+		packed:   "0100000000000000000000000000000000000000000000000000000000000000",
+	},
+	{
+		def:      `[{"type": "bytes10"}]`,
+		unpacked: [10]byte{1},
+		packed:   "0100000000000000000000000000000000000000000000000000000000000000",
+	},
+	{
+		def:      `[{"type": "bytes11"}]`,
+		unpacked: [11]byte{1},
+		packed:   "0100000000000000000000000000000000000000000000000000000000000000",
+	},
+	{
+		def:      `[{"type": "bytes12"}]`,
+		unpacked: [12]byte{1},
+		packed:   "0100000000000000000000000000000000000000000000000000000000000000",
+	},
+	{
+		def:      `[{"type": "bytes13"}]`,
+		unpacked: [13]byte{1},
+		packed:   "0100000000000000000000000000000000000000000000000000000000000000",
+	},
+	{
+		def:      `[{"type": "bytes14"}]`,
+		unpacked: [14]byte{1},
+		packed:   "0100000000000000000000000000000000000000000000000000000000000000",
+	},
+	{
+		def:      `[{"type": "bytes15"}]`,
+		unpacked: [15]byte{1},
+		packed:   "0100000000000000000000000000000000000000000000000000000000000000",
+	},
+	{
+		def:      `[{"type": "bytes16"}]`,
+		unpacked: [16]byte{1},
+		packed:   "0100000000000000000000000000000000000000000000000000000000000000",
+	},
+	{
+		def:      `[{"type": "bytes17"}]`,
+		unpacked: [17]byte{1},
+		packed:   "0100000000000000000000000000000000000000000000000000000000000000",
+	},
+	{
+		def:      `[{"type": "bytes18"}]`,
+		unpacked: [18]byte{1},
+		packed:   "0100000000000000000000000000000000000000000000000000000000000000",
+	},
+	{
+		def:      `[{"type": "bytes19"}]`,
+		unpacked: [19]byte{1},
+		packed:   "0100000000000000000000000000000000000000000000000000000000000000",
+	},
+	{
+		def:      `[{"type": "bytes20"}]`,
+		unpacked: [20]byte{1},
+		packed:   "0100000000000000000000000000000000000000000000000000000000000000",
+	},
+	{
+		def:      `[{"type": "bytes21"}]`,
+		unpacked: [21]byte{1},
+		packed:   "0100000000000000000000000000000000000000000000000000000000000000",
+	},
+	{
+		def:      `[{"type": "bytes22"}]`,
+		unpacked: [22]byte{1},
+		packed:   "0100000000000000000000000000000000000000000000000000000000000000",
+	},
+	{
+		def:      `[{"type": "bytes23"}]`,
+		unpacked: [23]byte{1},
+		packed:   "0100000000000000000000000000000000000000000000000000000000000000",
+	},
+	{
+		def:      `[{"type": "bytes24"}]`,
+		unpacked: [24]byte{1},
+		packed:   "0100000000000000000000000000000000000000000000000000000000000000",
+	},
+	{
+		def:      `[{"type": "bytes25"}]`,
+		unpacked: [25]byte{1},
+		packed:   "0100000000000000000000000000000000000000000000000000000000000000",
+	},
+	{
+		def:      `[{"type": "bytes26"}]`,
+		unpacked: [26]byte{1},
+		packed:   "0100000000000000000000000000000000000000000000000000000000000000",
+	},
+	{
+		def:      `[{"type": "bytes27"}]`,
+		unpacked: [27]byte{1},
+		packed:   "0100000000000000000000000000000000000000000000000000000000000000",
+	},
+	{
+		def:      `[{"type": "bytes28"}]`,
+		unpacked: [28]byte{1},
+		packed:   "0100000000000000000000000000000000000000000000000000000000000000",
+	},
+	{
+		def:      `[{"type": "bytes29"}]`,
+		unpacked: [29]byte{1},
+		packed:   "0100000000000000000000000000000000000000000000000000000000000000",
+	},
+	{
+		def:      `[{"type": "bytes30"}]`,
+		unpacked: [30]byte{1},
+		packed:   "0100000000000000000000000000000000000000000000000000000000000000",
+	},
+	{
+		def:      `[{"type": "bytes31"}]`,
+		unpacked: [31]byte{1},
+		packed:   "0100000000000000000000000000000000000000000000000000000000000000",
+	},
+	{
+		def:      `[{"type": "bytes32"}]`,
+		unpacked: [32]byte{1},
+		packed:   "0100000000000000000000000000000000000000000000000000000000000000",
+	},
+	{
+		def:      `[{"type": "bytes32"}]`,
+		packed:   "0100000000000000000000000000000000000000000000000000000000000000",
+		unpacked: [32]byte{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	},
+	{
+		def: `[{"type": "bytes"}]`,
+		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
+			"0000000000000000000000000000000000000000000000000000000000000020" +
+			"0100000000000000000000000000000000000000000000000000000000000000",
+		unpacked: common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"),
+	},
+	{
+		def:      `[{"type": "bytes32"}]`,
+		packed:   "0100000000000000000000000000000000000000000000000000000000000000",
+		unpacked: [32]byte{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	},
+	// Functions
+	{
+		def:      `[{"type": "function"}]`,
+		packed:   "0100000000000000000000000000000000000000000000000000000000000000",
+		unpacked: [24]byte{1},
+	},
+	// Slice and Array
+	{
+		def: `[{"type": "uint8[]"}]`,
+		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
+			"0000000000000000000000000000000000000000000000000000000000000002" +
+			"0000000000000000000000000000000000000000000000000000000000000001" +
+			"0000000000000000000000000000000000000000000000000000000000000002",
+		unpacked: []uint8{1, 2},
+	},
+	{
+		def: `[{"type": "uint8[]"}]`,
+		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
+			"0000000000000000000000000000000000000000000000000000000000000000",
+		unpacked: []uint8{},
+	},
+	{
+		def: `[{"type": "uint256[]"}]`,
+		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
+			"0000000000000000000000000000000000000000000000000000000000000000",
+		unpacked: []*big.Int{},
+	},
+	{
+		def: `[{"type": "uint8[2]"}]`,
+		packed: "0000000000000000000000000000000000000000000000000000000000000001" +
+			"0000000000000000000000000000000000000000000000000000000000000002",
+		unpacked: [2]uint8{1, 2},
+	},
+	{
+		def: `[{"type": "int8[2]"}]`,
+		packed: "0000000000000000000000000000000000000000000000000000000000000001" +
+			"0000000000000000000000000000000000000000000000000000000000000002",
+		unpacked: [2]int8{1, 2},
+	},
+	{
+		def: `[{"type": "int16[]"}]`,
+		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
+			"0000000000000000000000000000000000000000000000000000000000000002" +
+			"0000000000000000000000000000000000000000000000000000000000000001" +
+			"0000000000000000000000000000000000000000000000000000000000000002",
+		unpacked: []int16{1, 2},
+	},
+	{
+		def: `[{"type": "int16[2]"}]`,
+		packed: "0000000000000000000000000000000000000000000000000000000000000001" +
+			"0000000000000000000000000000000000000000000000000000000000000002",
+		unpacked: [2]int16{1, 2},
+	},
+	{
+		def: `[{"type": "int32[]"}]`,
+		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
+			"0000000000000000000000000000000000000000000000000000000000000002" +
+			"0000000000000000000000000000000000000000000000000000000000000001" +
+			"0000000000000000000000000000000000000000000000000000000000000002",
+		unpacked: []int32{1, 2},
+	},
+	{
+		def: `[{"type": "int32[2]"}]`,
+		packed: "0000000000000000000000000000000000000000000000000000000000000001" +
+			"0000000000000000000000000000000000000000000000000000000000000002",
+		unpacked: [2]int32{1, 2},
+	},
+	{
+		def: `[{"type": "int64[]"}]`,
+		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
+			"0000000000000000000000000000000000000000000000000000000000000002" +
+			"0000000000000000000000000000000000000000000000000000000000000001" +
+			"0000000000000000000000000000000000000000000000000000000000000002",
+		unpacked: []int64{1, 2},
+	},
+	{
+		def: `[{"type": "int64[2]"}]`,
+		packed: "0000000000000000000000000000000000000000000000000000000000000001" +
+			"0000000000000000000000000000000000000000000000000000000000000002",
+		unpacked: [2]int64{1, 2},
+	},
+	{
+		def: `[{"type": "int256[]"}]`,
+		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
+			"0000000000000000000000000000000000000000000000000000000000000002" +
+			"0000000000000000000000000000000000000000000000000000000000000001" +
+			"0000000000000000000000000000000000000000000000000000000000000002",
+		unpacked: []*big.Int{big.NewInt(1), big.NewInt(2)},
+	},
+	{
+		def: `[{"type": "int256[3]"}]`,
+		packed: "0000000000000000000000000000000000000000000000000000000000000001" +
+			"0000000000000000000000000000000000000000000000000000000000000002" +
+			"0000000000000000000000000000000000000000000000000000000000000003",
+		unpacked: [3]*big.Int{big.NewInt(1), big.NewInt(2), big.NewInt(3)},
+	},
+	// multi dimensional, if these pass, all types that don't require length prefix should pass
+	{
+		def: `[{"type": "uint8[][]"}]`,
+		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
+			"0000000000000000000000000000000000000000000000000000000000000000",
+		unpacked: [][]uint8{},
+	},
+	{
+		def: `[{"type": "uint8[][]"}]`,
+		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
+			"0000000000000000000000000000000000000000000000000000000000000002" +
+			"0000000000000000000000000000000000000000000000000000000000000040" +
+			"00000000000000000000000000000000000000000000000000000000000000a0" +
+			"0000000000000000000000000000000000000000000000000000000000000002" +
+			"0000000000000000000000000000000000000000000000000000000000000001" +
+			"0000000000000000000000000000000000000000000000000000000000000002" +
+			"0000000000000000000000000000000000000000000000000000000000000002" +
+			"0000000000000000000000000000000000000000000000000000000000000001" +
+			"0000000000000000000000000000000000000000000000000000000000000002",
+		unpacked: [][]uint8{{1, 2}, {1, 2}},
+	},
+	{
+		def: `[{"type": "uint8[][]"}]`,
+		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
+			"0000000000000000000000000000000000000000000000000000000000000002" +
+			"0000000000000000000000000000000000000000000000000000000000000040" +
+			"00000000000000000000000000000000000000000000000000000000000000a0" +
+			"0000000000000000000000000000000000000000000000000000000000000002" +
+			"0000000000000000000000000000000000000000000000000000000000000001" +
+			"0000000000000000000000000000000000000000000000000000000000000002" +
+			"0000000000000000000000000000000000000000000000000000000000000003" +
+			"0000000000000000000000000000000000000000000000000000000000000001" +
+			"0000000000000000000000000000000000000000000000000000000000000002" +
+			"0000000000000000000000000000000000000000000000000000000000000003",
+		unpacked: [][]uint8{{1, 2}, {1, 2, 3}},
+	},
+	{
+		def: `[{"type": "uint8[2][2]"}]`,
+		packed: "0000000000000000000000000000000000000000000000000000000000000001" +
+			"0000000000000000000000000000000000000000000000000000000000000002" +
+			"0000000000000000000000000000000000000000000000000000000000000001" +
+			"0000000000000000000000000000000000000000000000000000000000000002",
+		unpacked: [2][2]uint8{{1, 2}, {1, 2}},
+	},
+	{
+		def: `[{"type": "uint8[][2]"}]`,
+		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
+			"0000000000000000000000000000000000000000000000000000000000000040" +
+			"0000000000000000000000000000000000000000000000000000000000000060" +
+			"0000000000000000000000000000000000000000000000000000000000000000" +
+			"0000000000000000000000000000000000000000000000000000000000000000",
+		unpacked: [2][]uint8{{}, {}},
+	},
+	{
+		def: `[{"type": "uint8[][2]"}]`,
+		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
+			"0000000000000000000000000000000000000000000000000000000000000040" +
+			"0000000000000000000000000000000000000000000000000000000000000080" +
+			"0000000000000000000000000000000000000000000000000000000000000001" +
+			"0000000000000000000000000000000000000000000000000000000000000001" +
+			"0000000000000000000000000000000000000000000000000000000000000001" +
+			"0000000000000000000000000000000000000000000000000000000000000001",
+		unpacked: [2][]uint8{{1}, {1}},
+	},
+	{
+		def: `[{"type": "uint8[2][]"}]`,
+		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
+			"0000000000000000000000000000000000000000000000000000000000000000",
+		unpacked: [][2]uint8{},
+	},
+	{
+		def: `[{"type": "uint8[2][]"}]`,
+		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
+			"0000000000000000000000000000000000000000000000000000000000000001" +
+			"0000000000000000000000000000000000000000000000000000000000000001" +
+			"0000000000000000000000000000000000000000000000000000000000000002",
+		unpacked: [][2]uint8{{1, 2}},
+	},
+	{
+		def: `[{"type": "uint8[2][]"}]`,
+		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
+			"0000000000000000000000000000000000000000000000000000000000000002" +
+			"0000000000000000000000000000000000000000000000000000000000000001" +
+			"0000000000000000000000000000000000000000000000000000000000000002" +
+			"0000000000000000000000000000000000000000000000000000000000000001" +
+			"0000000000000000000000000000000000000000000000000000000000000002",
+		unpacked: [][2]uint8{{1, 2}, {1, 2}},
+	},
+	{
+		def: `[{"type": "uint16[]"}]`,
+		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
+			"0000000000000000000000000000000000000000000000000000000000000002" +
+			"0000000000000000000000000000000000000000000000000000000000000001" +
+			"0000000000000000000000000000000000000000000000000000000000000002",
+		unpacked: []uint16{1, 2},
+	},
+	{
+		def: `[{"type": "uint16[2]"}]`,
+		packed: "0000000000000000000000000000000000000000000000000000000000000001" +
+			"0000000000000000000000000000000000000000000000000000000000000002",
+		unpacked: [2]uint16{1, 2},
+	},
+	{
+		def: `[{"type": "uint32[]"}]`,
+		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
+			"0000000000000000000000000000000000000000000000000000000000000002" +
+			"0000000000000000000000000000000000000000000000000000000000000001" +
+			"0000000000000000000000000000000000000000000000000000000000000002",
+		unpacked: []uint32{1, 2},
+	},
+	{
+		def:      `[{"type": "uint32[2][3][4]"}]`,
+		unpacked: [4][3][2]uint32{{{1, 2}, {3, 4}, {5, 6}}, {{7, 8}, {9, 10}, {11, 12}}, {{13, 14}, {15, 16}, {17, 18}}, {{19, 20}, {21, 22}, {23, 24}}},
+		packed: "0000000000000000000000000000000000000000000000000000000000000001" +
+			"0000000000000000000000000000000000000000000000000000000000000002" +
+			"0000000000000000000000000000000000000000000000000000000000000003" +
+			"0000000000000000000000000000000000000000000000000000000000000004" +
+			"0000000000000000000000000000000000000000000000000000000000000005" +
+			"0000000000000000000000000000000000000000000000000000000000000006" +
+			"0000000000000000000000000000000000000000000000000000000000000007" +
+			"0000000000000000000000000000000000000000000000000000000000000008" +
+			"0000000000000000000000000000000000000000000000000000000000000009" +
+			"000000000000000000000000000000000000000000000000000000000000000a" +
+			"000000000000000000000000000000000000000000000000000000000000000b" +
+			"000000000000000000000000000000000000000000000000000000000000000c" +
+			"000000000000000000000000000000000000000000000000000000000000000d" +
+			"000000000000000000000000000000000000000000000000000000000000000e" +
+			"000000000000000000000000000000000000000000000000000000000000000f" +
+			"0000000000000000000000000000000000000000000000000000000000000010" +
+			"0000000000000000000000000000000000000000000000000000000000000011" +
+			"0000000000000000000000000000000000000000000000000000000000000012" +
+			"0000000000000000000000000000000000000000000000000000000000000013" +
+			"0000000000000000000000000000000000000000000000000000000000000014" +
+			"0000000000000000000000000000000000000000000000000000000000000015" +
+			"0000000000000000000000000000000000000000000000000000000000000016" +
+			"0000000000000000000000000000000000000000000000000000000000000017" +
+			"0000000000000000000000000000000000000000000000000000000000000018",
+	},
+
+	{
+		def:      `[{"type": "bytes32[]"}]`,
+		unpacked: []common.Hash{{1}, {2}},
+		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
+			"0000000000000000000000000000000000000000000000000000000000000002" +
+			"0100000000000000000000000000000000000000000000000000000000000000" +
+			"0200000000000000000000000000000000000000000000000000000000000000",
+	},
+	{
+		def: `[{"type": "uint32[2]"}]`,
+		packed: "0000000000000000000000000000000000000000000000000000000000000001" +
+			"0000000000000000000000000000000000000000000000000000000000000002",
+		unpacked: [2]uint32{1, 2},
+	},
+	{
+		def: `[{"type": "uint64[]"}]`,
+		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
+			"0000000000000000000000000000000000000000000000000000000000000002" +
+			"0000000000000000000000000000000000000000000000000000000000000001" +
+			"0000000000000000000000000000000000000000000000000000000000000002",
+		unpacked: []uint64{1, 2},
+	},
+	{
+		def: `[{"type": "uint64[2]"}]`,
+		packed: "0000000000000000000000000000000000000000000000000000000000000001" +
+			"0000000000000000000000000000000000000000000000000000000000000002",
+		unpacked: [2]uint64{1, 2},
+	},
+	{
+		def: `[{"type": "uint256[]"}]`,
+		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
+			"0000000000000000000000000000000000000000000000000000000000000002" +
+			"0000000000000000000000000000000000000000000000000000000000000001" +
+			"0000000000000000000000000000000000000000000000000000000000000002",
+		unpacked: []*big.Int{big.NewInt(1), big.NewInt(2)},
+	},
+	{
+		def: `[{"type": "uint256[3]"}]`,
+		packed: "0000000000000000000000000000000000000000000000000000000000000001" +
+			"0000000000000000000000000000000000000000000000000000000000000002" +
+			"0000000000000000000000000000000000000000000000000000000000000003",
+		unpacked: [3]*big.Int{big.NewInt(1), big.NewInt(2), big.NewInt(3)},
+	},
+	{
+		def: `[{"type": "string[4]"}]`,
+		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
+			"0000000000000000000000000000000000000000000000000000000000000080" +
+			"00000000000000000000000000000000000000000000000000000000000000c0" +
+			"0000000000000000000000000000000000000000000000000000000000000100" +
+			"0000000000000000000000000000000000000000000000000000000000000140" +
+			"0000000000000000000000000000000000000000000000000000000000000005" +
+			"48656c6c6f000000000000000000000000000000000000000000000000000000" +
+			"0000000000000000000000000000000000000000000000000000000000000005" +
+			"576f726c64000000000000000000000000000000000000000000000000000000" +
+			"000000000000000000000000000000000000000000000000000000000000000b" +
+			"476f2d657468657265756d000000000000000000000000000000000000000000" +
+			"0000000000000000000000000000000000000000000000000000000000000008" +
+			"457468657265756d000000000000000000000000000000000000000000000000",
+		unpacked: [4]string{"Hello", "World", "Go-ethereum", "Ethereum"},
+	},
+	{
+		def: `[{"type": "string[]"}]`,
+		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
+			"0000000000000000000000000000000000000000000000000000000000000002" +
+			"0000000000000000000000000000000000000000000000000000000000000040" +
+			"0000000000000000000000000000000000000000000000000000000000000080" +
+			"0000000000000000000000000000000000000000000000000000000000000008" +
+			"457468657265756d000000000000000000000000000000000000000000000000" +
+			"000000000000000000000000000000000000000000000000000000000000000b" +
+			"676f2d657468657265756d000000000000000000000000000000000000000000",
+		unpacked: []string{"Ethereum", "go-ethereum"},
+	},
+	{
+		def: `[{"type": "bytes[]"}]`,
+		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
+			"0000000000000000000000000000000000000000000000000000000000000002" +
+			"0000000000000000000000000000000000000000000000000000000000000040" +
+			"0000000000000000000000000000000000000000000000000000000000000080" +
+			"0000000000000000000000000000000000000000000000000000000000000003" +
+			"f0f0f00000000000000000000000000000000000000000000000000000000000" +
+			"0000000000000000000000000000000000000000000000000000000000000003" +
+			"f0f0f00000000000000000000000000000000000000000000000000000000000",
+		unpacked: [][]byte{{0xf0, 0xf0, 0xf0}, {0xf0, 0xf0, 0xf0}},
+	},
+	{
+		def: `[{"type": "uint256[2][][]"}]`,
+		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
+			"0000000000000000000000000000000000000000000000000000000000000002" +
+			"0000000000000000000000000000000000000000000000000000000000000040" +
+			"00000000000000000000000000000000000000000000000000000000000000e0" +
+			"0000000000000000000000000000000000000000000000000000000000000002" +
+			"0000000000000000000000000000000000000000000000000000000000000001" +
+			"00000000000000000000000000000000000000000000000000000000000000c8" +
+			"0000000000000000000000000000000000000000000000000000000000000001" +
+			"00000000000000000000000000000000000000000000000000000000000003e8" +
+			"0000000000000000000000000000000000000000000000000000000000000002" +
+			"0000000000000000000000000000000000000000000000000000000000000001" +
+			"00000000000000000000000000000000000000000000000000000000000000c8" +
+			"0000000000000000000000000000000000000000000000000000000000000001" +
+			"00000000000000000000000000000000000000000000000000000000000003e8",
+		unpacked: [][][2]*big.Int{{{big.NewInt(1), big.NewInt(200)}, {big.NewInt(1), big.NewInt(1000)}}, {{big.NewInt(1), big.NewInt(200)}, {big.NewInt(1), big.NewInt(1000)}}},
+	},
+	// struct outputs
+	{
+		def: `[{"name":"int1","type":"int256"},{"name":"int2","type":"int256"}]`,
+		packed: "0000000000000000000000000000000000000000000000000000000000000001" +
+			"0000000000000000000000000000000000000000000000000000000000000002",
+		unpacked: struct {
+			Int1 *big.Int
+			Int2 *big.Int
+		}{big.NewInt(1), big.NewInt(2)},
+	},
+	{
+		def:    `[{"name":"int_one","type":"int256"}]`,
+		packed: "0000000000000000000000000000000000000000000000000000000000000001",
+		unpacked: struct {
+			IntOne *big.Int
+		}{big.NewInt(1)},
+	},
+	{
+		def:    `[{"name":"int__one","type":"int256"}]`,
+		packed: "0000000000000000000000000000000000000000000000000000000000000001",
+		unpacked: struct {
+			IntOne *big.Int
+		}{big.NewInt(1)},
+	},
+	{
+		def:    `[{"name":"int_one_","type":"int256"}]`,
+		packed: "0000000000000000000000000000000000000000000000000000000000000001",
+		unpacked: struct {
+			IntOne *big.Int
+		}{big.NewInt(1)},
+	},
+	{
+		def: `[{"name":"int_one","type":"int256"}, {"name":"intone","type":"int256"}]`,
+		packed: "0000000000000000000000000000000000000000000000000000000000000001" +
+			"0000000000000000000000000000000000000000000000000000000000000002",
+		unpacked: struct {
+			IntOne *big.Int
+			Intone *big.Int
+		}{big.NewInt(1), big.NewInt(2)},
+	},
+	{
+		def:      `[{"type": "string"}]`,
+		unpacked: "foobar",
+		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
+			"0000000000000000000000000000000000000000000000000000000000000006" +
+			"666f6f6261720000000000000000000000000000000000000000000000000000",
+	},
+	{
+		def:      `[{"type": "string[]"}]`,
+		unpacked: []string{"hello", "foobar"},
+		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
+			"0000000000000000000000000000000000000000000000000000000000000002" + // len(array) = 2
+			"0000000000000000000000000000000000000000000000000000000000000040" + // offset 64 to i = 0
+			"0000000000000000000000000000000000000000000000000000000000000080" + // offset 128 to i = 1
+			"0000000000000000000000000000000000000000000000000000000000000005" + // len(str[0]) = 5
+			"68656c6c6f000000000000000000000000000000000000000000000000000000" + // str[0]
+			"0000000000000000000000000000000000000000000000000000000000000006" + // len(str[1]) = 6
+			"666f6f6261720000000000000000000000000000000000000000000000000000", // str[1]
+	},
+	{
+		def:      `[{"type": "string[2]"}]`,
+		unpacked: [2]string{"hello", "foobar"},
+		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
+			"0000000000000000000000000000000000000000000000000000000000000040" + // offset to i = 0
+			"0000000000000000000000000000000000000000000000000000000000000080" + // offset to i = 1
+			"0000000000000000000000000000000000000000000000000000000000000005" + // len(str[0]) = 5
+			"68656c6c6f000000000000000000000000000000000000000000000000000000" + // str[0]
+			"0000000000000000000000000000000000000000000000000000000000000006" + // len(str[1]) = 6
+			"666f6f6261720000000000000000000000000000000000000000000000000000", // str[1]
+	},
+	{
+		def:      `[{"type": "bytes32[][]"}]`,
+		unpacked: [][][32]byte{{{1}, {2}}, {{3}, {4}, {5}}},
+		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
+			"0000000000000000000000000000000000000000000000000000000000000002" + // len(array) = 2
+			"0000000000000000000000000000000000000000000000000000000000000040" + // offset 64 to i = 0
+			"00000000000000000000000000000000000000000000000000000000000000a0" + // offset 160 to i = 1
+			"0000000000000000000000000000000000000000000000000000000000000002" + // len(array[0]) = 2
+			"0100000000000000000000000000000000000000000000000000000000000000" + // array[0][0]
+			"0200000000000000000000000000000000000000000000000000000000000000" + // array[0][1]
+			"0000000000000000000000000000000000000000000000000000000000000003" + // len(array[1]) = 3
+			"0300000000000000000000000000000000000000000000000000000000000000" + // array[1][0]
+			"0400000000000000000000000000000000000000000000000000000000000000" + // array[1][1]
+			"0500000000000000000000000000000000000000000000000000000000000000", // array[1][2]
+	},
+	{
+		def:      `[{"type": "bytes32[][2]"}]`,
+		unpacked: [2][][32]byte{{{1}, {2}}, {{3}, {4}, {5}}},
+		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
+			"0000000000000000000000000000000000000000000000000000000000000040" + // offset 64 to i = 0
+			"00000000000000000000000000000000000000000000000000000000000000a0" + // offset 160 to i = 1
+			"0000000000000000000000000000000000000000000000000000000000000002" + // len(array[0]) = 2
+			"0100000000000000000000000000000000000000000000000000000000000000" + // array[0][0]
+			"0200000000000000000000000000000000000000000000000000000000000000" + // array[0][1]
+			"0000000000000000000000000000000000000000000000000000000000000003" + // len(array[1]) = 3
+			"0300000000000000000000000000000000000000000000000000000000000000" + // array[1][0]
+			"0400000000000000000000000000000000000000000000000000000000000000" + // array[1][1]
+			"0500000000000000000000000000000000000000000000000000000000000000", // array[1][2]
+	},
+	{
+		def:      `[{"type": "bytes32[3][2]"}]`,
+		unpacked: [2][3][32]byte{{{1}, {2}, {3}}, {{3}, {4}, {5}}},
+		packed: "0100000000000000000000000000000000000000000000000000000000000000" + // array[0][0]
+			"0200000000000000000000000000000000000000000000000000000000000000" + // array[0][1]
+			"0300000000000000000000000000000000000000000000000000000000000000" + // array[0][2]
+			"0300000000000000000000000000000000000000000000000000000000000000" + // array[1][0]
+			"0400000000000000000000000000000000000000000000000000000000000000" + // array[1][1]
+			"0500000000000000000000000000000000000000000000000000000000000000", // array[1][2]
+	},
+	{
+		// static tuple
+		def: `[{"name":"a","type":"int64"}, 
+		{"name":"b","type":"int256"}, 
+		{"name":"c","type":"int256"}, 
+		{"name":"d","type":"bool"},
+		{"name":"e","type":"bytes32[3][2]"}]`,
+		unpacked: struct {
+			A int64
+			B *big.Int
+			C *big.Int
+			D bool
+			E [2][3][32]byte
+		}{1, big.NewInt(1), big.NewInt(-1), true, [2][3][32]byte{{{1}, {2}, {3}}, {{3}, {4}, {5}}}},
+		packed: "0000000000000000000000000000000000000000000000000000000000000001" + // struct[a]
+			"0000000000000000000000000000000000000000000000000000000000000001" + // struct[b]
+			"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + // struct[c]
+			"0000000000000000000000000000000000000000000000000000000000000001" + // struct[d]
+			"0100000000000000000000000000000000000000000000000000000000000000" + // struct[e] array[0][0]
+			"0200000000000000000000000000000000000000000000000000000000000000" + // struct[e] array[0][1]
+			"0300000000000000000000000000000000000000000000000000000000000000" + // struct[e] array[0][2]
+			"0300000000000000000000000000000000000000000000000000000000000000" + // struct[e] array[1][0]
+			"0400000000000000000000000000000000000000000000000000000000000000" + // struct[e] array[1][1]
+			"0500000000000000000000000000000000000000000000000000000000000000", // struct[e] array[1][2]
+	},
+	{
+		def: `[{"name":"a","type":"string"}, 
+		{"name":"b","type":"int64"}, 
+		{"name":"c","type":"bytes"}, 
+		{"name":"d","type":"string[]"},
+		{"name":"e","type":"int256[]"},
+		{"name":"f","type":"address[]"}]`,
+		unpacked: struct {
+			FieldA string `abi:"a"` // Test whether abi tag works
+			FieldB int64  `abi:"b"`
+			C      []byte
+			D      []string
+			E      []*big.Int
+			F      []common.Address
+		}{"foobar", 1, []byte{1}, []string{"foo", "bar"}, []*big.Int{big.NewInt(1), big.NewInt(-1)}, []common.Address{{1}, {2}}},
+		packed: "00000000000000000000000000000000000000000000000000000000000000c0" + // struct[a] offset
+			"0000000000000000000000000000000000000000000000000000000000000001" + // struct[b]
+			"0000000000000000000000000000000000000000000000000000000000000100" + // struct[c] offset
+			"0000000000000000000000000000000000000000000000000000000000000140" + // struct[d] offset
+			"0000000000000000000000000000000000000000000000000000000000000220" + // struct[e] offset
+			"0000000000000000000000000000000000000000000000000000000000000280" + // struct[f] offset
+			"0000000000000000000000000000000000000000000000000000000000000006" + // struct[a] length
+			"666f6f6261720000000000000000000000000000000000000000000000000000" + // struct[a] "foobar"
+			"0000000000000000000000000000000000000000000000000000000000000001" + // struct[c] length
+			"0100000000000000000000000000000000000000000000000000000000000000" + // []byte{1}
+			"0000000000000000000000000000000000000000000000000000000000000002" + // struct[d] length
+			"0000000000000000000000000000000000000000000000000000000000000040" + // foo offset
+			"0000000000000000000000000000000000000000000000000000000000000080" + // bar offset
+			"0000000000000000000000000000000000000000000000000000000000000003" + // foo length
+			"666f6f0000000000000000000000000000000000000000000000000000000000" + // foo
+			"0000000000000000000000000000000000000000000000000000000000000003" + // bar offset
+			"6261720000000000000000000000000000000000000000000000000000000000" + // bar
+			"0000000000000000000000000000000000000000000000000000000000000002" + // struct[e] length
+			"0000000000000000000000000000000000000000000000000000000000000001" + // 1
+			"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + // -1
+			"0000000000000000000000000000000000000000000000000000000000000002" + // struct[f] length
+			"0000000000000000000000000100000000000000000000000000000000000000" + // common.Address{1}
+			"0000000000000000000000000200000000000000000000000000000000000000", // common.Address{2}
+	},
+	{
+		def: `[{"components": [{"name": "a","type": "uint256"},	
+							{"name": "b","type": "uint256[]"}],	
+							"name": "a","type": "tuple"},
+							{"name": "b","type": "uint256[]"}]`,
+		unpacked: struct {
+			A struct {
+				FieldA *big.Int `abi:"a"`
+				B      []*big.Int
+			}
+			B []*big.Int
+		}{
+			A: struct {
+				FieldA *big.Int `abi:"a"` // Test whether abi tag works for nested tuple
+				B      []*big.Int
+			}{big.NewInt(1), []*big.Int{big.NewInt(1), big.NewInt(2)}},
+			B: []*big.Int{big.NewInt(1), big.NewInt(2)}},
+		packed: "0000000000000000000000000000000000000000000000000000000000000040" + // a offset
+			"00000000000000000000000000000000000000000000000000000000000000e0" + // b offset
+			"0000000000000000000000000000000000000000000000000000000000000001" + // a.a value
+			"0000000000000000000000000000000000000000000000000000000000000040" + // a.b offset
+			"0000000000000000000000000000000000000000000000000000000000000002" + // a.b length
+			"0000000000000000000000000000000000000000000000000000000000000001" + // a.b[0] value
+			"0000000000000000000000000000000000000000000000000000000000000002" + // a.b[1] value
+			"0000000000000000000000000000000000000000000000000000000000000002" + // b length
+			"0000000000000000000000000000000000000000000000000000000000000001" + // b[0] value
+			"0000000000000000000000000000000000000000000000000000000000000002", // b[1] value
+	},
+
+	{
+		def: `[{"components": [{"name": "a","type": "int256"},	
+							{"name": "b","type": "int256[]"}],	
+							"name": "a","type": "tuple[]"}]`,
+		unpacked: []struct {
+			A *big.Int
+			B []*big.Int
+		}{
+			{big.NewInt(-1), []*big.Int{big.NewInt(1), big.NewInt(3)}},
+			{big.NewInt(1), []*big.Int{big.NewInt(2), big.NewInt(-1)}},
+		},
+		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
+			"0000000000000000000000000000000000000000000000000000000000000002" + // tuple length
+			"0000000000000000000000000000000000000000000000000000000000000040" + // tuple[0] offset
+			"00000000000000000000000000000000000000000000000000000000000000e0" + // tuple[1] offset
+			"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + // tuple[0].A
+			"0000000000000000000000000000000000000000000000000000000000000040" + // tuple[0].B offset
+			"0000000000000000000000000000000000000000000000000000000000000002" + // tuple[0].B length
+			"0000000000000000000000000000000000000000000000000000000000000001" + // tuple[0].B[0] value
+			"0000000000000000000000000000000000000000000000000000000000000003" + // tuple[0].B[1] value
+			"0000000000000000000000000000000000000000000000000000000000000001" + // tuple[1].A
+			"0000000000000000000000000000000000000000000000000000000000000040" + // tuple[1].B offset
+			"0000000000000000000000000000000000000000000000000000000000000002" + // tuple[1].B length
+			"0000000000000000000000000000000000000000000000000000000000000002" + // tuple[1].B[0] value
+			"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", // tuple[1].B[1] value
+	},
+	{
+		def: `[{"components": [{"name": "a","type": "int256"},	
+							{"name": "b","type": "int256"}],	
+							"name": "a","type": "tuple[2]"}]`,
+		unpacked: [2]struct {
+			A *big.Int
+			B *big.Int
+		}{
+			{big.NewInt(-1), big.NewInt(1)},
+			{big.NewInt(1), big.NewInt(-1)},
+		},
+		packed: "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + // tuple[0].a
+			"0000000000000000000000000000000000000000000000000000000000000001" + // tuple[0].b
+			"0000000000000000000000000000000000000000000000000000000000000001" + // tuple[1].a
+			"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", // tuple[1].b
+	},
+	{
+		def: `[{"components": [{"name": "a","type": "int256[]"}],
+							"name": "a","type": "tuple[2]"}]`,
+		unpacked: [2]struct {
+			A []*big.Int
+		}{
+			{[]*big.Int{big.NewInt(-1), big.NewInt(1)}},
+			{[]*big.Int{big.NewInt(1), big.NewInt(-1)}},
+		},
+		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
+			"0000000000000000000000000000000000000000000000000000000000000040" + // tuple[0] offset
+			"00000000000000000000000000000000000000000000000000000000000000c0" + // tuple[1] offset
+			"0000000000000000000000000000000000000000000000000000000000000020" + // tuple[0].A offset
+			"0000000000000000000000000000000000000000000000000000000000000002" + // tuple[0].A length
+			"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + // tuple[0].A[0]
+			"0000000000000000000000000000000000000000000000000000000000000001" + // tuple[0].A[1]
+			"0000000000000000000000000000000000000000000000000000000000000020" + // tuple[1].A offset
+			"0000000000000000000000000000000000000000000000000000000000000002" + // tuple[1].A length
+			"0000000000000000000000000000000000000000000000000000000000000001" + // tuple[1].A[0]
+			"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", // tuple[1].A[1]
+	},
+}

+ 17 - 19
accounts/abi/reflect.go

@@ -42,26 +42,26 @@ func indirectInterfaceOrPtr(v reflect.Value) reflect.Value {
 // reflectIntKind returns the reflect using the given size and
 // unsignedness.
 func reflectIntKindAndType(unsigned bool, size int) (reflect.Kind, reflect.Type) {
-	switch size {
-	case 8:
-		if unsigned {
+	if unsigned {
+		switch size {
+		case 8:
 			return reflect.Uint8, uint8T
+		case 16:
+			return reflect.Uint16, uint16T
+		case 32:
+			return reflect.Uint32, uint32T
+		case 64:
+			return reflect.Uint64, uint64T
 		}
+	}
+	switch size {
+	case 8:
 		return reflect.Int8, int8T
 	case 16:
-		if unsigned {
-			return reflect.Uint16, uint16T
-		}
 		return reflect.Int16, int16T
 	case 32:
-		if unsigned {
-			return reflect.Uint32, uint32T
-		}
 		return reflect.Int32, int32T
 	case 64:
-		if unsigned {
-			return reflect.Uint64, uint64T
-		}
 		return reflect.Int64, int64T
 	}
 	return reflect.Ptr, bigT
@@ -88,8 +88,8 @@ func set(dst, src reflect.Value) error {
 		return set(dst.Elem(), src)
 	case srcType.AssignableTo(dstType) && dst.CanSet():
 		dst.Set(src)
-	case dstType.Kind() == reflect.Slice && srcType.Kind() == reflect.Slice:
-		return setSlice(dst, src)
+	case dstType.Kind() == reflect.Slice && srcType.Kind() == reflect.Slice && dst.CanSet():
+		setSlice(dst, src)
 	default:
 		return fmt.Errorf("abi: cannot unmarshal %v in to %v", src.Type(), dst.Type())
 	}
@@ -98,15 +98,13 @@ func set(dst, src reflect.Value) error {
 
 // setSlice attempts to assign src to dst when slices are not assignable by default
 // e.g. src: [][]byte -> dst: [][15]byte
-func setSlice(dst, src reflect.Value) error {
+// setSlice ignores if we cannot copy all of src' elements.
+func setSlice(dst, src reflect.Value) {
 	slice := reflect.MakeSlice(dst.Type(), src.Len(), src.Len())
 	for i := 0; i < src.Len(); i++ {
-		v := src.Index(i)
-		reflect.Copy(slice.Index(i), v)
+		reflect.Copy(slice.Index(i), src.Index(i))
 	}
-
 	dst.Set(slice)
-	return nil
 }
 
 // requireAssignable assures that `dest` is a pointer and it's not an interface.

+ 25 - 0
accounts/abi/type_test.go

@@ -306,3 +306,28 @@ func TestTypeCheck(t *testing.T) {
 		}
 	}
 }
+
+func TestInternalType(t *testing.T) {
+	components := []ArgumentMarshaling{{Name: "a", Type: "int64"}}
+	internalType := "struct a.b[]"
+	kind := Type{
+		Kind: reflect.Struct,
+		T:    TupleTy,
+		Type: reflect.TypeOf(struct {
+			A int64 `json:"a"`
+		}{}),
+		stringKind:    "(int64)",
+		TupleRawName:  "ab[]",
+		TupleElems:    []*Type{{Kind: reflect.Int64, T: IntTy, Type: reflect.TypeOf(int64(0)), Size: 64, stringKind: "int64"}},
+		TupleRawNames: []string{"a"},
+	}
+
+	blob := "tuple"
+	typ, err := NewType(blob, internalType, components)
+	if err != nil {
+		t.Errorf("type %q: failed to parse type string: %v", blob, err)
+	}
+	if !reflect.DeepEqual(typ, kind) {
+		t.Errorf("type %q: parsed type mismatch:\nGOT %s\nWANT %s ", blob, spew.Sdump(typeWithoutStringer(typ)), spew.Sdump(typeWithoutStringer(kind)))
+	}
+}

+ 54 - 284
accounts/abi/unpack_test.go

@@ -30,6 +30,34 @@ import (
 	"github.com/stretchr/testify/require"
 )
 
+// TestUnpack tests the general pack/unpack tests in packing_test.go
+func TestUnpack(t *testing.T) {
+	for i, test := range packUnpackTests {
+		t.Run(strconv.Itoa(i), func(t *testing.T) {
+			//Unpack
+			def := fmt.Sprintf(`[{ "name" : "method", "type": "function", "outputs": %s}]`, test.def)
+			abi, err := JSON(strings.NewReader(def))
+			if err != nil {
+				t.Fatalf("invalid ABI definition %s: %v", def, err)
+			}
+			encb, err := hex.DecodeString(test.packed)
+			if err != nil {
+				t.Fatalf("invalid hex %s: %v", test.packed, err)
+			}
+			outptr := reflect.New(reflect.TypeOf(test.unpacked))
+			err = abi.Unpack(outptr.Interface(), "method", encb)
+			if err != nil {
+				t.Errorf("test %d (%v) failed: %v", i, test.def, err)
+				return
+			}
+			out := outptr.Elem().Interface()
+			if !reflect.DeepEqual(test.unpacked, out) {
+				t.Errorf("test %d (%v) failed: expected %v, got %v", i, test.def, test.unpacked, out)
+			}
+		})
+	}
+}
+
 type unpackTest struct {
 	def  string      // ABI definition JSON
 	enc  string      // evm return data
@@ -52,16 +80,6 @@ func (test unpackTest) checkError(err error) error {
 
 var unpackTests = []unpackTest{
 	// Bools
-	{
-		def:  `[{ "type": "bool" }]`,
-		enc:  "0000000000000000000000000000000000000000000000000000000000000001",
-		want: true,
-	},
-	{
-		def:  `[{ "type": "bool" }]`,
-		enc:  "0000000000000000000000000000000000000000000000000000000000000000",
-		want: false,
-	},
 	{
 		def:  `[{ "type": "bool" }]`,
 		enc:  "0000000000000000000000000000000000000000000000000001000000000001",
@@ -75,11 +93,6 @@ var unpackTests = []unpackTest{
 		err:  "abi: improperly encoded boolean value",
 	},
 	// Integers
-	{
-		def:  `[{"type": "uint32"}]`,
-		enc:  "0000000000000000000000000000000000000000000000000000000000000001",
-		want: uint32(1),
-	},
 	{
 		def:  `[{"type": "uint32"}]`,
 		enc:  "0000000000000000000000000000000000000000000000000000000000000001",
@@ -92,16 +105,6 @@ var unpackTests = []unpackTest{
 		want: uint16(0),
 		err:  "abi: cannot unmarshal *big.Int in to uint16",
 	},
-	{
-		def:  `[{"type": "uint17"}]`,
-		enc:  "0000000000000000000000000000000000000000000000000000000000000001",
-		want: big.NewInt(1),
-	},
-	{
-		def:  `[{"type": "int32"}]`,
-		enc:  "0000000000000000000000000000000000000000000000000000000000000001",
-		want: int32(1),
-	},
 	{
 		def:  `[{"type": "int32"}]`,
 		enc:  "0000000000000000000000000000000000000000000000000000000000000001",
@@ -114,33 +117,6 @@ var unpackTests = []unpackTest{
 		want: int16(0),
 		err:  "abi: cannot unmarshal *big.Int in to int16",
 	},
-	{
-		def:  `[{"type": "int17"}]`,
-		enc:  "0000000000000000000000000000000000000000000000000000000000000001",
-		want: big.NewInt(1),
-	},
-	{
-		def:  `[{"type": "int256"}]`,
-		enc:  "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
-		want: big.NewInt(-1),
-	},
-	// Address
-	{
-		def:  `[{"type": "address"}]`,
-		enc:  "0000000000000000000000000100000000000000000000000000000000000000",
-		want: common.Address{1},
-	},
-	// Bytes
-	{
-		def:  `[{"type": "bytes32"}]`,
-		enc:  "0100000000000000000000000000000000000000000000000000000000000000",
-		want: [32]byte{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
-	},
-	{
-		def:  `[{"type": "bytes"}]`,
-		enc:  "000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200100000000000000000000000000000000000000000000000000000000000000",
-		want: common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"),
-	},
 	{
 		def:  `[{"type": "bytes"}]`,
 		enc:  "000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200100000000000000000000000000000000000000000000000000000000000000",
@@ -153,237 +129,6 @@ var unpackTests = []unpackTest{
 		want: []byte(nil),
 		err:  "abi: cannot unmarshal [32]uint8 in to []uint8",
 	},
-	{
-		def:  `[{"type": "bytes32"}]`,
-		enc:  "0100000000000000000000000000000000000000000000000000000000000000",
-		want: [32]byte{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
-	},
-	// Functions
-	{
-		def:  `[{"type": "function"}]`,
-		enc:  "0100000000000000000000000000000000000000000000000000000000000000",
-		want: [24]byte{1},
-	},
-	// Slice and Array
-	{
-		def:  `[{"type": "uint8[]"}]`,
-		enc:  "0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
-		want: []uint8{1, 2},
-	},
-	{
-		def:  `[{"type": "uint8[]"}]`,
-		enc:  "00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000",
-		want: []uint8{},
-	},
-	{
-		def:  `[{"type": "uint256[]"}]`,
-		enc:  "00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000",
-		want: []*big.Int{},
-	},
-	{
-		def:  `[{"type": "uint8[2]"}]`,
-		enc:  "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
-		want: [2]uint8{1, 2},
-	},
-	// multi dimensional, if these pass, all types that don't require length prefix should pass
-	{
-		def:  `[{"type": "uint8[][]"}]`,
-		enc:  "00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000",
-		want: [][]uint8{},
-	},
-	{
-		def:  `[{"type": "uint8[][]"}]`,
-		enc:  "00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
-		want: [][]uint8{{1, 2}, {1, 2}},
-	},
-	{
-		def:  `[{"type": "uint8[][]"}]`,
-		enc:  "00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003",
-		want: [][]uint8{{1, 2}, {1, 2, 3}},
-	},
-	{
-		def:  `[{"type": "uint8[2][2]"}]`,
-		enc:  "0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
-		want: [2][2]uint8{{1, 2}, {1, 2}},
-	},
-	{
-		def:  `[{"type": "uint8[][2]"}]`,
-		enc:  "00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
-		want: [2][]uint8{{}, {}},
-	},
-	{
-		def:  `[{"type": "uint8[][2]"}]`,
-		enc:  "0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001",
-		want: [2][]uint8{{1}, {1}},
-	},
-	{
-		def:  `[{"type": "uint8[2][]"}]`,
-		enc:  "00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000",
-		want: [][2]uint8{},
-	},
-	{
-		def:  `[{"type": "uint8[2][]"}]`,
-		enc:  "0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
-		want: [][2]uint8{{1, 2}},
-	},
-	{
-		def:  `[{"type": "uint8[2][]"}]`,
-		enc:  "000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
-		want: [][2]uint8{{1, 2}, {1, 2}},
-	},
-	{
-		def:  `[{"type": "uint16[]"}]`,
-		enc:  "0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
-		want: []uint16{1, 2},
-	},
-	{
-		def:  `[{"type": "uint16[2]"}]`,
-		enc:  "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
-		want: [2]uint16{1, 2},
-	},
-	{
-		def:  `[{"type": "uint32[]"}]`,
-		enc:  "0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
-		want: []uint32{1, 2},
-	},
-	{
-		def:  `[{"type": "uint32[2]"}]`,
-		enc:  "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
-		want: [2]uint32{1, 2},
-	},
-	{
-		def:  `[{"type": "uint32[2][3][4]"}]`,
-		enc:  "000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000110000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000001300000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000015000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000170000000000000000000000000000000000000000000000000000000000000018",
-		want: [4][3][2]uint32{{{1, 2}, {3, 4}, {5, 6}}, {{7, 8}, {9, 10}, {11, 12}}, {{13, 14}, {15, 16}, {17, 18}}, {{19, 20}, {21, 22}, {23, 24}}},
-	},
-	{
-		def:  `[{"type": "uint64[]"}]`,
-		enc:  "0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
-		want: []uint64{1, 2},
-	},
-	{
-		def:  `[{"type": "uint64[2]"}]`,
-		enc:  "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
-		want: [2]uint64{1, 2},
-	},
-	{
-		def:  `[{"type": "uint256[]"}]`,
-		enc:  "0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
-		want: []*big.Int{big.NewInt(1), big.NewInt(2)},
-	},
-	{
-		def:  `[{"type": "uint256[3]"}]`,
-		enc:  "000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003",
-		want: [3]*big.Int{big.NewInt(1), big.NewInt(2), big.NewInt(3)},
-	},
-	{
-		def:  `[{"type": "string[4]"}]`,
-		enc:  "0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000000548656c6c6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c64000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b476f2d657468657265756d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008457468657265756d000000000000000000000000000000000000000000000000",
-		want: [4]string{"Hello", "World", "Go-ethereum", "Ethereum"},
-	},
-	{
-		def:  `[{"type": "string[]"}]`,
-		enc:  "00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000008457468657265756d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b676f2d657468657265756d000000000000000000000000000000000000000000",
-		want: []string{"Ethereum", "go-ethereum"},
-	},
-	{
-		def:  `[{"type": "bytes[]"}]`,
-		enc:  "00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000003f0f0f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003f0f0f00000000000000000000000000000000000000000000000000000000000",
-		want: [][]byte{{0xf0, 0xf0, 0xf0}, {0xf0, 0xf0, 0xf0}},
-	},
-	{
-		def:  `[{"type": "uint256[2][][]"}]`,
-		enc:  "00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000c8000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000003e80000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000c8000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000003e8",
-		want: [][][2]*big.Int{{{big.NewInt(1), big.NewInt(200)}, {big.NewInt(1), big.NewInt(1000)}}, {{big.NewInt(1), big.NewInt(200)}, {big.NewInt(1), big.NewInt(1000)}}},
-	},
-	{
-		def:  `[{"type": "int8[]"}]`,
-		enc:  "0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
-		want: []int8{1, 2},
-	},
-	{
-		def:  `[{"type": "int8[2]"}]`,
-		enc:  "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
-		want: [2]int8{1, 2},
-	},
-	{
-		def:  `[{"type": "int16[]"}]`,
-		enc:  "0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
-		want: []int16{1, 2},
-	},
-	{
-		def:  `[{"type": "int16[2]"}]`,
-		enc:  "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
-		want: [2]int16{1, 2},
-	},
-	{
-		def:  `[{"type": "int32[]"}]`,
-		enc:  "0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
-		want: []int32{1, 2},
-	},
-	{
-		def:  `[{"type": "int32[2]"}]`,
-		enc:  "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
-		want: [2]int32{1, 2},
-	},
-	{
-		def:  `[{"type": "int64[]"}]`,
-		enc:  "0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
-		want: []int64{1, 2},
-	},
-	{
-		def:  `[{"type": "int64[2]"}]`,
-		enc:  "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
-		want: [2]int64{1, 2},
-	},
-	{
-		def:  `[{"type": "int256[]"}]`,
-		enc:  "0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
-		want: []*big.Int{big.NewInt(1), big.NewInt(2)},
-	},
-	{
-		def:  `[{"type": "int256[3]"}]`,
-		enc:  "000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003",
-		want: [3]*big.Int{big.NewInt(1), big.NewInt(2), big.NewInt(3)},
-	},
-	// struct outputs
-	{
-		def: `[{"name":"int1","type":"int256"},{"name":"int2","type":"int256"}]`,
-		enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
-		want: struct {
-			Int1 *big.Int
-			Int2 *big.Int
-		}{big.NewInt(1), big.NewInt(2)},
-	},
-	{
-		def: `[{"name":"int_one","type":"int256"}]`,
-		enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
-		want: struct {
-			IntOne *big.Int
-		}{big.NewInt(1)},
-	},
-	{
-		def: `[{"name":"int__one","type":"int256"}]`,
-		enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
-		want: struct {
-			IntOne *big.Int
-		}{big.NewInt(1)},
-	},
-	{
-		def: `[{"name":"int_one_","type":"int256"}]`,
-		enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
-		want: struct {
-			IntOne *big.Int
-		}{big.NewInt(1)},
-	},
-	{
-		def: `[{"name":"int_one","type":"int256"}, {"name":"intone","type":"int256"}]`,
-		enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
-		want: struct {
-			IntOne *big.Int
-			Intone *big.Int
-		}{big.NewInt(1), big.NewInt(2)},
-	},
 	{
 		def: `[{"name":"___","type":"int256"}]`,
 		enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
@@ -438,11 +183,36 @@ var unpackTests = []unpackTest{
 		}{},
 		err: "abi: purely underscored output cannot unpack to struct",
 	},
+	// Make sure only the first argument is consumed
+	{
+		def: `[{"name":"int_one","type":"int256"}]`,
+		enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
+		want: struct {
+			IntOne *big.Int
+		}{big.NewInt(1)},
+	},
+	{
+		def: `[{"name":"int__one","type":"int256"}]`,
+		enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
+		want: struct {
+			IntOne *big.Int
+		}{big.NewInt(1)},
+	},
+	{
+		def: `[{"name":"int_one_","type":"int256"}]`,
+		enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
+		want: struct {
+			IntOne *big.Int
+		}{big.NewInt(1)},
+	},
 }
 
-func TestUnpack(t *testing.T) {
+// TestLocalUnpackTests runs test specially designed only for unpacking.
+// All test cases that can be used to test packing and unpacking should move to packing_test.go
+func TestLocalUnpackTests(t *testing.T) {
 	for i, test := range unpackTests {
 		t.Run(strconv.Itoa(i), func(t *testing.T) {
+			//Unpack
 			def := fmt.Sprintf(`[{ "name" : "method", "type": "function", "outputs": %s}]`, test.def)
 			abi, err := JSON(strings.NewReader(def))
 			if err != nil {