github.com/MetalBlockchain/subnet-evm@v0.4.9/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{}, fmt.Errorf("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{}, fmt.Errorf("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 typ.T = FixedBytesTy 168 typ.Size = varSize 169 } 170 case "tuple": 171 var ( 172 fields []reflect.StructField 173 elems []*Type 174 names []string 175 expression string // canonical parameter expression 176 used = make(map[string]bool) 177 ) 178 expression += "(" 179 for idx, c := range components { 180 cType, err := NewType(c.Type, c.InternalType, c.Components) 181 if err != nil { 182 return Type{}, err 183 } 184 name := ToCamelCase(c.Name) 185 if name == "" { 186 return Type{}, errors.New("abi: purely anonymous or underscored field is not supported") 187 } 188 fieldName := ResolveNameConflict(name, func(s string) bool { return used[s] }) 189 190 used[fieldName] = true 191 if !isValidFieldName(fieldName) { 192 return Type{}, fmt.Errorf("field %d has invalid name", idx) 193 } 194 fields = append(fields, reflect.StructField{ 195 Name: fieldName, // reflect.StructOf will panic for any exported field. 196 Type: cType.GetType(), 197 Tag: reflect.StructTag("json:\"" + c.Name + "\""), 198 }) 199 elems = append(elems, &cType) 200 names = append(names, c.Name) 201 expression += cType.stringKind 202 if idx != len(components)-1 { 203 expression += "," 204 } 205 } 206 expression += ")" 207 208 typ.TupleType = reflect.StructOf(fields) 209 typ.TupleElems = elems 210 typ.TupleRawNames = names 211 typ.T = TupleTy 212 typ.stringKind = expression 213 214 const structPrefix = "struct " 215 // After solidity 0.5.10, a new field of abi "internalType" 216 // is introduced. From that we can obtain the struct name 217 // user defined in the source code. 218 if internalType != "" && strings.HasPrefix(internalType, structPrefix) { 219 // Foo.Bar type definition is not allowed in golang, 220 // convert the format to FooBar 221 typ.TupleRawName = strings.ReplaceAll(internalType[len(structPrefix):], ".", "") 222 } 223 224 case "function": 225 typ.T = FunctionTy 226 typ.Size = 24 227 default: 228 return Type{}, fmt.Errorf("unsupported arg type: %s", t) 229 } 230 231 return 232 } 233 234 // GetType returns the reflection type of the ABI type. 235 func (t Type) GetType() reflect.Type { 236 switch t.T { 237 case IntTy: 238 return reflectIntType(false, t.Size) 239 case UintTy: 240 return reflectIntType(true, t.Size) 241 case BoolTy: 242 return reflect.TypeOf(false) 243 case StringTy: 244 return reflect.TypeOf("") 245 case SliceTy: 246 return reflect.SliceOf(t.Elem.GetType()) 247 case ArrayTy: 248 return reflect.ArrayOf(t.Size, t.Elem.GetType()) 249 case TupleTy: 250 return t.TupleType 251 case AddressTy: 252 return reflect.TypeOf(common.Address{}) 253 case FixedBytesTy: 254 return reflect.ArrayOf(t.Size, reflect.TypeOf(byte(0))) 255 case BytesTy: 256 return reflect.SliceOf(reflect.TypeOf(byte(0))) 257 case HashTy: 258 // hashtype currently not used 259 return reflect.ArrayOf(32, reflect.TypeOf(byte(0))) 260 case FixedPointTy: 261 // fixedpoint type currently not used 262 return reflect.ArrayOf(32, reflect.TypeOf(byte(0))) 263 case FunctionTy: 264 return reflect.ArrayOf(24, reflect.TypeOf(byte(0))) 265 default: 266 panic("Invalid type") 267 } 268 } 269 270 // String implements Stringer. 271 func (t Type) String() (out string) { 272 return t.stringKind 273 } 274 275 func (t Type) pack(v reflect.Value) ([]byte, error) { 276 // dereference pointer first if it's a pointer 277 v = indirect(v) 278 if err := typeCheck(t, v); err != nil { 279 return nil, err 280 } 281 282 switch t.T { 283 case SliceTy, ArrayTy: 284 var ret []byte 285 286 if t.requiresLengthPrefix() { 287 // append length 288 ret = append(ret, packNum(reflect.ValueOf(v.Len()))...) 289 } 290 291 // calculate offset if any 292 offset := 0 293 offsetReq := isDynamicType(*t.Elem) 294 if offsetReq { 295 offset = getTypeSize(*t.Elem) * v.Len() 296 } 297 var tail []byte 298 for i := 0; i < v.Len(); i++ { 299 val, err := t.Elem.pack(v.Index(i)) 300 if err != nil { 301 return nil, err 302 } 303 if !offsetReq { 304 ret = append(ret, val...) 305 continue 306 } 307 ret = append(ret, packNum(reflect.ValueOf(offset))...) 308 offset += len(val) 309 tail = append(tail, val...) 310 } 311 return append(ret, tail...), nil 312 case TupleTy: 313 // (T1,...,Tk) for k >= 0 and any types T1, …, Tk 314 // enc(X) = head(X(1)) ... head(X(k)) tail(X(1)) ... tail(X(k)) 315 // where X = (X(1), ..., X(k)) and head and tail are defined for Ti being a static 316 // type as 317 // head(X(i)) = enc(X(i)) and tail(X(i)) = "" (the empty string) 318 // and as 319 // head(X(i)) = enc(len(head(X(1)) ... head(X(k)) tail(X(1)) ... tail(X(i-1)))) 320 // tail(X(i)) = enc(X(i)) 321 // otherwise, i.e. if Ti is a dynamic type. 322 fieldmap, err := mapArgNamesToStructFields(t.TupleRawNames, v) 323 if err != nil { 324 return nil, err 325 } 326 // Calculate prefix occupied size. 327 offset := 0 328 for _, elem := range t.TupleElems { 329 offset += getTypeSize(*elem) 330 } 331 var ret, tail []byte 332 for i, elem := range t.TupleElems { 333 field := v.FieldByName(fieldmap[t.TupleRawNames[i]]) 334 if !field.IsValid() { 335 return nil, fmt.Errorf("field %s for tuple not found in the given struct", t.TupleRawNames[i]) 336 } 337 val, err := elem.pack(field) 338 if err != nil { 339 return nil, err 340 } 341 if isDynamicType(*elem) { 342 ret = append(ret, packNum(reflect.ValueOf(offset))...) 343 tail = append(tail, val...) 344 offset += len(val) 345 } else { 346 ret = append(ret, val...) 347 } 348 } 349 return append(ret, tail...), nil 350 351 default: 352 return packElement(t, v) 353 } 354 } 355 356 // requireLengthPrefix returns whether the type requires any sort of length 357 // prefixing. 358 func (t Type) requiresLengthPrefix() bool { 359 return t.T == StringTy || t.T == BytesTy || t.T == SliceTy 360 } 361 362 // isDynamicType returns true if the type is dynamic. 363 // The following types are called “dynamic”: 364 // * bytes 365 // * string 366 // * T[] for any T 367 // * T[k] for any dynamic T and any k >= 0 368 // * (T1,...,Tk) if Ti is dynamic for some 1 <= i <= k 369 func isDynamicType(t Type) bool { 370 if t.T == TupleTy { 371 for _, elem := range t.TupleElems { 372 if isDynamicType(*elem) { 373 return true 374 } 375 } 376 return false 377 } 378 return t.T == StringTy || t.T == BytesTy || t.T == SliceTy || (t.T == ArrayTy && isDynamicType(*t.Elem)) 379 } 380 381 // getTypeSize returns the size that this type needs to occupy. 382 // We distinguish static and dynamic types. Static types are encoded in-place 383 // and dynamic types are encoded at a separately allocated location after the 384 // current block. 385 // So for a static variable, the size returned represents the size that the 386 // variable actually occupies. 387 // For a dynamic variable, the returned size is fixed 32 bytes, which is used 388 // to store the location reference for actual value storage. 389 func getTypeSize(t Type) int { 390 if t.T == ArrayTy && !isDynamicType(*t.Elem) { 391 // Recursively calculate type size if it is a nested array 392 if t.Elem.T == ArrayTy || t.Elem.T == TupleTy { 393 return t.Size * getTypeSize(*t.Elem) 394 } 395 return t.Size * 32 396 } else if t.T == TupleTy && !isDynamicType(t) { 397 total := 0 398 for _, elem := range t.TupleElems { 399 total += getTypeSize(*elem) 400 } 401 return total 402 } 403 return 32 404 } 405 406 // isLetter reports whether a given 'rune' is classified as a Letter. 407 // This method is copied from reflect/type.go 408 func isLetter(ch rune) bool { 409 return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch == '_' || ch >= utf8.RuneSelf && unicode.IsLetter(ch) 410 } 411 412 // isValidFieldName checks if a string is a valid (struct) field name or not. 413 // 414 // According to the language spec, a field name should be an identifier. 415 // 416 // identifier = letter { letter | unicode_digit } . 417 // letter = unicode_letter | "_" . 418 // This method is copied from reflect/type.go 419 func isValidFieldName(fieldName string) bool { 420 for i, c := range fieldName { 421 if i == 0 && !isLetter(c) { 422 return false 423 } 424 425 if !(isLetter(c) || unicode.IsDigit(c)) { 426 return false 427 } 428 } 429 430 return len(fieldName) > 0 431 }