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