123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205 |
- // Copyright 2015 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 (
- "fmt"
- "reflect"
- "regexp"
- "strconv"
- "strings"
- )
- // Type enumerator
- const (
- IntTy byte = iota
- UintTy
- BoolTy
- StringTy
- SliceTy
- ArrayTy
- AddressTy
- FixedBytesTy
- BytesTy
- HashTy
- FixedPointTy
- FunctionTy
- )
- // Type is the reflection of the supported argument type
- type Type struct {
- Elem *Type
- Kind reflect.Kind
- Type reflect.Type
- Size int
- T byte // Our own type checking
- stringKind string // holds the unparsed string for deriving signatures
- }
- var (
- // typeRegex parses the abi sub types
- typeRegex = regexp.MustCompile("([a-zA-Z]+)(([0-9]+)(x([0-9]+))?)?")
- )
- // NewType creates a new reflection type of abi type given in t.
- func NewType(t string) (typ Type, err error) {
- // check that array brackets are equal if they exist
- if strings.Count(t, "[") != strings.Count(t, "]") {
- return Type{}, fmt.Errorf("invalid arg type in abi")
- }
- typ.stringKind = t
- // if there are brackets, get ready to go into slice/array mode and
- // recursively create the type
- if strings.Count(t, "[") != 0 {
- i := strings.LastIndex(t, "[")
- // recursively embed the type
- embeddedType, err := NewType(t[:i])
- if err != nil {
- return Type{}, err
- }
- // grab the last cell and create a type from there
- sliced := t[i:]
- // grab the slice size with regexp
- re := regexp.MustCompile("[0-9]+")
- intz := re.FindAllString(sliced, -1)
- if len(intz) == 0 {
- // is a slice
- typ.T = SliceTy
- typ.Kind = reflect.Slice
- typ.Elem = &embeddedType
- typ.Type = reflect.SliceOf(embeddedType.Type)
- } else if len(intz) == 1 {
- // is a array
- typ.T = ArrayTy
- typ.Kind = reflect.Array
- typ.Elem = &embeddedType
- typ.Size, err = strconv.Atoi(intz[0])
- if err != nil {
- return Type{}, fmt.Errorf("abi: error parsing variable size: %v", err)
- }
- typ.Type = reflect.ArrayOf(typ.Size, embeddedType.Type)
- } else {
- return Type{}, fmt.Errorf("invalid formatting of array type")
- }
- return typ, err
- }
- // parse the type and size of the abi-type.
- parsedType := typeRegex.FindAllStringSubmatch(t, -1)[0]
- // varSize is the size of the variable
- var varSize int
- if len(parsedType[3]) > 0 {
- var err error
- varSize, err = strconv.Atoi(parsedType[2])
- if err != nil {
- return Type{}, fmt.Errorf("abi: error parsing variable size: %v", err)
- }
- } else {
- if parsedType[0] == "uint" || parsedType[0] == "int" {
- // this should fail because it means that there's something wrong with
- // the abi type (the compiler should always format it to the size...always)
- return Type{}, fmt.Errorf("unsupported arg type: %s", t)
- }
- }
- // varType is the parsed abi type
- switch varType := parsedType[1]; varType {
- case "int":
- typ.Kind, typ.Type = reflectIntKindAndType(false, varSize)
- typ.Size = varSize
- typ.T = IntTy
- case "uint":
- typ.Kind, typ.Type = reflectIntKindAndType(true, varSize)
- typ.Size = varSize
- typ.T = UintTy
- case "bool":
- typ.Kind = reflect.Bool
- typ.T = BoolTy
- typ.Type = reflect.TypeOf(bool(false))
- case "address":
- typ.Kind = reflect.Array
- typ.Type = addressT
- typ.Size = 20
- typ.T = AddressTy
- case "string":
- typ.Kind = reflect.String
- typ.Type = reflect.TypeOf("")
- typ.T = StringTy
- case "bytes":
- if varSize == 0 {
- typ.T = BytesTy
- typ.Kind = reflect.Slice
- typ.Type = reflect.SliceOf(reflect.TypeOf(byte(0)))
- } else {
- typ.T = FixedBytesTy
- typ.Kind = reflect.Array
- typ.Size = varSize
- typ.Type = reflect.ArrayOf(varSize, reflect.TypeOf(byte(0)))
- }
- case "function":
- typ.Kind = reflect.Array
- typ.T = FunctionTy
- typ.Size = 24
- typ.Type = reflect.ArrayOf(24, reflect.TypeOf(byte(0)))
- default:
- return Type{}, fmt.Errorf("unsupported arg type: %s", t)
- }
- return
- }
- // String implements Stringer
- func (t Type) String() (out string) {
- return t.stringKind
- }
- func (t Type) pack(v reflect.Value) ([]byte, error) {
- // dereference pointer first if it's a pointer
- v = indirect(v)
- if err := typeCheck(t, v); err != nil {
- return nil, err
- }
- if t.T == SliceTy || t.T == ArrayTy {
- var packed []byte
- for i := 0; i < v.Len(); i++ {
- val, err := t.Elem.pack(v.Index(i))
- if err != nil {
- return nil, err
- }
- packed = append(packed, val...)
- }
- if t.T == SliceTy {
- return packBytesSlice(packed, v.Len()), nil
- } else if t.T == ArrayTy {
- return packed, nil
- }
- }
- return packElement(t, v), nil
- }
- // requireLengthPrefix returns whether the type requires any sort of length
- // prefixing.
- func (t Type) requiresLengthPrefix() bool {
- return t.T == StringTy || t.T == BytesTy || t.T == SliceTy
- }
|