aboutsummaryrefslogtreecommitdiffstats
path: root/accounts/abi
diff options
context:
space:
mode:
authorJeffrey Wilcke <geffobscura@gmail.com>2016-03-30 22:22:02 +0800
committerJeffrey Wilcke <geffobscura@gmail.com>2016-04-05 02:30:58 +0800
commit022cbd680052eb87b32d5f59587957779d382c0c (patch)
treef4894fc2eeea920233fcdd108e0977cc3b19fb6f /accounts/abi
parent96c7c39ae4a031a508b0470ff2b1a95f0f3f9e51 (diff)
downloadgo-tangerine-022cbd680052eb87b32d5f59587957779d382c0c.tar
go-tangerine-022cbd680052eb87b32d5f59587957779d382c0c.tar.gz
go-tangerine-022cbd680052eb87b32d5f59587957779d382c0c.tar.bz2
go-tangerine-022cbd680052eb87b32d5f59587957779d382c0c.tar.lz
go-tangerine-022cbd680052eb87b32d5f59587957779d382c0c.tar.xz
go-tangerine-022cbd680052eb87b32d5f59587957779d382c0c.tar.zst
go-tangerine-022cbd680052eb87b32d5f59587957779d382c0c.zip
abi: accept input slices of all supported types
Diffstat (limited to 'accounts/abi')
-rw-r--r--accounts/abi/abi.go7
-rw-r--r--accounts/abi/abi_test.go119
-rw-r--r--accounts/abi/numbers.go2
-rw-r--r--accounts/abi/numbers_test.go4
-rw-r--r--accounts/abi/type.go119
5 files changed, 106 insertions, 145 deletions
diff --git a/accounts/abi/abi.go b/accounts/abi/abi.go
index 91f9700d9..01603b217 100644
--- a/accounts/abi/abi.go
+++ b/accounts/abi/abi.go
@@ -63,9 +63,8 @@ func (abi ABI) pack(method Method, args ...interface{}) ([]byte, error) {
return nil, fmt.Errorf("`%s` %v", method.Name, err)
}
- // check for a string or bytes input type
- switch input.Type.T {
- case StringTy, BytesTy:
+ // check for a slice type (string, bytes, slice)
+ if input.Type.T == StringTy || input.Type.T == BytesTy || input.Type.IsSlice {
// calculate the offset
offset := len(method.Inputs)*32 + len(variableInput)
// set the offset
@@ -73,7 +72,7 @@ func (abi ABI) pack(method Method, args ...interface{}) ([]byte, error) {
// Append the packed output to the variable input. The variable input
// will be appended at the end of the input.
variableInput = append(variableInput, packed...)
- default:
+ } else {
// append the packed value to the input
ret = append(ret, packed...)
}
diff --git a/accounts/abi/abi_test.go b/accounts/abi/abi_test.go
index 66d2e1b39..db33face9 100644
--- a/accounts/abi/abi_test.go
+++ b/accounts/abi/abi_test.go
@@ -49,7 +49,9 @@ const jsondata2 = `
{ "type" : "function", "name" : "foo", "const" : false, "inputs" : [ { "name" : "inputs", "type" : "uint32" } ] },
{ "type" : "function", "name" : "bar", "const" : false, "inputs" : [ { "name" : "inputs", "type" : "uint32" }, { "name" : "string", "type" : "uint16" } ] },
{ "type" : "function", "name" : "slice", "const" : false, "inputs" : [ { "name" : "inputs", "type" : "uint32[2]" } ] },
- { "type" : "function", "name" : "slice256", "const" : false, "inputs" : [ { "name" : "inputs", "type" : "uint256[2]" } ] }
+ { "type" : "function", "name" : "slice256", "const" : false, "inputs" : [ { "name" : "inputs", "type" : "uint256[2]" } ] },
+ { "type" : "function", "name" : "sliceAddress", "const" : false, "inputs" : [ { "name" : "inputs", "type" : "address[]" } ] },
+ { "type" : "function", "name" : "sliceMultiAddress", "const" : false, "inputs" : [ { "name" : "a", "type" : "address[]" }, { "name" : "b", "type" : "address[]" } ] }
]`
func TestType(t *testing.T) {
@@ -68,7 +70,7 @@ func TestType(t *testing.T) {
if typ.Kind != reflect.Slice {
t.Error("expected uint32[] to have type slice")
}
- if typ.Type != ubig_ts {
+ if typ.Type != ubig_t {
t.Error("expcted uith32[] to have type uint64")
}
@@ -79,7 +81,7 @@ func TestType(t *testing.T) {
if typ.Kind != reflect.Slice {
t.Error("expected uint32[2] to have kind slice")
}
- if typ.Type != ubig_ts {
+ if typ.Type != ubig_t {
t.Error("expcted uith32[2] to have type uint64")
}
if typ.Size != 2 {
@@ -202,16 +204,6 @@ func TestTestSlice(t *testing.T) {
t.FailNow()
}
- addr := make([]byte, 20)
- if _, err := abi.Pack("address", addr); err != nil {
- t.Error(err)
- }
-
- addr = make([]byte, 21)
- if _, err := abi.Pack("address", addr); err == nil {
- t.Error("expected address of 21 width to throw")
- }
-
slice := make([]byte, 2)
if _, err := abi.Pack("uint64[2]", slice); err != nil {
t.Error(err)
@@ -222,19 +214,6 @@ func TestTestSlice(t *testing.T) {
}
}
-func TestTestAddress(t *testing.T) {
- abi, err := JSON(strings.NewReader(jsondata2))
- if err != nil {
- t.Error(err)
- t.FailNow()
- }
-
- addr := make([]byte, 20)
- if _, err := abi.Pack("address", addr); err != nil {
- t.Error(err)
- }
-}
-
func TestMethodSignature(t *testing.T) {
String, _ := NewType("string")
String32, _ := NewType("string32")
@@ -310,44 +289,69 @@ func TestPackSlice(t *testing.T) {
}
sig := crypto.Keccak256([]byte("slice(uint32[2])"))[:4]
- sig = append(sig, make([]byte, 64)...)
- sig[35] = 1
- sig[67] = 2
+ sig = append(sig, common.LeftPadBytes([]byte{32}, 32)...)
+ sig = append(sig, common.LeftPadBytes([]byte{2}, 32)...)
+ sig = append(sig, common.LeftPadBytes([]byte{1}, 32)...)
+ sig = append(sig, common.LeftPadBytes([]byte{2}, 32)...)
packed, err := abi.Pack("slice", []uint32{1, 2})
if err != nil {
t.Error(err)
- t.FailNow()
}
if !bytes.Equal(packed, sig) {
t.Errorf("expected %x got %x", sig, packed)
}
-}
-func TestPackSliceBig(t *testing.T) {
- abi, err := JSON(strings.NewReader(jsondata2))
+ var addrA, addrB = common.Address{1}, common.Address{2}
+ sig = abi.Methods["sliceAddress"].Id()
+ sig = append(sig, common.LeftPadBytes([]byte{32}, 32)...)
+ sig = append(sig, common.LeftPadBytes([]byte{2}, 32)...)
+ sig = append(sig, common.LeftPadBytes(addrA[:], 32)...)
+ sig = append(sig, common.LeftPadBytes(addrB[:], 32)...)
+
+ packed, err = abi.Pack("sliceAddress", []common.Address{addrA, addrB})
if err != nil {
- t.Error(err)
- t.FailNow()
+ t.Fatal(err)
+ }
+ if !bytes.Equal(packed, sig) {
+ t.Errorf("expected %x got %x", sig, packed)
}
- sig := crypto.Keccak256([]byte("slice256(uint256[2])"))[:4]
- sig = append(sig, make([]byte, 64)...)
- sig[35] = 1
- sig[67] = 2
+ var addrC, addrD = common.Address{3}, common.Address{4}
+ sig = abi.Methods["sliceMultiAddress"].Id()
+ sig = append(sig, common.LeftPadBytes([]byte{64}, 32)...)
+ sig = append(sig, common.LeftPadBytes([]byte{160}, 32)...)
+ sig = append(sig, common.LeftPadBytes([]byte{2}, 32)...)
+ sig = append(sig, common.LeftPadBytes(addrA[:], 32)...)
+ sig = append(sig, common.LeftPadBytes(addrB[:], 32)...)
+ sig = append(sig, common.LeftPadBytes([]byte{2}, 32)...)
+ sig = append(sig, common.LeftPadBytes(addrC[:], 32)...)
+ sig = append(sig, common.LeftPadBytes(addrD[:], 32)...)
+
+ packed, err = abi.Pack("sliceMultiAddress", []common.Address{addrA, addrB}, []common.Address{addrC, addrD})
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !bytes.Equal(packed, sig) {
+ t.Errorf("expected %x got %x", sig, packed)
+ }
- packed, err := abi.Pack("slice256", []*big.Int{big.NewInt(1), big.NewInt(2)})
+ sig = crypto.Keccak256([]byte("slice256(uint256[2])"))[:4]
+ sig = append(sig, common.LeftPadBytes([]byte{32}, 32)...)
+ sig = append(sig, common.LeftPadBytes([]byte{2}, 32)...)
+ sig = append(sig, common.LeftPadBytes([]byte{1}, 32)...)
+ sig = append(sig, common.LeftPadBytes([]byte{2}, 32)...)
+
+ packed, err = abi.Pack("slice256", []*big.Int{big.NewInt(1), big.NewInt(2)})
if err != nil {
t.Error(err)
- t.FailNow()
}
if !bytes.Equal(packed, sig) {
t.Errorf("expected %x got %x", sig, packed)
}
}
-
func ExampleJSON() {
const definition = `[{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"isBar","outputs":[{"name":"","type":"bool"}],"type":"function"}]`
@@ -370,7 +374,7 @@ func TestInputVariableInputLength(t *testing.T) {
{ "type" : "function", "name" : "strOne", "const" : true, "inputs" : [ { "name" : "str", "type" : "string" } ] },
{ "type" : "function", "name" : "bytesOne", "const" : true, "inputs" : [ { "name" : "str", "type" : "bytes" } ] },
{ "type" : "function", "name" : "strTwo", "const" : true, "inputs" : [ { "name" : "str", "type" : "string" }, { "name" : "str1", "type" : "string" } ] }
-]`
+ ]`
abi, err := JSON(strings.NewReader(definition))
if err != nil {
@@ -493,35 +497,6 @@ func TestInputVariableInputLength(t *testing.T) {
}
}
-func TestBytes(t *testing.T) {
- const definition = `[
- { "type" : "function", "name" : "balance", "const" : true, "inputs" : [ { "name" : "address", "type" : "bytes20" } ] },
- { "type" : "function", "name" : "send", "const" : false, "inputs" : [ { "name" : "amount", "type" : "uint256" } ] }
-]`
-
- abi, err := JSON(strings.NewReader(definition))
- if err != nil {
- t.Fatal(err)
- }
- ok := make([]byte, 20)
- _, err = abi.Pack("balance", ok)
- if err != nil {
- t.Error(err)
- }
-
- toosmall := make([]byte, 19)
- _, err = abi.Pack("balance", toosmall)
- if err != nil {
- t.Error(err)
- }
-
- toobig := make([]byte, 21)
- _, err = abi.Pack("balance", toobig)
- if err == nil {
- t.Error("expected error")
- }
-}
-
func TestDefaultFunctionParsing(t *testing.T) {
const definition = `[{ "name" : "balance" }]`
diff --git a/accounts/abi/numbers.go b/accounts/abi/numbers.go
index 02609d567..084701de5 100644
--- a/accounts/abi/numbers.go
+++ b/accounts/abi/numbers.go
@@ -117,8 +117,6 @@ func packNum(value reflect.Value, to byte) []byte {
// checks whether the given reflect value is signed. This also works for slices with a number type
func isSigned(v reflect.Value) bool {
switch v.Type() {
- case ubig_ts, big_ts, big_t, ubig_t:
- return true
case int_ts, int8_ts, int16_ts, int32_ts, int64_ts, int_t, int8_t, int16_t, int32_t, int64_t:
return true
}
diff --git a/accounts/abi/numbers_test.go b/accounts/abi/numbers_test.go
index 78dc57543..6590e41a6 100644
--- a/accounts/abi/numbers_test.go
+++ b/accounts/abi/numbers_test.go
@@ -81,8 +81,4 @@ func TestSigned(t *testing.T) {
if !isSigned(reflect.ValueOf(int(10))) {
t.Error()
}
-
- if !isSigned(reflect.ValueOf(big.NewInt(10))) {
- t.Error()
- }
}
diff --git a/accounts/abi/type.go b/accounts/abi/type.go
index c08b744f7..18cd04672 100644
--- a/accounts/abi/type.go
+++ b/accounts/abi/type.go
@@ -96,63 +96,57 @@ func NewType(t string) (typ Type, err error) {
t += "256"
}
- if isslice {
+ switch vtype {
+ case "int":
+ typ.Kind = reflect.Ptr
+ typ.Type = big_t
+ typ.Size = 256
+ typ.T = IntTy
+ case "uint":
+ typ.Kind = reflect.Ptr
+ typ.Type = ubig_t
+ typ.Size = 256
+ typ.T = UintTy
+ case "bool":
+ typ.Kind = reflect.Bool
+ typ.T = BoolTy
+ case "real": // TODO
+ typ.Kind = reflect.Invalid
+ case "address":
typ.Kind = reflect.Slice
- typ.Size = size
- switch vtype {
- case "int":
- typ.Type = big_ts
- case "uint":
- typ.Type = ubig_ts
- default:
- return Type{}, fmt.Errorf("unsupported arg slice type: %s", t)
- }
- } else {
- switch vtype {
- case "int":
- typ.Kind = reflect.Ptr
- typ.Type = big_t
- typ.Size = 256
- typ.T = IntTy
- case "uint":
- typ.Kind = reflect.Ptr
- typ.Type = ubig_t
- typ.Size = 256
- typ.T = UintTy
- case "bool":
- typ.Kind = reflect.Bool
- typ.T = BoolTy
- case "real": // TODO
- typ.Kind = reflect.Invalid
- case "address":
- typ.Kind = reflect.Slice
- typ.Type = address_t
- typ.Size = 20
- typ.T = AddressTy
- case "string":
- typ.Kind = reflect.String
- typ.Size = -1
- typ.T = StringTy
- if vsize > 0 {
- typ.Size = 32
- }
- case "hash":
- typ.Kind = reflect.Slice
+ typ.Type = address_t
+ typ.Size = 20
+ typ.T = AddressTy
+ case "string":
+ typ.Kind = reflect.String
+ typ.Size = -1
+ typ.T = StringTy
+ if vsize > 0 {
typ.Size = 32
- typ.Type = hash_t
- typ.T = HashTy
- case "bytes":
- typ.Kind = reflect.Slice
- typ.Type = byte_ts
- typ.Size = vsize
- if vsize == 0 {
- typ.T = BytesTy
- } else {
- typ.T = FixedBytesTy
- }
- default:
- return Type{}, fmt.Errorf("unsupported arg type: %s", t)
}
+ case "hash":
+ typ.Kind = reflect.Slice
+ typ.Size = 32
+ typ.Type = hash_t
+ typ.T = HashTy
+ case "bytes":
+ typ.Kind = reflect.Slice
+ typ.Type = byte_ts
+ typ.Size = vsize
+ if vsize == 0 {
+ typ.T = BytesTy
+ } else {
+ typ.T = FixedBytesTy
+ }
+ default:
+ return Type{}, fmt.Errorf("unsupported arg type: %s", t)
+ }
+
+ // if the type is a slice we must set Kind to a reflect.Slice
+ // so that serialisation can be determined based on this kind.
+ if isslice {
+ typ.Kind = reflect.Slice
+ typ.Size = size
}
typ.stringKind = t
@@ -203,7 +197,7 @@ func (t Type) pack(v interface{}) ([]byte, error) {
return packBytesSlice([]byte(value.String()), value.Len()), nil
case reflect.Slice:
- // if the param is a bytes type, pack the slice up as a string
+ // Byte slice is a special case, it gets treated as a single value
if t.T == BytesTy {
return packBytesSlice(value.Bytes(), value.Len()), nil
}
@@ -212,21 +206,20 @@ func (t Type) pack(v interface{}) ([]byte, error) {
return nil, fmt.Errorf("%v out of bound. %d for %d", value.Kind(), value.Len(), t.Size)
}
- // Address is a special slice. The slice acts as one rather than a list of elements.
- if t.T == AddressTy {
- return common.LeftPadBytes(v.([]byte), 32), nil
- }
-
// Signed / Unsigned check
- if (t.T != IntTy && isSigned(value)) || (t.T == UintTy && isSigned(value)) {
+ if value.Type() == big_t && (t.T != IntTy && isSigned(value)) || (t.T == UintTy && isSigned(value)) {
return nil, fmt.Errorf("slice of incompatible types.")
}
var packed []byte
for i := 0; i < value.Len(); i++ {
- packed = append(packed, packNum(value.Index(i), t.T)...)
+ val, err := t.pack(value.Index(i).Interface())
+ if err != nil {
+ return nil, err
+ }
+ packed = append(packed, val...)
}
- return packed, nil
+ return packBytesSlice(packed, value.Len()), nil
case reflect.Bool:
if value.Bool() {
return common.LeftPadBytes(common.Big1.Bytes(), 32), nil