github.com/jeffallen/go-ethereum@v1.1.4-0.20150910155051-571d3236c49c/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  	"github.com/ethereum/go-ethereum/common"
    26  )
    27  
    28  const (
    29  	IntTy byte = iota
    30  	UintTy
    31  	BoolTy
    32  	SliceTy
    33  	AddressTy
    34  	RealTy
    35  )
    36  
    37  // Type is the reflection of the supported argument type
    38  type Type struct {
    39  	Kind       reflect.Kind
    40  	Type       reflect.Type
    41  	Size       int
    42  	T          byte   // Our own type checking
    43  	stringKind string // holds the unparsed string for deriving signatures
    44  }
    45  
    46  // New type returns a fully parsed Type given by the input string or an error if it  can't be parsed.
    47  //
    48  // Strings can be in the format of:
    49  //
    50  // 	Input  = Type [ "[" [ Number ] "]" ] Name .
    51  // 	Type   = [ "u" ] "int" [ Number ] .
    52  //
    53  // Examples:
    54  //
    55  //      string     int       uint       real
    56  //      string32   int8      uint8      uint[]
    57  //      address    int256    uint256    real[2]
    58  func NewType(t string) (typ Type, err error) {
    59  	// 1. full string 2. type 3. (opt.) is slice 4. (opt.) size
    60  	freg, err := regexp.Compile("([a-zA-Z0-9]+)(\\[([0-9]*)?\\])?")
    61  	if err != nil {
    62  		return Type{}, err
    63  	}
    64  	res := freg.FindAllStringSubmatch(t, -1)[0]
    65  	var (
    66  		isslice bool
    67  		size    int
    68  	)
    69  	switch {
    70  	case res[3] != "":
    71  		// err is ignored. Already checked for number through the regexp
    72  		size, _ = strconv.Atoi(res[3])
    73  		isslice = true
    74  	case res[2] != "":
    75  		isslice = true
    76  		size = -1
    77  	case res[0] == "":
    78  		return Type{}, fmt.Errorf("type parse error for `%s`", t)
    79  	}
    80  
    81  	treg, err := regexp.Compile("([a-zA-Z]+)([0-9]*)?")
    82  	if err != nil {
    83  		return Type{}, err
    84  	}
    85  
    86  	parsedType := treg.FindAllStringSubmatch(res[1], -1)[0]
    87  	vsize, _ := strconv.Atoi(parsedType[2])
    88  	vtype := parsedType[1]
    89  	// substitute canonical representation
    90  	if vsize == 0 && (vtype == "int" || vtype == "uint") {
    91  		vsize = 256
    92  		t += "256"
    93  	}
    94  
    95  	if isslice {
    96  		typ.Kind = reflect.Slice
    97  		typ.Size = size
    98  		switch vtype {
    99  		case "int":
   100  			typ.Type = big_ts
   101  		case "uint":
   102  			typ.Type = ubig_ts
   103  		default:
   104  			return Type{}, fmt.Errorf("unsupported arg slice type: %s", t)
   105  		}
   106  	} else {
   107  		switch vtype {
   108  		case "int":
   109  			typ.Kind = reflect.Ptr
   110  			typ.Type = big_t
   111  			typ.Size = 256
   112  			typ.T = IntTy
   113  		case "uint":
   114  			typ.Kind = reflect.Ptr
   115  			typ.Type = ubig_t
   116  			typ.Size = 256
   117  			typ.T = UintTy
   118  		case "bool":
   119  			typ.Kind = reflect.Bool
   120  		case "real": // TODO
   121  			typ.Kind = reflect.Invalid
   122  		case "address":
   123  			typ.Kind = reflect.Slice
   124  			typ.Type = byte_ts
   125  			typ.Size = 20
   126  			typ.T = AddressTy
   127  		case "string":
   128  			typ.Kind = reflect.String
   129  			typ.Size = -1
   130  			if vsize > 0 {
   131  				typ.Size = 32
   132  			}
   133  		default:
   134  			return Type{}, fmt.Errorf("unsupported arg type: %s", t)
   135  		}
   136  	}
   137  	typ.stringKind = t
   138  
   139  	return
   140  }
   141  
   142  func (t Type) String() (out string) {
   143  	return t.stringKind
   144  }
   145  
   146  // Test the given input parameter `v` and checks if it matches certain
   147  // criteria
   148  // * Big integers are checks for ptr types and if the given value is
   149  //   assignable
   150  // * Integer are checked for size
   151  // * Strings, addresses and bytes are checks for type and size
   152  func (t Type) pack(v interface{}) ([]byte, error) {
   153  	value := reflect.ValueOf(v)
   154  	switch kind := value.Kind(); kind {
   155  	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
   156  		if t.Type != ubig_t {
   157  			return nil, fmt.Errorf("type mismatch: %s for %T", t.Type, v)
   158  		}
   159  		return packNum(value, t.T), nil
   160  	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
   161  		if t.Type != ubig_t {
   162  			return nil, fmt.Errorf("type mismatch: %s for %T", t.Type, v)
   163  		}
   164  		return packNum(value, t.T), nil
   165  	case reflect.Ptr:
   166  		// If the value is a ptr do a assign check (only used by
   167  		// big.Int for now)
   168  		if t.Type == ubig_t && value.Type() != ubig_t {
   169  			return nil, fmt.Errorf("type mismatch: %s for %T", t.Type, v)
   170  		}
   171  		return packNum(value, t.T), nil
   172  	case reflect.String:
   173  		if t.Size > -1 && value.Len() > t.Size {
   174  			return nil, fmt.Errorf("%v out of bound. %d for %d", value.Kind(), value.Len(), t.Size)
   175  		}
   176  		return []byte(common.LeftPadString(t.String(), 32)), nil
   177  	case reflect.Slice:
   178  		if t.Size > -1 && value.Len() > t.Size {
   179  			return nil, fmt.Errorf("%v out of bound. %d for %d", value.Kind(), value.Len(), t.Size)
   180  		}
   181  
   182  		// Address is a special slice. The slice acts as one rather than a list of elements.
   183  		if t.T == AddressTy {
   184  			return common.LeftPadBytes(v.([]byte), 32), nil
   185  		}
   186  
   187  		// Signed / Unsigned check
   188  		if (t.T != IntTy && isSigned(value)) || (t.T == UintTy && isSigned(value)) {
   189  			return nil, fmt.Errorf("slice of incompatible types.")
   190  		}
   191  
   192  		var packed []byte
   193  		for i := 0; i < value.Len(); i++ {
   194  			packed = append(packed, packNum(value.Index(i), t.T)...)
   195  		}
   196  		return packed, nil
   197  	case reflect.Bool:
   198  		if value.Bool() {
   199  			return common.LeftPadBytes(common.Big1.Bytes(), 32), nil
   200  		} else {
   201  			return common.LeftPadBytes(common.Big0.Bytes(), 32), nil
   202  		}
   203  	}
   204  
   205  	panic("unreached")
   206  }