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