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