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 }