github.com/waltonchain/waltonchain_gwtc_src@v1.1.4-0.20201225072101-8a298c95a819/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-wtc 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-wtc 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  )
    25  
    26  const (
    27  	IntTy byte = iota
    28  	UintTy
    29  	BoolTy
    30  	StringTy
    31  	SliceTy
    32  	AddressTy
    33  	FixedBytesTy
    34  	BytesTy
    35  	HashTy
    36  	FixedPointTy
    37  	FunctionTy
    38  )
    39  
    40  // Type is the reflection of the supported argument type
    41  type Type struct {
    42  	IsSlice, IsArray bool
    43  	SliceSize        int
    44  
    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  	// fullTypeRegex parses the abi types
    57  	//
    58  	// Types can be in the format of:
    59  	//
    60  	// 	Input  = Type [ "[" [ Number ] "]" ] Name .
    61  	// 	Type   = [ "u" ] "int" [ Number ] [ x ] [ Number ].
    62  	//
    63  	// Examples:
    64  	//
    65  	//      string     int       uint       fixed
    66  	//      string32   int8      uint8      uint[]
    67  	//      address    int256    uint256    fixed128x128[2]
    68  	fullTypeRegex = regexp.MustCompile(`([a-zA-Z0-9]+)(\[([0-9]*)\])?`)
    69  	// typeRegex parses the abi sub types
    70  	typeRegex = regexp.MustCompile("([a-zA-Z]+)(([0-9]+)(x([0-9]+))?)?")
    71  )
    72  
    73  // NewType creates a new reflection type of abi type given in t.
    74  func NewType(t string) (typ Type, err error) {
    75  	res := fullTypeRegex.FindAllStringSubmatch(t, -1)[0]
    76  	// check if type is slice and parse type.
    77  	switch {
    78  	case res[3] != "":
    79  		// err is ignored. Already checked for number through the regexp
    80  		typ.SliceSize, _ = strconv.Atoi(res[3])
    81  		typ.IsArray = true
    82  	case res[2] != "":
    83  		typ.IsSlice, typ.SliceSize = true, -1
    84  	case res[0] == "":
    85  		return Type{}, fmt.Errorf("abi: type parse error: %s", t)
    86  	}
    87  	if typ.IsArray || typ.IsSlice {
    88  		sliceType, err := NewType(res[1])
    89  		if err != nil {
    90  			return Type{}, err
    91  		}
    92  		typ.Elem = &sliceType
    93  		typ.stringKind = sliceType.stringKind + t[len(res[1]):]
    94  		// Although we know that this is an array, we cannot return
    95  		// as we don't know the type of the element, however, if it
    96  		// is still an array, then don't determine the type.
    97  		if typ.Elem.IsArray || typ.Elem.IsSlice {
    98  			return typ, nil
    99  		}
   100  	}
   101  
   102  	// parse the type and size of the abi-type.
   103  	parsedType := typeRegex.FindAllStringSubmatch(res[1], -1)[0]
   104  	// varSize is the size of the variable
   105  	var varSize int
   106  	if len(parsedType[3]) > 0 {
   107  		var err error
   108  		varSize, err = strconv.Atoi(parsedType[2])
   109  		if err != nil {
   110  			return Type{}, fmt.Errorf("abi: error parsing variable size: %v", err)
   111  		}
   112  	}
   113  	// varType is the parsed abi type
   114  	varType := parsedType[1]
   115  	// substitute canonical integer
   116  	if varSize == 0 && (varType == "int" || varType == "uint") {
   117  		varSize = 256
   118  		t += "256"
   119  	}
   120  
   121  	// only set stringKind if not array or slice, as for those,
   122  	// the correct string type has been set
   123  	if !(typ.IsArray || typ.IsSlice) {
   124  		typ.stringKind = t
   125  	}
   126  
   127  	switch varType {
   128  	case "int":
   129  		typ.Kind, typ.Type = reflectIntKindAndType(false, varSize)
   130  		typ.Size = varSize
   131  		typ.T = IntTy
   132  	case "uint":
   133  		typ.Kind, typ.Type = reflectIntKindAndType(true, varSize)
   134  		typ.Size = varSize
   135  		typ.T = UintTy
   136  	case "bool":
   137  		typ.Kind = reflect.Bool
   138  		typ.T = BoolTy
   139  	case "address":
   140  		typ.Kind = reflect.Array
   141  		typ.Type = address_t
   142  		typ.Size = 20
   143  		typ.T = AddressTy
   144  	case "string":
   145  		typ.Kind = reflect.String
   146  		typ.Size = -1
   147  		typ.T = StringTy
   148  	case "bytes":
   149  		sliceType, _ := NewType("uint8")
   150  		typ.Elem = &sliceType
   151  		if varSize == 0 {
   152  			typ.IsSlice = true
   153  			typ.T = BytesTy
   154  			typ.SliceSize = -1
   155  		} else {
   156  			typ.IsArray = true
   157  			typ.T = FixedBytesTy
   158  			typ.SliceSize = varSize
   159  		}
   160  	case "function":
   161  		sliceType, _ := NewType("uint8")
   162  		typ.Elem = &sliceType
   163  		typ.IsArray = true
   164  		typ.T = FunctionTy
   165  		typ.SliceSize = 24
   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  	if (t.IsSlice || t.IsArray) && t.T != BytesTy && t.T != FixedBytesTy && t.T != FunctionTy {
   187  		var packed []byte
   188  
   189  		for i := 0; i < v.Len(); i++ {
   190  			val, err := t.Elem.pack(v.Index(i))
   191  			if err != nil {
   192  				return nil, err
   193  			}
   194  			packed = append(packed, val...)
   195  		}
   196  		if t.IsSlice {
   197  			return packBytesSlice(packed, v.Len()), nil
   198  		} else if t.IsArray {
   199  			return packed, nil
   200  		}
   201  	}
   202  
   203  	return packElement(t, v), nil
   204  }
   205  
   206  // requireLengthPrefix returns whether the type requires any sort of length
   207  // prefixing.
   208  func (t Type) requiresLengthPrefix() bool {
   209  	return t.T != FixedBytesTy && (t.T == StringTy || t.T == BytesTy || t.IsSlice)
   210  }