|
|
|
@ -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) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|