github.com/insight-chain/inb-go@v1.1.3-0.20191221022159-da049980ae38/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 AddressTy 36 FixedBytesTy 37 BytesTy 38 HashTy 39 FixedPointTy 40 FunctionTy 41 ) 42 43 // Type is the reflection of the supported argument type 44 type Type struct { 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 // typeRegex parses the abi sub types 57 typeRegex = regexp.MustCompile("([a-zA-Z]+)(([0-9]+)(x([0-9]+))?)?") 58 ) 59 60 // NewType creates a new reflection type of abi type given in t. 61 func NewType(t string) (typ Type, err error) { 62 // check that array brackets are equal if they exist 63 if strings.Count(t, "[") != strings.Count(t, "]") { 64 return Type{}, fmt.Errorf("invalid arg type in abi") 65 } 66 67 typ.stringKind = t 68 69 // if there are brackets, get ready to go into slice/array mode and 70 // recursively create the type 71 if strings.Count(t, "[") != 0 { 72 i := strings.LastIndex(t, "[") 73 // recursively embed the type 74 embeddedType, err := NewType(t[:i]) 75 if err != nil { 76 return Type{}, err 77 } 78 // grab the last cell and create a type from there 79 sliced := t[i:] 80 // grab the slice size with regexp 81 re := regexp.MustCompile("[0-9]+") 82 intz := re.FindAllString(sliced, -1) 83 84 if len(intz) == 0 { 85 // is a slice 86 typ.T = SliceTy 87 typ.Kind = reflect.Slice 88 typ.Elem = &embeddedType 89 typ.Type = reflect.SliceOf(embeddedType.Type) 90 } else if len(intz) == 1 { 91 // is a array 92 typ.T = ArrayTy 93 typ.Kind = reflect.Array 94 typ.Elem = &embeddedType 95 typ.Size, err = strconv.Atoi(intz[0]) 96 if err != nil { 97 return Type{}, fmt.Errorf("abi: error parsing variable size: %v", err) 98 } 99 typ.Type = reflect.ArrayOf(typ.Size, embeddedType.Type) 100 } else { 101 return Type{}, fmt.Errorf("invalid formatting of array type") 102 } 103 return typ, err 104 } 105 // parse the type and size of the abi-type. 106 matches := typeRegex.FindAllStringSubmatch(t, -1) 107 if len(matches) == 0 { 108 return Type{}, fmt.Errorf("invalid type '%v'", t) 109 } 110 parsedType := matches[0] 111 112 // varSize is the size of the variable 113 var varSize int 114 if len(parsedType[3]) > 0 { 115 var err error 116 varSize, err = strconv.Atoi(parsedType[2]) 117 if err != nil { 118 return Type{}, fmt.Errorf("abi: error parsing variable size: %v", err) 119 } 120 } else { 121 if parsedType[0] == "uint" || parsedType[0] == "int" { 122 // this should fail because it means that there's something wrong with 123 // the abi type (the compiler should always format it to the size...always) 124 return Type{}, fmt.Errorf("unsupported arg type: %s", t) 125 } 126 } 127 // varType is the parsed abi type 128 switch varType := parsedType[1]; varType { 129 case "int": 130 typ.Kind, typ.Type = reflectIntKindAndType(false, varSize) 131 typ.Size = varSize 132 typ.T = IntTy 133 case "uint": 134 typ.Kind, typ.Type = reflectIntKindAndType(true, varSize) 135 typ.Size = varSize 136 typ.T = UintTy 137 case "bool": 138 typ.Kind = reflect.Bool 139 typ.T = BoolTy 140 typ.Type = reflect.TypeOf(bool(false)) 141 case "address": 142 typ.Kind = reflect.Array 143 typ.Type = addressT 144 typ.Size = 20 145 typ.T = AddressTy 146 case "string": 147 typ.Kind = reflect.String 148 typ.Type = reflect.TypeOf("") 149 typ.T = StringTy 150 case "bytes": 151 if varSize == 0 { 152 typ.T = BytesTy 153 typ.Kind = reflect.Slice 154 typ.Type = reflect.SliceOf(reflect.TypeOf(byte(0))) 155 } else { 156 typ.T = FixedBytesTy 157 typ.Kind = reflect.Array 158 typ.Size = varSize 159 typ.Type = reflect.ArrayOf(varSize, reflect.TypeOf(byte(0))) 160 } 161 case "function": 162 typ.Kind = reflect.Array 163 typ.T = FunctionTy 164 typ.Size = 24 165 typ.Type = reflect.ArrayOf(24, reflect.TypeOf(byte(0))) 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 switch t.T { 187 case SliceTy, ArrayTy: 188 var ret []byte 189 190 if t.requiresLengthPrefix() { 191 // append length 192 ret = append(ret, packNum(reflect.ValueOf(v.Len()))...) 193 } 194 195 // calculate offset if any 196 offset := 0 197 offsetReq := isDynamicType(*t.Elem) 198 if offsetReq { 199 offset = getDynamicTypeOffset(*t.Elem) * v.Len() 200 } 201 var tail []byte 202 for i := 0; i < v.Len(); i++ { 203 val, err := t.Elem.pack(v.Index(i)) 204 if err != nil { 205 return nil, err 206 } 207 if !offsetReq { 208 ret = append(ret, val...) 209 continue 210 } 211 ret = append(ret, packNum(reflect.ValueOf(offset))...) 212 offset += len(val) 213 tail = append(tail, val...) 214 } 215 return append(ret, tail...), nil 216 default: 217 return packElement(t, v), nil 218 } 219 } 220 221 // requireLengthPrefix returns whether the type requires any sort of length 222 // prefixing. 223 func (t Type) requiresLengthPrefix() bool { 224 return t.T == StringTy || t.T == BytesTy || t.T == SliceTy 225 } 226 227 // isDynamicType returns true if the type is dynamic. 228 // StringTy, BytesTy, and SliceTy(irrespective of slice element type) are dynamic types 229 // ArrayTy is considered dynamic if and only if the Array element is a dynamic type. 230 // This function recursively checks the type for slice and array elements. 231 func isDynamicType(t Type) bool { 232 // dynamic types 233 // array is also a dynamic type if the array type is dynamic 234 return t.T == StringTy || t.T == BytesTy || t.T == SliceTy || (t.T == ArrayTy && isDynamicType(*t.Elem)) 235 } 236 237 // getDynamicTypeOffset returns the offset for the type. 238 // See `isDynamicType` to know which types are considered dynamic. 239 // If the type t is an array and element type is not a dynamic type, then we consider it a static type and 240 // return 32 * size of array since length prefix is not required. 241 // If t is a dynamic type or element type(for slices and arrays) is dynamic, then we simply return 32 as offset. 242 func getDynamicTypeOffset(t Type) int { 243 // if it is an array and there are no dynamic types 244 // then the array is static type 245 if t.T == ArrayTy && !isDynamicType(*t.Elem) { 246 return 32 * t.Size 247 } 248 return 32 249 }