github.com/ethereumproject/go-ethereum@v5.5.2+incompatible/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  )
    25  
    26  const (
    27  	IntTy byte = iota
    28  	UintTy
    29  	BoolTy
    30  	StringTy
    31  	SliceTy
    32  	AddressTy
    33  	FixedBytesTy
    34  	BytesTy
    35  	HashTy
    36  	RealTy
    37  )
    38  
    39  // Type is the reflection of the supported argument type
    40  type Type struct {
    41  	IsSlice, IsArray bool
    42  	SliceSize        int
    43  
    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  	// fullTypeRegex parses the abi types
    56  	//
    57  	// Types can be in the format of:
    58  	//
    59  	// 	Input  = Type [ "[" [ Number ] "]" ] Name .
    60  	// 	Type   = [ "u" ] "int" [ Number ] .
    61  	//
    62  	// Examples:
    63  	//
    64  	//      string     int       uint       real
    65  	//      string32   int8      uint8      uint[]
    66  	//      address    int256    uint256    real[2]
    67  	fullTypeRegex = regexp.MustCompile("([a-zA-Z0-9]+)(\\[([0-9]*)?\\])?")
    68  	// typeRegex parses the abi sub types
    69  	typeRegex = regexp.MustCompile("([a-zA-Z]+)([0-9]*)?")
    70  )
    71  
    72  // NewType creates a new reflection type of abi type given in t.
    73  func NewType(t string) (typ Type, err error) {
    74  	res := fullTypeRegex.FindAllStringSubmatch(t, -1)[0]
    75  	// check if type is slice and parse type.
    76  	switch {
    77  	case res[3] != "":
    78  		// err is ignored. Already checked for number through the regexp
    79  		typ.SliceSize, _ = strconv.Atoi(res[3])
    80  		typ.IsArray = true
    81  	case res[2] != "":
    82  		typ.IsSlice, typ.SliceSize = true, -1
    83  	case res[0] == "":
    84  		return Type{}, fmt.Errorf("abi: type parse error: %s", t)
    85  	}
    86  	if typ.IsArray || typ.IsSlice {
    87  		sliceType, err := NewType(res[1])
    88  		if err != nil {
    89  			return Type{}, err
    90  		}
    91  		typ.Elem = &sliceType
    92  		typ.stringKind = sliceType.stringKind + t[len(res[1]):]
    93  		return typ, nil
    94  	}
    95  
    96  	// parse the type and size of the abi-type.
    97  	parsedType := typeRegex.FindAllStringSubmatch(res[1], -1)[0]
    98  	// varSize is the size of the variable
    99  	var varSize int
   100  	if len(parsedType[2]) > 0 {
   101  		var err error
   102  		varSize, err = strconv.Atoi(parsedType[2])
   103  		if err != nil {
   104  			return Type{}, fmt.Errorf("abi: error parsing variable size: %v", err)
   105  		}
   106  	}
   107  	// varType is the parsed abi type
   108  	varType := parsedType[1]
   109  	// substitute canonical integer
   110  	if varSize == 0 && (varType == "int" || varType == "uint") {
   111  		varSize = 256
   112  		t += "256"
   113  	}
   114  	typ.stringKind = t
   115  
   116  	switch varType {
   117  	case "int":
   118  		typ.Kind = reflectIntKind(false, varSize)
   119  		typ.Type = big_t
   120  		typ.Size = varSize
   121  		typ.T = IntTy
   122  	case "uint":
   123  		typ.Kind = reflectIntKind(true, varSize)
   124  		typ.Type = ubig_t
   125  		typ.Size = varSize
   126  		typ.T = UintTy
   127  	case "bool":
   128  		typ.Kind = reflect.Bool
   129  		typ.T = BoolTy
   130  	case "address":
   131  		typ.Kind = reflect.Array
   132  		typ.Type = address_t
   133  		typ.Size = 20
   134  		typ.T = AddressTy
   135  	case "string":
   136  		typ.Kind = reflect.String
   137  		typ.Size = -1
   138  		typ.T = StringTy
   139  	case "bytes":
   140  		sliceType, _ := NewType("uint8")
   141  		typ.Elem = &sliceType
   142  		if varSize == 0 {
   143  			typ.IsSlice = true
   144  			typ.T = BytesTy
   145  			typ.SliceSize = -1
   146  		} else {
   147  			typ.IsArray = true
   148  			typ.T = FixedBytesTy
   149  			typ.SliceSize = varSize
   150  		}
   151  	default:
   152  		return Type{}, fmt.Errorf("unsupported arg type: %s", t)
   153  	}
   154  
   155  	return
   156  }
   157  
   158  // String implements Stringer
   159  func (t Type) String() (out string) {
   160  	return t.stringKind
   161  }
   162  
   163  func (t Type) pack(v reflect.Value) ([]byte, error) {
   164  	// dereference pointer first if it's a pointer
   165  	v = indirect(v)
   166  
   167  	if err := typeCheck(t, v); err != nil {
   168  		return nil, err
   169  	}
   170  
   171  	if (t.IsSlice || t.IsArray) && t.T != BytesTy && t.T != FixedBytesTy {
   172  		var packed []byte
   173  		for i := 0; i < v.Len(); i++ {
   174  			val, err := t.Elem.pack(v.Index(i))
   175  			if err != nil {
   176  				return nil, err
   177  			}
   178  			packed = append(packed, val...)
   179  		}
   180  		return packBytesSlice(packed, v.Len()), nil
   181  	}
   182  
   183  	return packElement(t, v), nil
   184  }
   185  
   186  // requireLengthPrefix returns whether the type requires any sort of length
   187  // prefixing.
   188  func (t Type) requiresLengthPrefix() bool {
   189  	return t.T != FixedBytesTy && (t.T == StringTy || t.T == BytesTy || t.IsSlice || t.IsArray)
   190  }