github.com/tuotoo/go-ethereum@v1.7.4-0.20171121184211-049797d40a24/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  const (
    28  	IntTy byte = iota
    29  	UintTy
    30  	BoolTy
    31  	StringTy
    32  	SliceTy
    33  	ArrayTy
    34  	AddressTy
    35  	FixedBytesTy
    36  	BytesTy
    37  	HashTy
    38  	FixedPointTy
    39  	FunctionTy
    40  )
    41  
    42  // Type is the reflection of the supported argument type
    43  type Type struct {
    44  	Elem *Type
    45  
    46  	Kind reflect.Kind
    47  	Type reflect.Type
    48  	Size int
    49  	T    byte // Our own type checking
    50  
    51  	stringKind string // holds the unparsed string for deriving signatures
    52  }
    53  
    54  var (
    55  	// typeRegex parses the abi sub types
    56  	typeRegex = regexp.MustCompile("([a-zA-Z]+)(([0-9]+)(x([0-9]+))?)?")
    57  )
    58  
    59  // NewType creates a new reflection type of abi type given in t.
    60  func NewType(t string) (typ Type, err error) {
    61  	// check that array brackets are equal if they exist
    62  	if strings.Count(t, "[") != strings.Count(t, "]") {
    63  		return Type{}, fmt.Errorf("invalid arg type in abi")
    64  	}
    65  
    66  	typ.stringKind = t
    67  
    68  	// if there are brackets, get ready to go into slice/array mode and
    69  	// recursively create the type
    70  	if strings.Count(t, "[") != 0 {
    71  		i := strings.LastIndex(t, "[")
    72  		// recursively embed the type
    73  		embeddedType, err := NewType(t[:i])
    74  		if err != nil {
    75  			return Type{}, err
    76  		}
    77  		// grab the last cell and create a type from there
    78  		sliced := t[i:]
    79  		// grab the slice size with regexp
    80  		re := regexp.MustCompile("[0-9]+")
    81  		intz := re.FindAllString(sliced, -1)
    82  
    83  		if len(intz) == 0 {
    84  			// is a slice
    85  			typ.T = SliceTy
    86  			typ.Kind = reflect.Slice
    87  			typ.Elem = &embeddedType
    88  			typ.Type = reflect.SliceOf(embeddedType.Type)
    89  		} else if len(intz) == 1 {
    90  			// is a array
    91  			typ.T = ArrayTy
    92  			typ.Kind = reflect.Array
    93  			typ.Elem = &embeddedType
    94  			typ.Size, err = strconv.Atoi(intz[0])
    95  			if err != nil {
    96  				return Type{}, fmt.Errorf("abi: error parsing variable size: %v", err)
    97  			}
    98  			typ.Type = reflect.ArrayOf(typ.Size, embeddedType.Type)
    99  		} else {
   100  			return Type{}, fmt.Errorf("invalid formatting of array type")
   101  		}
   102  		return typ, err
   103  	} else {
   104  		// parse the type and size of the abi-type.
   105  		parsedType := typeRegex.FindAllStringSubmatch(t, -1)[0]
   106  		// varSize is the size of the variable
   107  		var varSize int
   108  		if len(parsedType[3]) > 0 {
   109  			var err error
   110  			varSize, err = strconv.Atoi(parsedType[2])
   111  			if err != nil {
   112  				return Type{}, fmt.Errorf("abi: error parsing variable size: %v", err)
   113  			}
   114  		} else {
   115  			if parsedType[0] == "uint" || parsedType[0] == "int" {
   116  				// this should fail because it means that there's something wrong with
   117  				// the abi type (the compiler should always format it to the size...always)
   118  				return Type{}, fmt.Errorf("unsupported arg type: %s", t)
   119  			}
   120  		}
   121  		// varType is the parsed abi type
   122  		varType := parsedType[1]
   123  
   124  		switch varType {
   125  		case "int":
   126  			typ.Kind, typ.Type = reflectIntKindAndType(false, varSize)
   127  			typ.Size = varSize
   128  			typ.T = IntTy
   129  		case "uint":
   130  			typ.Kind, typ.Type = reflectIntKindAndType(true, varSize)
   131  			typ.Size = varSize
   132  			typ.T = UintTy
   133  		case "bool":
   134  			typ.Kind = reflect.Bool
   135  			typ.T = BoolTy
   136  			typ.Type = reflect.TypeOf(bool(false))
   137  		case "address":
   138  			typ.Kind = reflect.Array
   139  			typ.Type = address_t
   140  			typ.Size = 20
   141  			typ.T = AddressTy
   142  		case "string":
   143  			typ.Kind = reflect.String
   144  			typ.Type = reflect.TypeOf("")
   145  			typ.T = StringTy
   146  		case "bytes":
   147  			if varSize == 0 {
   148  				typ.T = BytesTy
   149  				typ.Kind = reflect.Slice
   150  				typ.Type = reflect.SliceOf(reflect.TypeOf(byte(0)))
   151  			} else {
   152  				typ.T = FixedBytesTy
   153  				typ.Kind = reflect.Array
   154  				typ.Size = varSize
   155  				typ.Type = reflect.ArrayOf(varSize, reflect.TypeOf(byte(0)))
   156  			}
   157  		case "function":
   158  			typ.Kind = reflect.Array
   159  			typ.T = FunctionTy
   160  			typ.Size = 24
   161  			typ.Type = reflect.ArrayOf(24, reflect.TypeOf(byte(0)))
   162  		default:
   163  			return Type{}, fmt.Errorf("unsupported arg type: %s", t)
   164  		}
   165  	}
   166  
   167  	return
   168  }
   169  
   170  // String implements Stringer
   171  func (t Type) String() (out string) {
   172  	return t.stringKind
   173  }
   174  
   175  func (t Type) pack(v reflect.Value) ([]byte, error) {
   176  	// dereference pointer first if it's a pointer
   177  	v = indirect(v)
   178  
   179  	if err := typeCheck(t, v); err != nil {
   180  		return nil, err
   181  	}
   182  
   183  	if t.T == SliceTy || t.T == ArrayTy {
   184  		var packed []byte
   185  
   186  		for i := 0; i < v.Len(); i++ {
   187  			val, err := t.Elem.pack(v.Index(i))
   188  			if err != nil {
   189  				return nil, err
   190  			}
   191  			packed = append(packed, val...)
   192  		}
   193  		if t.T == SliceTy {
   194  			return packBytesSlice(packed, v.Len()), nil
   195  		} else if t.T == ArrayTy {
   196  			return packed, nil
   197  		}
   198  	}
   199  	return packElement(t, v), nil
   200  }
   201  
   202  // requireLengthPrefix returns whether the type requires any sort of length
   203  // prefixing.
   204  func (t Type) requiresLengthPrefix() bool {
   205  	return t.T == StringTy || t.T == BytesTy || t.T == SliceTy
   206  }