github.com/aigarnetwork/aigar@v0.0.0-20191115204914-d59a6eb70f8e/accounts/abi/type.go (about)

     1  //  Copyright 2018 The go-ethereum Authors
     2  //  Copyright 2019 The go-aigar Authors
     3  //  This file is part of the go-aigar library.
     4  //
     5  //  The go-aigar library is free software: you can redistribute it and/or modify
     6  //  it under the terms of the GNU Lesser General Public License as published by
     7  //  the Free Software Foundation, either version 3 of the License, or
     8  //  (at your option) any later version.
     9  //
    10  //  The go-aigar library is distributed in the hope that it will be useful,
    11  //  but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    13  //  GNU Lesser General Public License for more details.
    14  //
    15  //  You should have received a copy of the GNU Lesser General Public License
    16  //  along with the go-aigar library. If not, see <http://www.gnu.org/licenses/>.
    17  
    18  package abi
    19  
    20  import (
    21  	"errors"
    22  	"fmt"
    23  	"reflect"
    24  	"regexp"
    25  	"strconv"
    26  	"strings"
    27  )
    28  
    29  // Type enumerator
    30  const (
    31  	IntTy byte = iota
    32  	UintTy
    33  	BoolTy
    34  	StringTy
    35  	SliceTy
    36  	ArrayTy
    37  	TupleTy
    38  	AddressTy
    39  	FixedBytesTy
    40  	BytesTy
    41  	HashTy
    42  	FixedPointTy
    43  	FunctionTy
    44  )
    45  
    46  // Type is the reflection of the supported argument type
    47  type Type struct {
    48  	Elem *Type
    49  	Kind reflect.Kind
    50  	Type reflect.Type
    51  	Size int
    52  	T    byte // Our own type checking
    53  
    54  	stringKind string // holds the unparsed string for deriving signatures
    55  
    56  	// Tuple relative fields
    57  	TupleRawName  string   // Raw struct name defined in source code, may be empty.
    58  	TupleElems    []*Type  // Type information of all tuple fields
    59  	TupleRawNames []string // Raw field name of all tuple fields
    60  }
    61  
    62  var (
    63  	// typeRegex parses the abi sub types
    64  	typeRegex = regexp.MustCompile("([a-zA-Z]+)(([0-9]+)(x([0-9]+))?)?")
    65  )
    66  
    67  // NewType creates a new reflection type of abi type given in t.
    68  func NewType(t string, internalType string, components []ArgumentMarshaling) (typ Type, err error) {
    69  	// check that array brackets are equal if they exist
    70  	if strings.Count(t, "[") != strings.Count(t, "]") {
    71  		return Type{}, fmt.Errorf("invalid arg type in abi")
    72  	}
    73  	typ.stringKind = t
    74  
    75  	// if there are brackets, get ready to go into slice/array mode and
    76  	// recursively create the type
    77  	if strings.Count(t, "[") != 0 {
    78  		// Note internalType can be empty here.
    79  		subInternal := internalType
    80  		if i := strings.LastIndex(internalType, "["); i != -1 {
    81  			subInternal = subInternal[:i]
    82  		}
    83  		// recursively embed the type
    84  		i := strings.LastIndex(t, "[")
    85  		embeddedType, err := NewType(t[:i], subInternal, components)
    86  		if err != nil {
    87  			return Type{}, err
    88  		}
    89  		// grab the last cell and create a type from there
    90  		sliced := t[i:]
    91  		// grab the slice size with regexp
    92  		re := regexp.MustCompile("[0-9]+")
    93  		intz := re.FindAllString(sliced, -1)
    94  
    95  		if len(intz) == 0 {
    96  			// is a slice
    97  			typ.T = SliceTy
    98  			typ.Kind = reflect.Slice
    99  			typ.Elem = &embeddedType
   100  			typ.Type = reflect.SliceOf(embeddedType.Type)
   101  			typ.stringKind = embeddedType.stringKind + sliced
   102  		} else if len(intz) == 1 {
   103  			// is a array
   104  			typ.T = ArrayTy
   105  			typ.Kind = reflect.Array
   106  			typ.Elem = &embeddedType
   107  			typ.Size, err = strconv.Atoi(intz[0])
   108  			if err != nil {
   109  				return Type{}, fmt.Errorf("abi: error parsing variable size: %v", err)
   110  			}
   111  			typ.Type = reflect.ArrayOf(typ.Size, embeddedType.Type)
   112  			typ.stringKind = embeddedType.stringKind + sliced
   113  		} else {
   114  			return Type{}, fmt.Errorf("invalid formatting of array type")
   115  		}
   116  		return typ, err
   117  	}
   118  	// parse the type and size of the abi-type.
   119  	matches := typeRegex.FindAllStringSubmatch(t, -1)
   120  	if len(matches) == 0 {
   121  		return Type{}, fmt.Errorf("invalid type '%v'", t)
   122  	}
   123  	parsedType := matches[0]
   124  
   125  	// varSize is the size of the variable
   126  	var varSize int
   127  	if len(parsedType[3]) > 0 {
   128  		var err error
   129  		varSize, err = strconv.Atoi(parsedType[2])
   130  		if err != nil {
   131  			return Type{}, fmt.Errorf("abi: error parsing variable size: %v", err)
   132  		}
   133  	} else {
   134  		if parsedType[0] == "uint" || parsedType[0] == "int" {
   135  			// this should fail because it means that there's something wrong with
   136  			// the abi type (the compiler should always format it to the size...always)
   137  			return Type{}, fmt.Errorf("unsupported arg type: %s", t)
   138  		}
   139  	}
   140  	// varType is the parsed abi type
   141  	switch varType := parsedType[1]; varType {
   142  	case "int":
   143  		typ.Kind, typ.Type = reflectIntKindAndType(false, varSize)
   144  		typ.Size = varSize
   145  		typ.T = IntTy
   146  	case "uint":
   147  		typ.Kind, typ.Type = reflectIntKindAndType(true, varSize)
   148  		typ.Size = varSize
   149  		typ.T = UintTy
   150  	case "bool":
   151  		typ.Kind = reflect.Bool
   152  		typ.T = BoolTy
   153  		typ.Type = reflect.TypeOf(bool(false))
   154  	case "address":
   155  		typ.Kind = reflect.Array
   156  		typ.Type = addressT
   157  		typ.Size = 20
   158  		typ.T = AddressTy
   159  	case "string":
   160  		typ.Kind = reflect.String
   161  		typ.Type = reflect.TypeOf("")
   162  		typ.T = StringTy
   163  	case "bytes":
   164  		if varSize == 0 {
   165  			typ.T = BytesTy
   166  			typ.Kind = reflect.Slice
   167  			typ.Type = reflect.SliceOf(reflect.TypeOf(byte(0)))
   168  		} else {
   169  			typ.T = FixedBytesTy
   170  			typ.Kind = reflect.Array
   171  			typ.Size = varSize
   172  			typ.Type = reflect.ArrayOf(varSize, reflect.TypeOf(byte(0)))
   173  		}
   174  	case "tuple":
   175  		var (
   176  			fields     []reflect.StructField
   177  			elems      []*Type
   178  			names      []string
   179  			expression string // canonical parameter expression
   180  		)
   181  		expression += "("
   182  		for idx, c := range components {
   183  			cType, err := NewType(c.Type, c.InternalType, c.Components)
   184  			if err != nil {
   185  				return Type{}, err
   186  			}
   187  			if ToCamelCase(c.Name) == "" {
   188  				return Type{}, errors.New("abi: purely anonymous or underscored field is not supported")
   189  			}
   190  			fields = append(fields, reflect.StructField{
   191  				Name: ToCamelCase(c.Name), // reflect.StructOf will panic for any exported field.
   192  				Type: cType.Type,
   193  				Tag:  reflect.StructTag("json:\"" + c.Name + "\""),
   194  			})
   195  			elems = append(elems, &cType)
   196  			names = append(names, c.Name)
   197  			expression += cType.stringKind
   198  			if idx != len(components)-1 {
   199  				expression += ","
   200  			}
   201  		}
   202  		expression += ")"
   203  		typ.Kind = reflect.Struct
   204  		typ.Type = reflect.StructOf(fields)
   205  		typ.TupleElems = elems
   206  		typ.TupleRawNames = names
   207  		typ.T = TupleTy
   208  		typ.stringKind = expression
   209  
   210  		const structPrefix = "struct "
   211  		// After solidity 0.5.10, a new field of abi "internalType"
   212  		// is introduced. From that we can obtain the struct name
   213  		// user defined in the source code.
   214  		if internalType != "" && strings.HasPrefix(internalType, structPrefix) {
   215  			// Foo.Bar type definition is not allowed in golang,
   216  			// convert the format to FooBar
   217  			typ.TupleRawName = strings.Replace(internalType[len(structPrefix):], ".", "", -1)
   218  		}
   219  
   220  	case "function":
   221  		typ.Kind = reflect.Array
   222  		typ.T = FunctionTy
   223  		typ.Size = 24
   224  		typ.Type = reflect.ArrayOf(24, reflect.TypeOf(byte(0)))
   225  	default:
   226  		return Type{}, fmt.Errorf("unsupported arg type: %s", t)
   227  	}
   228  
   229  	return
   230  }
   231  
   232  // String implements Stringer
   233  func (t Type) String() (out string) {
   234  	return t.stringKind
   235  }
   236  
   237  func (t Type) pack(v reflect.Value) ([]byte, error) {
   238  	// dereference pointer first if it's a pointer
   239  	v = indirect(v)
   240  	if err := typeCheck(t, v); err != nil {
   241  		return nil, err
   242  	}
   243  
   244  	switch t.T {
   245  	case SliceTy, ArrayTy:
   246  		var ret []byte
   247  
   248  		if t.requiresLengthPrefix() {
   249  			// append length
   250  			ret = append(ret, packNum(reflect.ValueOf(v.Len()))...)
   251  		}
   252  
   253  		// calculate offset if any
   254  		offset := 0
   255  		offsetReq := isDynamicType(*t.Elem)
   256  		if offsetReq {
   257  			offset = getTypeSize(*t.Elem) * v.Len()
   258  		}
   259  		var tail []byte
   260  		for i := 0; i < v.Len(); i++ {
   261  			val, err := t.Elem.pack(v.Index(i))
   262  			if err != nil {
   263  				return nil, err
   264  			}
   265  			if !offsetReq {
   266  				ret = append(ret, val...)
   267  				continue
   268  			}
   269  			ret = append(ret, packNum(reflect.ValueOf(offset))...)
   270  			offset += len(val)
   271  			tail = append(tail, val...)
   272  		}
   273  		return append(ret, tail...), nil
   274  	case TupleTy:
   275  		// (T1,...,Tk) for k >= 0 and any types T1, …, Tk
   276  		// enc(X) = head(X(1)) ... head(X(k)) tail(X(1)) ... tail(X(k))
   277  		// where X = (X(1), ..., X(k)) and head and tail are defined for Ti being a static
   278  		// type as
   279  		//     head(X(i)) = enc(X(i)) and tail(X(i)) = "" (the empty string)
   280  		// and as
   281  		//     head(X(i)) = enc(len(head(X(1)) ... head(X(k)) tail(X(1)) ... tail(X(i-1))))
   282  		//     tail(X(i)) = enc(X(i))
   283  		// otherwise, i.e. if Ti is a dynamic type.
   284  		fieldmap, err := mapArgNamesToStructFields(t.TupleRawNames, v)
   285  		if err != nil {
   286  			return nil, err
   287  		}
   288  		// Calculate prefix occupied size.
   289  		offset := 0
   290  		for _, elem := range t.TupleElems {
   291  			offset += getTypeSize(*elem)
   292  		}
   293  		var ret, tail []byte
   294  		for i, elem := range t.TupleElems {
   295  			field := v.FieldByName(fieldmap[t.TupleRawNames[i]])
   296  			if !field.IsValid() {
   297  				return nil, fmt.Errorf("field %s for tuple not found in the given struct", t.TupleRawNames[i])
   298  			}
   299  			val, err := elem.pack(field)
   300  			if err != nil {
   301  				return nil, err
   302  			}
   303  			if isDynamicType(*elem) {
   304  				ret = append(ret, packNum(reflect.ValueOf(offset))...)
   305  				tail = append(tail, val...)
   306  				offset += len(val)
   307  			} else {
   308  				ret = append(ret, val...)
   309  			}
   310  		}
   311  		return append(ret, tail...), nil
   312  
   313  	default:
   314  		return packElement(t, v), nil
   315  	}
   316  }
   317  
   318  // requireLengthPrefix returns whether the type requires any sort of length
   319  // prefixing.
   320  func (t Type) requiresLengthPrefix() bool {
   321  	return t.T == StringTy || t.T == BytesTy || t.T == SliceTy
   322  }
   323  
   324  // isDynamicType returns true if the type is dynamic.
   325  // The following types are called “dynamic”:
   326  // * bytes
   327  // * string
   328  // * T[] for any T
   329  // * T[k] for any dynamic T and any k >= 0
   330  // * (T1,...,Tk) if Ti is dynamic for some 1 <= i <= k
   331  func isDynamicType(t Type) bool {
   332  	if t.T == TupleTy {
   333  		for _, elem := range t.TupleElems {
   334  			if isDynamicType(*elem) {
   335  				return true
   336  			}
   337  		}
   338  		return false
   339  	}
   340  	return t.T == StringTy || t.T == BytesTy || t.T == SliceTy || (t.T == ArrayTy && isDynamicType(*t.Elem))
   341  }
   342  
   343  // getTypeSize returns the size that this type needs to occupy.
   344  // We distinguish static and dynamic types. Static types are encoded in-place
   345  // and dynamic types are encoded at a separately allocated location after the
   346  // current block.
   347  // So for a static variable, the size returned represents the size that the
   348  // variable actually occupies.
   349  // For a dynamic variable, the returned size is fixed 32 bytes, which is used
   350  // to store the location reference for actual value storage.
   351  func getTypeSize(t Type) int {
   352  	if t.T == ArrayTy && !isDynamicType(*t.Elem) {
   353  		// Recursively calculate type size if it is a nested array
   354  		if t.Elem.T == ArrayTy {
   355  			return t.Size * getTypeSize(*t.Elem)
   356  		}
   357  		return t.Size * 32
   358  	} else if t.T == TupleTy && !isDynamicType(t) {
   359  		total := 0
   360  		for _, elem := range t.TupleElems {
   361  			total += getTypeSize(*elem)
   362  		}
   363  		return total
   364  	}
   365  	return 32
   366  }