github.com/ava-labs/subnet-evm@v0.6.4/accounts/abi/type.go (about) 1 // (c) 2019-2020, Ava Labs, Inc. 2 // 3 // This file is a derived work, based on the go-ethereum library whose original 4 // notices appear below. 5 // 6 // It is distributed under a license compatible with the licensing terms of the 7 // original code from which it is derived. 8 // 9 // Much love to the original authors for their work. 10 // ********** 11 // Copyright 2015 The go-ethereum Authors 12 // This file is part of the go-ethereum library. 13 // 14 // The go-ethereum library is free software: you can redistribute it and/or modify 15 // it under the terms of the GNU Lesser General Public License as published by 16 // the Free Software Foundation, either version 3 of the License, or 17 // (at your option) any later version. 18 // 19 // The go-ethereum library is distributed in the hope that it will be useful, 20 // but WITHOUT ANY WARRANTY; without even the implied warranty of 21 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 // GNU Lesser General Public License for more details. 23 // 24 // You should have received a copy of the GNU Lesser General Public License 25 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 26 27 package abi 28 29 import ( 30 "errors" 31 "fmt" 32 "reflect" 33 "regexp" 34 "strconv" 35 "strings" 36 "unicode" 37 "unicode/utf8" 38 39 "github.com/ethereum/go-ethereum/common" 40 ) 41 42 // Type enumerator 43 const ( 44 IntTy byte = iota 45 UintTy 46 BoolTy 47 StringTy 48 SliceTy 49 ArrayTy 50 TupleTy 51 AddressTy 52 FixedBytesTy 53 BytesTy 54 HashTy 55 FixedPointTy 56 FunctionTy 57 ) 58 59 // Type is the reflection of the supported argument type. 60 type Type struct { 61 Elem *Type 62 Size int 63 T byte // Our own type checking 64 65 stringKind string // holds the unparsed string for deriving signatures 66 67 // Tuple relative fields 68 TupleRawName string // Raw struct name defined in source code, may be empty. 69 TupleElems []*Type // Type information of all tuple fields 70 TupleRawNames []string // Raw field name of all tuple fields 71 TupleType reflect.Type // Underlying struct of the tuple 72 } 73 74 var ( 75 // typeRegex parses the abi sub types 76 typeRegex = regexp.MustCompile("([a-zA-Z]+)(([0-9]+)(x([0-9]+))?)?") 77 ) 78 79 // NewType creates a new reflection type of abi type given in t. 80 func NewType(t string, internalType string, components []ArgumentMarshaling) (typ Type, err error) { 81 // check that array brackets are equal if they exist 82 if strings.Count(t, "[") != strings.Count(t, "]") { 83 return Type{}, errors.New("invalid arg type in abi") 84 } 85 typ.stringKind = t 86 87 // if there are brackets, get ready to go into slice/array mode and 88 // recursively create the type 89 if strings.Count(t, "[") != 0 { 90 // Note internalType can be empty here. 91 subInternal := internalType 92 if i := strings.LastIndex(internalType, "["); i != -1 { 93 subInternal = subInternal[:i] 94 } 95 // recursively embed the type 96 i := strings.LastIndex(t, "[") 97 embeddedType, err := NewType(t[:i], subInternal, components) 98 if err != nil { 99 return Type{}, err 100 } 101 // grab the last cell and create a type from there 102 sliced := t[i:] 103 // grab the slice size with regexp 104 re := regexp.MustCompile("[0-9]+") 105 intz := re.FindAllString(sliced, -1) 106 107 if len(intz) == 0 { 108 // is a slice 109 typ.T = SliceTy 110 typ.Elem = &embeddedType 111 typ.stringKind = embeddedType.stringKind + sliced 112 } else if len(intz) == 1 { 113 // is an array 114 typ.T = ArrayTy 115 typ.Elem = &embeddedType 116 typ.Size, err = strconv.Atoi(intz[0]) 117 if err != nil { 118 return Type{}, fmt.Errorf("abi: error parsing variable size: %v", err) 119 } 120 typ.stringKind = embeddedType.stringKind + sliced 121 } else { 122 return Type{}, errors.New("invalid formatting of array type") 123 } 124 return typ, err 125 } 126 // parse the type and size of the abi-type. 127 matches := typeRegex.FindAllStringSubmatch(t, -1) 128 if len(matches) == 0 { 129 return Type{}, fmt.Errorf("invalid type '%v'", t) 130 } 131 parsedType := matches[0] 132 133 // varSize is the size of the variable 134 var varSize int 135 if len(parsedType[3]) > 0 { 136 var err error 137 varSize, err = strconv.Atoi(parsedType[2]) 138 if err != nil { 139 return Type{}, fmt.Errorf("abi: error parsing variable size: %v", err) 140 } 141 } else { 142 if parsedType[0] == "uint" || parsedType[0] == "int" { 143 // this should fail because it means that there's something wrong with 144 // the abi type (the compiler should always format it to the size...always) 145 return Type{}, fmt.Errorf("unsupported arg type: %s", t) 146 } 147 } 148 // varType is the parsed abi type 149 switch varType := parsedType[1]; varType { 150 case "int": 151 typ.Size = varSize 152 typ.T = IntTy 153 case "uint": 154 typ.Size = varSize 155 typ.T = UintTy 156 case "bool": 157 typ.T = BoolTy 158 case "address": 159 typ.Size = 20 160 typ.T = AddressTy 161 case "string": 162 typ.T = StringTy 163 case "bytes": 164 if varSize == 0 { 165 typ.T = BytesTy 166 } else { 167 if varSize > 32 { 168 return Type{}, fmt.Errorf("unsupported arg type: %s", t) 169 } 170 typ.T = FixedBytesTy 171 typ.Size = varSize 172 } 173 case "tuple": 174 var ( 175 fields []reflect.StructField 176 elems []*Type 177 names []string 178 expression string // canonical parameter expression 179 used = make(map[string]bool) 180 ) 181 expression += "(" 182 for idx, c := range components { 183 cType, err := NewType(c.Type, c.InternalType, c.Components) 184 if err != nil { 185 return Type{}, err 186 } 187 name := ToCamelCase(c.Name) 188 if name == "" { 189 return Type{}, errors.New("abi: purely anonymous or underscored field is not supported") 190 } 191 fieldName := ResolveNameConflict(name, func(s string) bool { return used[s] }) 192 193 used[fieldName] = true 194 if !isValidFieldName(fieldName) { 195 return Type{}, fmt.Errorf("field %d has invalid name", idx) 196 } 197 fields = append(fields, reflect.StructField{ 198 Name: fieldName, // reflect.StructOf will panic for any exported field. 199 Type: cType.GetType(), 200 Tag: reflect.StructTag("json:\"" + c.Name + "\""), 201 }) 202 elems = append(elems, &cType) 203 names = append(names, c.Name) 204 expression += cType.stringKind 205 if idx != len(components)-1 { 206 expression += "," 207 } 208 } 209 expression += ")" 210 211 typ.TupleType = reflect.StructOf(fields) 212 typ.TupleElems = elems 213 typ.TupleRawNames = names 214 typ.T = TupleTy 215 typ.stringKind = expression 216 217 const structPrefix = "struct " 218 // After solidity 0.5.10, a new field of abi "internalType" 219 // is introduced. From that we can obtain the struct name 220 // user defined in the source code. 221 if internalType != "" && strings.HasPrefix(internalType, structPrefix) { 222 // Foo.Bar type definition is not allowed in golang, 223 // convert the format to FooBar 224 typ.TupleRawName = strings.ReplaceAll(internalType[len(structPrefix):], ".", "") 225 } 226 227 case "function": 228 typ.T = FunctionTy 229 typ.Size = 24 230 default: 231 return Type{}, fmt.Errorf("unsupported arg type: %s", t) 232 } 233 234 return 235 } 236 237 // GetType returns the reflection type of the ABI type. 238 func (t Type) GetType() reflect.Type { 239 switch t.T { 240 case IntTy: 241 return reflectIntType(false, t.Size) 242 case UintTy: 243 return reflectIntType(true, t.Size) 244 case BoolTy: 245 return reflect.TypeOf(false) 246 case StringTy: 247 return reflect.TypeOf("") 248 case SliceTy: 249 return reflect.SliceOf(t.Elem.GetType()) 250 case ArrayTy: 251 return reflect.ArrayOf(t.Size, t.Elem.GetType()) 252 case TupleTy: 253 return t.TupleType 254 case AddressTy: 255 return reflect.TypeOf(common.Address{}) 256 case FixedBytesTy: 257 return reflect.ArrayOf(t.Size, reflect.TypeOf(byte(0))) 258 case BytesTy: 259 return reflect.SliceOf(reflect.TypeOf(byte(0))) 260 case HashTy: 261 // hashtype currently not used 262 return reflect.ArrayOf(32, reflect.TypeOf(byte(0))) 263 case FixedPointTy: 264 // fixedpoint type currently not used 265 return reflect.ArrayOf(32, reflect.TypeOf(byte(0))) 266 case FunctionTy: 267 return reflect.ArrayOf(24, reflect.TypeOf(byte(0))) 268 default: 269 panic("Invalid type") 270 } 271 } 272 273 // String implements Stringer. 274 func (t Type) String() (out string) { 275 return t.stringKind 276 } 277 278 func (t Type) pack(v reflect.Value) ([]byte, error) { 279 // dereference pointer first if it's a pointer 280 v = indirect(v) 281 if err := typeCheck(t, v); err != nil { 282 return nil, err 283 } 284 285 switch t.T { 286 case SliceTy, ArrayTy: 287 var ret []byte 288 289 if t.requiresLengthPrefix() { 290 // append length 291 ret = append(ret, packNum(reflect.ValueOf(v.Len()))...) 292 } 293 294 // calculate offset if any 295 offset := 0 296 offsetReq := isDynamicType(*t.Elem) 297 if offsetReq { 298 offset = getTypeSize(*t.Elem) * v.Len() 299 } 300 var tail []byte 301 for i := 0; i < v.Len(); i++ { 302 val, err := t.Elem.pack(v.Index(i)) 303 if err != nil { 304 return nil, err 305 } 306 if !offsetReq { 307 ret = append(ret, val...) 308 continue 309 } 310 ret = append(ret, packNum(reflect.ValueOf(offset))...) 311 offset += len(val) 312 tail = append(tail, val...) 313 } 314 return append(ret, tail...), nil 315 case TupleTy: 316 // (T1,...,Tk) for k >= 0 and any types T1, …, Tk 317 // enc(X) = head(X(1)) ... head(X(k)) tail(X(1)) ... tail(X(k)) 318 // where X = (X(1), ..., X(k)) and head and tail are defined for Ti being a static 319 // type as 320 // head(X(i)) = enc(X(i)) and tail(X(i)) = "" (the empty string) 321 // and as 322 // head(X(i)) = enc(len(head(X(1)) ... head(X(k)) tail(X(1)) ... tail(X(i-1)))) 323 // tail(X(i)) = enc(X(i)) 324 // otherwise, i.e. if Ti is a dynamic type. 325 fieldmap, err := mapArgNamesToStructFields(t.TupleRawNames, v) 326 if err != nil { 327 return nil, err 328 } 329 // Calculate prefix occupied size. 330 offset := 0 331 for _, elem := range t.TupleElems { 332 offset += getTypeSize(*elem) 333 } 334 var ret, tail []byte 335 for i, elem := range t.TupleElems { 336 field := v.FieldByName(fieldmap[t.TupleRawNames[i]]) 337 if !field.IsValid() { 338 return nil, fmt.Errorf("field %s for tuple not found in the given struct", t.TupleRawNames[i]) 339 } 340 val, err := elem.pack(field) 341 if err != nil { 342 return nil, err 343 } 344 if isDynamicType(*elem) { 345 ret = append(ret, packNum(reflect.ValueOf(offset))...) 346 tail = append(tail, val...) 347 offset += len(val) 348 } else { 349 ret = append(ret, val...) 350 } 351 } 352 return append(ret, tail...), nil 353 354 default: 355 return packElement(t, v) 356 } 357 } 358 359 // requiresLengthPrefix returns whether the type requires any sort of length 360 // prefixing. 361 func (t Type) requiresLengthPrefix() bool { 362 return t.T == StringTy || t.T == BytesTy || t.T == SliceTy 363 } 364 365 // isDynamicType returns true if the type is dynamic. 366 // The following types are called “dynamic”: 367 // * bytes 368 // * string 369 // * T[] for any T 370 // * T[k] for any dynamic T and any k >= 0 371 // * (T1,...,Tk) if Ti is dynamic for some 1 <= i <= k 372 func isDynamicType(t Type) bool { 373 if t.T == TupleTy { 374 for _, elem := range t.TupleElems { 375 if isDynamicType(*elem) { 376 return true 377 } 378 } 379 return false 380 } 381 return t.T == StringTy || t.T == BytesTy || t.T == SliceTy || (t.T == ArrayTy && isDynamicType(*t.Elem)) 382 } 383 384 // getTypeSize returns the size that this type needs to occupy. 385 // We distinguish static and dynamic types. Static types are encoded in-place 386 // and dynamic types are encoded at a separately allocated location after the 387 // current block. 388 // So for a static variable, the size returned represents the size that the 389 // variable actually occupies. 390 // For a dynamic variable, the returned size is fixed 32 bytes, which is used 391 // to store the location reference for actual value storage. 392 func getTypeSize(t Type) int { 393 if t.T == ArrayTy && !isDynamicType(*t.Elem) { 394 // Recursively calculate type size if it is a nested array 395 if t.Elem.T == ArrayTy || t.Elem.T == TupleTy { 396 return t.Size * getTypeSize(*t.Elem) 397 } 398 return t.Size * 32 399 } else if t.T == TupleTy && !isDynamicType(t) { 400 total := 0 401 for _, elem := range t.TupleElems { 402 total += getTypeSize(*elem) 403 } 404 return total 405 } 406 return 32 407 } 408 409 // isLetter reports whether a given 'rune' is classified as a Letter. 410 // This method is copied from reflect/type.go 411 func isLetter(ch rune) bool { 412 return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch == '_' || ch >= utf8.RuneSelf && unicode.IsLetter(ch) 413 } 414 415 // isValidFieldName checks if a string is a valid (struct) field name or not. 416 // 417 // According to the language spec, a field name should be an identifier. 418 // 419 // identifier = letter { letter | unicode_digit } . 420 // letter = unicode_letter | "_" . 421 // This method is copied from reflect/type.go 422 func isValidFieldName(fieldName string) bool { 423 for i, c := range fieldName { 424 if i == 0 && !isLetter(c) { 425 return false 426 } 427 428 if !(isLetter(c) || unicode.IsDigit(c)) { 429 return false 430 } 431 } 432 433 return len(fieldName) > 0 434 }