github.com/insight-chain/inb-go@v1.1.3-0.20191221022159-da049980ae38/accounts/abi/type.go (about)

     1  // Copyright 2015 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package abi
    18  
    19  import (
    20  	"fmt"
    21  	"reflect"
    22  	"regexp"
    23  	"strconv"
    24  	"strings"
    25  )
    26  
    27  // Type enumerator
    28  const (
    29  	IntTy byte = iota
    30  	UintTy
    31  	BoolTy
    32  	StringTy
    33  	SliceTy
    34  	ArrayTy
    35  	AddressTy
    36  	FixedBytesTy
    37  	BytesTy
    38  	HashTy
    39  	FixedPointTy
    40  	FunctionTy
    41  )
    42  
    43  // Type is the reflection of the supported argument type
    44  type Type struct {
    45  	Elem *Type
    46  
    47  	Kind reflect.Kind
    48  	Type reflect.Type
    49  	Size int
    50  	T    byte // Our own type checking
    51  
    52  	stringKind string // holds the unparsed string for deriving signatures
    53  }
    54  
    55  var (
    56  	// typeRegex parses the abi sub types
    57  	typeRegex = regexp.MustCompile("([a-zA-Z]+)(([0-9]+)(x([0-9]+))?)?")
    58  )
    59  
    60  // NewType creates a new reflection type of abi type given in t.
    61  func NewType(t string) (typ Type, err error) {
    62  	// check that array brackets are equal if they exist
    63  	if strings.Count(t, "[") != strings.Count(t, "]") {
    64  		return Type{}, fmt.Errorf("invalid arg type in abi")
    65  	}
    66  
    67  	typ.stringKind = t
    68  
    69  	// if there are brackets, get ready to go into slice/array mode and
    70  	// recursively create the type
    71  	if strings.Count(t, "[") != 0 {
    72  		i := strings.LastIndex(t, "[")
    73  		// recursively embed the type
    74  		embeddedType, err := NewType(t[:i])
    75  		if err != nil {
    76  			return Type{}, err
    77  		}
    78  		// grab the last cell and create a type from there
    79  		sliced := t[i:]
    80  		// grab the slice size with regexp
    81  		re := regexp.MustCompile("[0-9]+")
    82  		intz := re.FindAllString(sliced, -1)
    83  
    84  		if len(intz) == 0 {
    85  			// is a slice
    86  			typ.T = SliceTy
    87  			typ.Kind = reflect.Slice
    88  			typ.Elem = &embeddedType
    89  			typ.Type = reflect.SliceOf(embeddedType.Type)
    90  		} else if len(intz) == 1 {
    91  			// is a array
    92  			typ.T = ArrayTy
    93  			typ.Kind = reflect.Array
    94  			typ.Elem = &embeddedType
    95  			typ.Size, err = strconv.Atoi(intz[0])
    96  			if err != nil {
    97  				return Type{}, fmt.Errorf("abi: error parsing variable size: %v", err)
    98  			}
    99  			typ.Type = reflect.ArrayOf(typ.Size, embeddedType.Type)
   100  		} else {
   101  			return Type{}, fmt.Errorf("invalid formatting of array type")
   102  		}
   103  		return typ, err
   104  	}
   105  	// parse the type and size of the abi-type.
   106  	matches := typeRegex.FindAllStringSubmatch(t, -1)
   107  	if len(matches) == 0 {
   108  		return Type{}, fmt.Errorf("invalid type '%v'", t)
   109  	}
   110  	parsedType := matches[0]
   111  
   112  	// varSize is the size of the variable
   113  	var varSize int
   114  	if len(parsedType[3]) > 0 {
   115  		var err error
   116  		varSize, err = strconv.Atoi(parsedType[2])
   117  		if err != nil {
   118  			return Type{}, fmt.Errorf("abi: error parsing variable size: %v", err)
   119  		}
   120  	} else {
   121  		if parsedType[0] == "uint" || parsedType[0] == "int" {
   122  			// this should fail because it means that there's something wrong with
   123  			// the abi type (the compiler should always format it to the size...always)
   124  			return Type{}, fmt.Errorf("unsupported arg type: %s", t)
   125  		}
   126  	}
   127  	// varType is the parsed abi type
   128  	switch varType := parsedType[1]; varType {
   129  	case "int":
   130  		typ.Kind, typ.Type = reflectIntKindAndType(false, varSize)
   131  		typ.Size = varSize
   132  		typ.T = IntTy
   133  	case "uint":
   134  		typ.Kind, typ.Type = reflectIntKindAndType(true, varSize)
   135  		typ.Size = varSize
   136  		typ.T = UintTy
   137  	case "bool":
   138  		typ.Kind = reflect.Bool
   139  		typ.T = BoolTy
   140  		typ.Type = reflect.TypeOf(bool(false))
   141  	case "address":
   142  		typ.Kind = reflect.Array
   143  		typ.Type = addressT
   144  		typ.Size = 20
   145  		typ.T = AddressTy
   146  	case "string":
   147  		typ.Kind = reflect.String
   148  		typ.Type = reflect.TypeOf("")
   149  		typ.T = StringTy
   150  	case "bytes":
   151  		if varSize == 0 {
   152  			typ.T = BytesTy
   153  			typ.Kind = reflect.Slice
   154  			typ.Type = reflect.SliceOf(reflect.TypeOf(byte(0)))
   155  		} else {
   156  			typ.T = FixedBytesTy
   157  			typ.Kind = reflect.Array
   158  			typ.Size = varSize
   159  			typ.Type = reflect.ArrayOf(varSize, reflect.TypeOf(byte(0)))
   160  		}
   161  	case "function":
   162  		typ.Kind = reflect.Array
   163  		typ.T = FunctionTy
   164  		typ.Size = 24
   165  		typ.Type = reflect.ArrayOf(24, reflect.TypeOf(byte(0)))
   166  	default:
   167  		return Type{}, fmt.Errorf("unsupported arg type: %s", t)
   168  	}
   169  
   170  	return
   171  }
   172  
   173  // String implements Stringer
   174  func (t Type) String() (out string) {
   175  	return t.stringKind
   176  }
   177  
   178  func (t Type) pack(v reflect.Value) ([]byte, error) {
   179  	// dereference pointer first if it's a pointer
   180  	v = indirect(v)
   181  
   182  	if err := typeCheck(t, v); err != nil {
   183  		return nil, err
   184  	}
   185  
   186  	switch t.T {
   187  	case SliceTy, ArrayTy:
   188  		var ret []byte
   189  
   190  		if t.requiresLengthPrefix() {
   191  			// append length
   192  			ret = append(ret, packNum(reflect.ValueOf(v.Len()))...)
   193  		}
   194  
   195  		// calculate offset if any
   196  		offset := 0
   197  		offsetReq := isDynamicType(*t.Elem)
   198  		if offsetReq {
   199  			offset = getDynamicTypeOffset(*t.Elem) * v.Len()
   200  		}
   201  		var tail []byte
   202  		for i := 0; i < v.Len(); i++ {
   203  			val, err := t.Elem.pack(v.Index(i))
   204  			if err != nil {
   205  				return nil, err
   206  			}
   207  			if !offsetReq {
   208  				ret = append(ret, val...)
   209  				continue
   210  			}
   211  			ret = append(ret, packNum(reflect.ValueOf(offset))...)
   212  			offset += len(val)
   213  			tail = append(tail, val...)
   214  		}
   215  		return append(ret, tail...), nil
   216  	default:
   217  		return packElement(t, v), nil
   218  	}
   219  }
   220  
   221  // requireLengthPrefix returns whether the type requires any sort of length
   222  // prefixing.
   223  func (t Type) requiresLengthPrefix() bool {
   224  	return t.T == StringTy || t.T == BytesTy || t.T == SliceTy
   225  }
   226  
   227  // isDynamicType returns true if the type is dynamic.
   228  // StringTy, BytesTy, and SliceTy(irrespective of slice element type) are dynamic types
   229  // ArrayTy is considered dynamic if and only if the Array element is a dynamic type.
   230  // This function recursively checks the type for slice and array elements.
   231  func isDynamicType(t Type) bool {
   232  	// dynamic types
   233  	// array is also a dynamic type if the array type is dynamic
   234  	return t.T == StringTy || t.T == BytesTy || t.T == SliceTy || (t.T == ArrayTy && isDynamicType(*t.Elem))
   235  }
   236  
   237  // getDynamicTypeOffset returns the offset for the type.
   238  // See `isDynamicType` to know which types are considered dynamic.
   239  // If the type t is an array and element type is not a dynamic type, then we consider it a static type and
   240  // return 32 * size of array since length prefix is not required.
   241  // If t is a dynamic type or element type(for slices and arrays) is dynamic, then we simply return 32 as offset.
   242  func getDynamicTypeOffset(t Type) int {
   243  	// if it is an array and there are no dynamic types
   244  	// then the array is static type
   245  	if t.T == ArrayTy && !isDynamicType(*t.Elem) {
   246  		return 32 * t.Size
   247  	}
   248  	return 32
   249  }