mirror of https://github.com/status-im/op-geth.git
abi: removed implicit type casting & refactored type parsing
This commit is contained in:
parent
968d8ffe94
commit
a306e17a26
|
@ -186,7 +186,7 @@ func toGoSlice(i int, t Argument, output []byte) (interface{}, error) {
|
||||||
// argument in T.
|
// argument in T.
|
||||||
func toGoType(i int, t Argument, output []byte) (interface{}, error) {
|
func toGoType(i int, t Argument, output []byte) (interface{}, error) {
|
||||||
// we need to treat slices differently
|
// we need to treat slices differently
|
||||||
if t.Type.Kind == reflect.Slice {
|
if t.Type.IsSlice {
|
||||||
return toGoSlice(i, t, output)
|
return toGoSlice(i, t, output)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -59,7 +59,7 @@ func TestType(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
if typ.Kind != reflect.Ptr {
|
if typ.Kind != reflect.Uint {
|
||||||
t.Error("expected uint32 to have kind Ptr")
|
t.Error("expected uint32 to have kind Ptr")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,8 +67,8 @@ func TestType(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
if typ.Kind != reflect.Slice {
|
if !typ.IsSlice {
|
||||||
t.Error("expected uint32[] to have type slice")
|
t.Error("expected uint32[] to be slice")
|
||||||
}
|
}
|
||||||
if typ.Type != ubig_t {
|
if typ.Type != ubig_t {
|
||||||
t.Error("expcted uith32[] to have type uint64")
|
t.Error("expcted uith32[] to have type uint64")
|
||||||
|
@ -78,13 +78,13 @@ func TestType(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
if typ.Kind != reflect.Slice {
|
if !typ.IsSlice {
|
||||||
t.Error("expected uint32[2] to have kind slice")
|
t.Error("expected uint32[2] to be slice")
|
||||||
}
|
}
|
||||||
if typ.Type != ubig_t {
|
if typ.Type != ubig_t {
|
||||||
t.Error("expcted uith32[2] to have type uint64")
|
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")
|
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")
|
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 {
|
if _, err := abi.Pack("test", uint32(1000)); err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
@ -204,7 +200,7 @@ func TestTestSlice(t *testing.T) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
|
|
||||||
slice := make([]byte, 2)
|
slice := make([]uint64, 2)
|
||||||
if _, err := abi.Pack("uint64[2]", slice); err != nil {
|
if _, err := abi.Pack("uint64[2]", slice); err != nil {
|
||||||
t.Error(err)
|
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) {
|
func TestMethodSignature(t *testing.T) {
|
||||||
String, _ := NewType("string")
|
String, _ := NewType("string")
|
||||||
String32, _ := NewType("string32")
|
String32, _ := NewType("string32")
|
||||||
|
|
|
@ -40,6 +40,9 @@ const (
|
||||||
|
|
||||||
// Type is the reflection of the supported argument type
|
// Type is the reflection of the supported argument type
|
||||||
type Type struct {
|
type Type struct {
|
||||||
|
IsSlice bool
|
||||||
|
SliceSize int
|
||||||
|
|
||||||
Kind reflect.Kind
|
Kind reflect.Kind
|
||||||
Type reflect.Type
|
Type reflect.Type
|
||||||
Size int
|
Size int
|
||||||
|
@ -47,6 +50,11 @@ type Type struct {
|
||||||
stringKind string // holds the unparsed string for deriving signatures
|
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.
|
// 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:
|
// Strings can be in the format of:
|
||||||
|
@ -61,51 +69,54 @@ type Type struct {
|
||||||
// address int256 uint256 real[2]
|
// address int256 uint256 real[2]
|
||||||
func NewType(t string) (typ Type, err error) {
|
func NewType(t string) (typ Type, err error) {
|
||||||
// 1. full string 2. type 3. (opt.) is slice 4. (opt.) size
|
// 1. full string 2. type 3. (opt.) is slice 4. (opt.) size
|
||||||
freg, err := regexp.Compile("([a-zA-Z0-9]+)(\\[([0-9]*)?\\])?")
|
// parse the full representation of the abi-type definition; including:
|
||||||
if err != nil {
|
// * full string
|
||||||
return Type{}, err
|
// * type
|
||||||
}
|
// * is slice
|
||||||
res := freg.FindAllStringSubmatch(t, -1)[0]
|
// * slice size
|
||||||
var (
|
res := fullTypeRegex.FindAllStringSubmatch(t, -1)[0]
|
||||||
isslice bool
|
|
||||||
size int
|
// check if type is slice and parse type.
|
||||||
)
|
|
||||||
switch {
|
switch {
|
||||||
case res[3] != "":
|
case res[3] != "":
|
||||||
// err is ignored. Already checked for number through the regexp
|
// err is ignored. Already checked for number through the regexp
|
||||||
size, _ = strconv.Atoi(res[3])
|
typ.SliceSize, _ = strconv.Atoi(res[3])
|
||||||
isslice = true
|
typ.IsSlice = true
|
||||||
case res[2] != "":
|
case res[2] != "":
|
||||||
isslice = true
|
typ.IsSlice, typ.SliceSize = true, -1
|
||||||
size = -1
|
|
||||||
case res[0] == "":
|
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]*)?")
|
// parse the type and size of the abi-type.
|
||||||
if err != nil {
|
parsedType := typeRegex.FindAllStringSubmatch(res[1], -1)[0]
|
||||||
return Type{}, err
|
// 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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
// varType is the parsed abi type
|
||||||
parsedType := treg.FindAllStringSubmatch(res[1], -1)[0]
|
varType := parsedType[1]
|
||||||
vsize, _ := strconv.Atoi(parsedType[2])
|
// substitute canonical integer
|
||||||
vtype := parsedType[1]
|
if varSize == 0 && (varType == "int" || varType == "uint") {
|
||||||
// substitute canonical representation
|
varSize = 256
|
||||||
if vsize == 0 && (vtype == "int" || vtype == "uint") {
|
|
||||||
vsize = 256
|
|
||||||
t += "256"
|
t += "256"
|
||||||
}
|
}
|
||||||
|
|
||||||
switch vtype {
|
switch varType {
|
||||||
case "int":
|
case "int":
|
||||||
typ.Kind = reflect.Ptr
|
typ.Kind = reflect.Int
|
||||||
typ.Type = big_t
|
typ.Type = big_t
|
||||||
typ.Size = 256
|
typ.Size = varSize
|
||||||
typ.T = IntTy
|
typ.T = IntTy
|
||||||
case "uint":
|
case "uint":
|
||||||
typ.Kind = reflect.Ptr
|
typ.Kind = reflect.Uint
|
||||||
typ.Type = ubig_t
|
typ.Type = ubig_t
|
||||||
typ.Size = 256
|
typ.Size = varSize
|
||||||
typ.T = UintTy
|
typ.T = UintTy
|
||||||
case "bool":
|
case "bool":
|
||||||
typ.Kind = reflect.Bool
|
typ.Kind = reflect.Bool
|
||||||
|
@ -120,7 +131,7 @@ func NewType(t string) (typ Type, err error) {
|
||||||
typ.Kind = reflect.String
|
typ.Kind = reflect.String
|
||||||
typ.Size = -1
|
typ.Size = -1
|
||||||
typ.T = StringTy
|
typ.T = StringTy
|
||||||
if vsize > 0 {
|
if varSize > 0 {
|
||||||
typ.Size = 32
|
typ.Size = 32
|
||||||
}
|
}
|
||||||
case "hash":
|
case "hash":
|
||||||
|
@ -131,8 +142,8 @@ func NewType(t string) (typ Type, err error) {
|
||||||
case "bytes":
|
case "bytes":
|
||||||
typ.Kind = reflect.Array
|
typ.Kind = reflect.Array
|
||||||
typ.Type = byte_ts
|
typ.Type = byte_ts
|
||||||
typ.Size = vsize
|
typ.Size = varSize
|
||||||
if vsize == 0 {
|
if varSize == 0 {
|
||||||
typ.T = BytesTy
|
typ.T = BytesTy
|
||||||
} else {
|
} else {
|
||||||
typ.T = FixedBytesTy
|
typ.T = FixedBytesTy
|
||||||
|
@ -140,13 +151,6 @@ func NewType(t string) (typ Type, err error) {
|
||||||
default:
|
default:
|
||||||
return Type{}, fmt.Errorf("unsupported arg type: %s", t)
|
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
|
typ.stringKind = t
|
||||||
|
|
||||||
return
|
return
|
||||||
|
@ -173,14 +177,26 @@ func (t Type) pack(v interface{}) ([]byte, error) {
|
||||||
value := reflect.ValueOf(v)
|
value := reflect.ValueOf(v)
|
||||||
switch kind := value.Kind(); kind {
|
switch kind := value.Kind(); kind {
|
||||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||||
|
// check input is unsigned
|
||||||
if t.Type != ubig_t {
|
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
|
return packNum(value, t.T), nil
|
||||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||||
if t.Type != ubig_t {
|
if t.Type != ubig_t {
|
||||||
return nil, fmt.Errorf("type mismatch: %s for %T", t.Type, v)
|
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
|
return packNum(value, t.T), nil
|
||||||
case reflect.Ptr:
|
case reflect.Ptr:
|
||||||
// If the value is a ptr do a assign check (only used by
|
// 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
|
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)
|
return nil, fmt.Errorf("%v out of bound. %d for %d", value.Kind(), value.Len(), t.Size)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue