aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeffrey Wilcke <geffobscura@gmail.com>2016-04-01 05:54:47 +0800
committerJeffrey Wilcke <geffobscura@gmail.com>2016-04-05 02:30:59 +0800
commita306e17a26e96e383afe86a2f1cdfa2320ec0f2f (patch)
treee594fab043b0936864b6578f2d1db2239a75ace3
parent968d8ffe942f6ef3776b43a73fb0fe85eb955a68 (diff)
downloaddexon-a306e17a26e96e383afe86a2f1cdfa2320ec0f2f.tar
dexon-a306e17a26e96e383afe86a2f1cdfa2320ec0f2f.tar.gz
dexon-a306e17a26e96e383afe86a2f1cdfa2320ec0f2f.tar.bz2
dexon-a306e17a26e96e383afe86a2f1cdfa2320ec0f2f.tar.lz
dexon-a306e17a26e96e383afe86a2f1cdfa2320ec0f2f.tar.xz
dexon-a306e17a26e96e383afe86a2f1cdfa2320ec0f2f.tar.zst
dexon-a306e17a26e96e383afe86a2f1cdfa2320ec0f2f.zip
abi: removed implicit type casting & refactored type parsing
-rw-r--r--accounts/abi/abi.go2
-rw-r--r--accounts/abi/abi_test.go33
-rw-r--r--accounts/abi/type.go98
3 files changed, 80 insertions, 53 deletions
diff --git a/accounts/abi/abi.go b/accounts/abi/abi.go
index b0765e7db..9ef7c0f0d 100644
--- a/accounts/abi/abi.go
+++ b/accounts/abi/abi.go
@@ -186,7 +186,7 @@ func toGoSlice(i int, t Argument, output []byte) (interface{}, error) {
// argument in T.
func toGoType(i int, t Argument, output []byte) (interface{}, error) {
// we need to treat slices differently
- if t.Type.Kind == reflect.Slice {
+ if t.Type.IsSlice {
return toGoSlice(i, t, output)
}
diff --git a/accounts/abi/abi_test.go b/accounts/abi/abi_test.go
index a0f0d1034..a1b3e62d9 100644
--- a/accounts/abi/abi_test.go
+++ b/accounts/abi/abi_test.go
@@ -59,7 +59,7 @@ func TestType(t *testing.T) {
if err != nil {
t.Error(err)
}
- if typ.Kind != reflect.Ptr {
+ if typ.Kind != reflect.Uint {
t.Error("expected uint32 to have kind Ptr")
}
@@ -67,8 +67,8 @@ func TestType(t *testing.T) {
if err != nil {
t.Error(err)
}
- if typ.Kind != reflect.Slice {
- t.Error("expected uint32[] to have type slice")
+ if !typ.IsSlice {
+ t.Error("expected uint32[] to be slice")
}
if typ.Type != ubig_t {
t.Error("expcted uith32[] to have type uint64")
@@ -78,13 +78,13 @@ func TestType(t *testing.T) {
if err != nil {
t.Error(err)
}
- if typ.Kind != reflect.Slice {
- t.Error("expected uint32[2] to have kind slice")
+ if !typ.IsSlice {
+ t.Error("expected uint32[2] to be slice")
}
if typ.Type != ubig_t {
t.Error("expcted uith32[2] to have type uint64")
}
- if typ.Size != 2 {
+ if typ.SliceSize != 2 {
t.Error("expected uint32[2] to have a size of 2")
}
}
@@ -149,10 +149,6 @@ func TestTestNumbers(t *testing.T) {
t.Errorf("expected send( ptr ) to throw, requires *big.Int instead of *int")
}
- if _, err := abi.Pack("send", 1000); err != nil {
- t.Error("expected send(1000) to cast to big")
- }
-
if _, err := abi.Pack("test", uint32(1000)); err != nil {
t.Error(err)
}
@@ -204,7 +200,7 @@ func TestTestSlice(t *testing.T) {
t.FailNow()
}
- slice := make([]byte, 2)
+ slice := make([]uint64, 2)
if _, err := abi.Pack("uint64[2]", slice); err != nil {
t.Error(err)
}
@@ -214,6 +210,21 @@ func TestTestSlice(t *testing.T) {
}
}
+func TestImplicitTypeCasts(t *testing.T) {
+ abi, err := JSON(strings.NewReader(jsondata2))
+ if err != nil {
+ t.Error(err)
+ t.FailNow()
+ }
+
+ slice := make([]uint8, 2)
+ _, err = abi.Pack("uint64[2]", slice)
+ expStr := "`uint64[2]` abi: cannot use type uint8 as type uint64"
+ if err.Error() != expStr {
+ t.Errorf("expected %v, got %v", expStr, err)
+ }
+}
+
func TestMethodSignature(t *testing.T) {
String, _ := NewType("string")
String32, _ := NewType("string32")
diff --git a/accounts/abi/type.go b/accounts/abi/type.go
index b7ce6a13b..5a5a5ac49 100644
--- a/accounts/abi/type.go
+++ b/accounts/abi/type.go
@@ -40,6 +40,9 @@ const (
// Type is the reflection of the supported argument type
type Type struct {
+ IsSlice bool
+ SliceSize int
+
Kind reflect.Kind
Type reflect.Type
Size int
@@ -47,6 +50,11 @@ type Type struct {
stringKind string // holds the unparsed string for deriving signatures
}
+var (
+ fullTypeRegex = regexp.MustCompile("([a-zA-Z0-9]+)(\\[([0-9]*)?\\])?")
+ typeRegex = regexp.MustCompile("([a-zA-Z]+)([0-9]*)?")
+)
+
// NewType returns a fully parsed Type given by the input string or an error if it can't be parsed.
//
// Strings can be in the format of:
@@ -61,51 +69,54 @@ type Type struct {
// address int256 uint256 real[2]
func NewType(t string) (typ Type, err error) {
// 1. full string 2. type 3. (opt.) is slice 4. (opt.) size
- freg, err := regexp.Compile("([a-zA-Z0-9]+)(\\[([0-9]*)?\\])?")
- if err != nil {
- return Type{}, err
- }
- res := freg.FindAllStringSubmatch(t, -1)[0]
- var (
- isslice bool
- size int
- )
+ // parse the full representation of the abi-type definition; including:
+ // * full string
+ // * type
+ // * is slice
+ // * slice size
+ res := fullTypeRegex.FindAllStringSubmatch(t, -1)[0]
+
+ // check if type is slice and parse type.
switch {
case res[3] != "":
// err is ignored. Already checked for number through the regexp
- size, _ = strconv.Atoi(res[3])
- isslice = true
+ typ.SliceSize, _ = strconv.Atoi(res[3])
+ typ.IsSlice = true
case res[2] != "":
- isslice = true
- size = -1
+ typ.IsSlice, typ.SliceSize = true, -1
case res[0] == "":
- return Type{}, fmt.Errorf("type parse error for `%s`", t)
+ return Type{}, fmt.Errorf("abi: type parse error: %s", t)
}
- treg, err := regexp.Compile("([a-zA-Z]+)([0-9]*)?")
- if err != nil {
- return Type{}, err
+ // parse the type and size of the abi-type.
+ parsedType := typeRegex.FindAllStringSubmatch(res[1], -1)[0]
+ // varSize is the size of the variable
+ var varSize int
+ if len(parsedType[2]) > 0 {
+ var err error
+ varSize, err = strconv.Atoi(parsedType[2])
+ if err != nil {
+ return Type{}, fmt.Errorf("abi: error parsing variable size: %v", err)
+ }
}
-
- parsedType := treg.FindAllStringSubmatch(res[1], -1)[0]
- vsize, _ := strconv.Atoi(parsedType[2])
- vtype := parsedType[1]
- // substitute canonical representation
- if vsize == 0 && (vtype == "int" || vtype == "uint") {
- vsize = 256
+ // varType is the parsed abi type
+ varType := parsedType[1]
+ // substitute canonical integer
+ if varSize == 0 && (varType == "int" || varType == "uint") {
+ varSize = 256
t += "256"
}
- switch vtype {
+ switch varType {
case "int":
- typ.Kind = reflect.Ptr
+ typ.Kind = reflect.Int
typ.Type = big_t
- typ.Size = 256
+ typ.Size = varSize
typ.T = IntTy
case "uint":
- typ.Kind = reflect.Ptr
+ typ.Kind = reflect.Uint
typ.Type = ubig_t
- typ.Size = 256
+ typ.Size = varSize
typ.T = UintTy
case "bool":
typ.Kind = reflect.Bool
@@ -120,7 +131,7 @@ func NewType(t string) (typ Type, err error) {
typ.Kind = reflect.String
typ.Size = -1
typ.T = StringTy
- if vsize > 0 {
+ if varSize > 0 {
typ.Size = 32
}
case "hash":
@@ -131,8 +142,8 @@ func NewType(t string) (typ Type, err error) {
case "bytes":
typ.Kind = reflect.Array
typ.Type = byte_ts
- typ.Size = vsize
- if vsize == 0 {
+ typ.Size = varSize
+ if varSize == 0 {
typ.T = BytesTy
} else {
typ.T = FixedBytesTy
@@ -140,13 +151,6 @@ func NewType(t string) (typ Type, err error) {
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
return
@@ -173,14 +177,26 @@ func (t Type) pack(v interface{}) ([]byte, error) {
value := reflect.ValueOf(v)
switch kind := value.Kind(); kind {
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+ // check input is unsigned
if t.Type != ubig_t {
- return nil, fmt.Errorf("type mismatch: %s for %T", t.Type, v)
+ return nil, fmt.Errorf("abi: type mismatch: %s for %T", t.Type, v)
+ }
+
+ // no implicit type casting
+ if int(value.Type().Size()*8) != t.Size {
+ return nil, fmt.Errorf("abi: cannot use type %T as type uint%d", v, t.Size)
}
+
return packNum(value, t.T), nil
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
if t.Type != ubig_t {
return nil, fmt.Errorf("type mismatch: %s for %T", t.Type, v)
}
+
+ // no implicit type casting
+ if int(value.Type().Size()*8) != t.Size {
+ return nil, fmt.Errorf("abi: cannot use type %T as type uint%d", v, t.Size)
+ }
return packNum(value, t.T), nil
case reflect.Ptr:
// If the value is a ptr do a assign check (only used by
@@ -201,7 +217,7 @@ func (t Type) pack(v interface{}) ([]byte, error) {
return packBytesSlice(value.Bytes(), value.Len()), nil
}
- if t.Size > -1 && value.Len() > t.Size {
+ if t.SliceSize > -1 && value.Len() > t.SliceSize {
return nil, fmt.Errorf("%v out of bound. %d for %d", value.Kind(), value.Len(), t.Size)
}