github.com/aigarnetwork/aigar@v0.0.0-20191115204914-d59a6eb70f8e/accounts/abi/type.go (about) 1 // Copyright 2018 The go-ethereum Authors 2 // Copyright 2019 The go-aigar Authors 3 // This file is part of the go-aigar library. 4 // 5 // The go-aigar library is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Lesser General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // The go-aigar library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Lesser General Public License for more details. 14 // 15 // You should have received a copy of the GNU Lesser General Public License 16 // along with the go-aigar library. If not, see <http://www.gnu.org/licenses/>. 17 18 package abi 19 20 import ( 21 "errors" 22 "fmt" 23 "reflect" 24 "regexp" 25 "strconv" 26 "strings" 27 ) 28 29 // Type enumerator 30 const ( 31 IntTy byte = iota 32 UintTy 33 BoolTy 34 StringTy 35 SliceTy 36 ArrayTy 37 TupleTy 38 AddressTy 39 FixedBytesTy 40 BytesTy 41 HashTy 42 FixedPointTy 43 FunctionTy 44 ) 45 46 // Type is the reflection of the supported argument type 47 type Type struct { 48 Elem *Type 49 Kind reflect.Kind 50 Type reflect.Type 51 Size int 52 T byte // Our own type checking 53 54 stringKind string // holds the unparsed string for deriving signatures 55 56 // Tuple relative fields 57 TupleRawName string // Raw struct name defined in source code, may be empty. 58 TupleElems []*Type // Type information of all tuple fields 59 TupleRawNames []string // Raw field name of all tuple fields 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.Kind = reflect.Slice 99 typ.Elem = &embeddedType 100 typ.Type = reflect.SliceOf(embeddedType.Type) 101 typ.stringKind = embeddedType.stringKind + sliced 102 } else if len(intz) == 1 { 103 // is a array 104 typ.T = ArrayTy 105 typ.Kind = reflect.Array 106 typ.Elem = &embeddedType 107 typ.Size, err = strconv.Atoi(intz[0]) 108 if err != nil { 109 return Type{}, fmt.Errorf("abi: error parsing variable size: %v", err) 110 } 111 typ.Type = reflect.ArrayOf(typ.Size, embeddedType.Type) 112 typ.stringKind = embeddedType.stringKind + sliced 113 } else { 114 return Type{}, fmt.Errorf("invalid formatting of array type") 115 } 116 return typ, err 117 } 118 // parse the type and size of the abi-type. 119 matches := typeRegex.FindAllStringSubmatch(t, -1) 120 if len(matches) == 0 { 121 return Type{}, fmt.Errorf("invalid type '%v'", t) 122 } 123 parsedType := matches[0] 124 125 // varSize is the size of the variable 126 var varSize int 127 if len(parsedType[3]) > 0 { 128 var err error 129 varSize, err = strconv.Atoi(parsedType[2]) 130 if err != nil { 131 return Type{}, fmt.Errorf("abi: error parsing variable size: %v", err) 132 } 133 } else { 134 if parsedType[0] == "uint" || parsedType[0] == "int" { 135 // this should fail because it means that there's something wrong with 136 // the abi type (the compiler should always format it to the size...always) 137 return Type{}, fmt.Errorf("unsupported arg type: %s", t) 138 } 139 } 140 // varType is the parsed abi type 141 switch varType := parsedType[1]; varType { 142 case "int": 143 typ.Kind, typ.Type = reflectIntKindAndType(false, varSize) 144 typ.Size = varSize 145 typ.T = IntTy 146 case "uint": 147 typ.Kind, typ.Type = reflectIntKindAndType(true, varSize) 148 typ.Size = varSize 149 typ.T = UintTy 150 case "bool": 151 typ.Kind = reflect.Bool 152 typ.T = BoolTy 153 typ.Type = reflect.TypeOf(bool(false)) 154 case "address": 155 typ.Kind = reflect.Array 156 typ.Type = addressT 157 typ.Size = 20 158 typ.T = AddressTy 159 case "string": 160 typ.Kind = reflect.String 161 typ.Type = reflect.TypeOf("") 162 typ.T = StringTy 163 case "bytes": 164 if varSize == 0 { 165 typ.T = BytesTy 166 typ.Kind = reflect.Slice 167 typ.Type = reflect.SliceOf(reflect.TypeOf(byte(0))) 168 } else { 169 typ.T = FixedBytesTy 170 typ.Kind = reflect.Array 171 typ.Size = varSize 172 typ.Type = reflect.ArrayOf(varSize, reflect.TypeOf(byte(0))) 173 } 174 case "tuple": 175 var ( 176 fields []reflect.StructField 177 elems []*Type 178 names []string 179 expression string // canonical parameter expression 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 if ToCamelCase(c.Name) == "" { 188 return Type{}, errors.New("abi: purely anonymous or underscored field is not supported") 189 } 190 fields = append(fields, reflect.StructField{ 191 Name: ToCamelCase(c.Name), // reflect.StructOf will panic for any exported field. 192 Type: cType.Type, 193 Tag: reflect.StructTag("json:\"" + c.Name + "\""), 194 }) 195 elems = append(elems, &cType) 196 names = append(names, c.Name) 197 expression += cType.stringKind 198 if idx != len(components)-1 { 199 expression += "," 200 } 201 } 202 expression += ")" 203 typ.Kind = reflect.Struct 204 typ.Type = reflect.StructOf(fields) 205 typ.TupleElems = elems 206 typ.TupleRawNames = names 207 typ.T = TupleTy 208 typ.stringKind = expression 209 210 const structPrefix = "struct " 211 // After solidity 0.5.10, a new field of abi "internalType" 212 // is introduced. From that we can obtain the struct name 213 // user defined in the source code. 214 if internalType != "" && strings.HasPrefix(internalType, structPrefix) { 215 // Foo.Bar type definition is not allowed in golang, 216 // convert the format to FooBar 217 typ.TupleRawName = strings.Replace(internalType[len(structPrefix):], ".", "", -1) 218 } 219 220 case "function": 221 typ.Kind = reflect.Array 222 typ.T = FunctionTy 223 typ.Size = 24 224 typ.Type = reflect.ArrayOf(24, reflect.TypeOf(byte(0))) 225 default: 226 return Type{}, fmt.Errorf("unsupported arg type: %s", t) 227 } 228 229 return 230 } 231 232 // String implements Stringer 233 func (t Type) String() (out string) { 234 return t.stringKind 235 } 236 237 func (t Type) pack(v reflect.Value) ([]byte, error) { 238 // dereference pointer first if it's a pointer 239 v = indirect(v) 240 if err := typeCheck(t, v); err != nil { 241 return nil, err 242 } 243 244 switch t.T { 245 case SliceTy, ArrayTy: 246 var ret []byte 247 248 if t.requiresLengthPrefix() { 249 // append length 250 ret = append(ret, packNum(reflect.ValueOf(v.Len()))...) 251 } 252 253 // calculate offset if any 254 offset := 0 255 offsetReq := isDynamicType(*t.Elem) 256 if offsetReq { 257 offset = getTypeSize(*t.Elem) * v.Len() 258 } 259 var tail []byte 260 for i := 0; i < v.Len(); i++ { 261 val, err := t.Elem.pack(v.Index(i)) 262 if err != nil { 263 return nil, err 264 } 265 if !offsetReq { 266 ret = append(ret, val...) 267 continue 268 } 269 ret = append(ret, packNum(reflect.ValueOf(offset))...) 270 offset += len(val) 271 tail = append(tail, val...) 272 } 273 return append(ret, tail...), nil 274 case TupleTy: 275 // (T1,...,Tk) for k >= 0 and any types T1, …, Tk 276 // enc(X) = head(X(1)) ... head(X(k)) tail(X(1)) ... tail(X(k)) 277 // where X = (X(1), ..., X(k)) and head and tail are defined for Ti being a static 278 // type as 279 // head(X(i)) = enc(X(i)) and tail(X(i)) = "" (the empty string) 280 // and as 281 // head(X(i)) = enc(len(head(X(1)) ... head(X(k)) tail(X(1)) ... tail(X(i-1)))) 282 // tail(X(i)) = enc(X(i)) 283 // otherwise, i.e. if Ti is a dynamic type. 284 fieldmap, err := mapArgNamesToStructFields(t.TupleRawNames, v) 285 if err != nil { 286 return nil, err 287 } 288 // Calculate prefix occupied size. 289 offset := 0 290 for _, elem := range t.TupleElems { 291 offset += getTypeSize(*elem) 292 } 293 var ret, tail []byte 294 for i, elem := range t.TupleElems { 295 field := v.FieldByName(fieldmap[t.TupleRawNames[i]]) 296 if !field.IsValid() { 297 return nil, fmt.Errorf("field %s for tuple not found in the given struct", t.TupleRawNames[i]) 298 } 299 val, err := elem.pack(field) 300 if err != nil { 301 return nil, err 302 } 303 if isDynamicType(*elem) { 304 ret = append(ret, packNum(reflect.ValueOf(offset))...) 305 tail = append(tail, val...) 306 offset += len(val) 307 } else { 308 ret = append(ret, val...) 309 } 310 } 311 return append(ret, tail...), nil 312 313 default: 314 return packElement(t, v), nil 315 } 316 } 317 318 // requireLengthPrefix returns whether the type requires any sort of length 319 // prefixing. 320 func (t Type) requiresLengthPrefix() bool { 321 return t.T == StringTy || t.T == BytesTy || t.T == SliceTy 322 } 323 324 // isDynamicType returns true if the type is dynamic. 325 // The following types are called “dynamic”: 326 // * bytes 327 // * string 328 // * T[] for any T 329 // * T[k] for any dynamic T and any k >= 0 330 // * (T1,...,Tk) if Ti is dynamic for some 1 <= i <= k 331 func isDynamicType(t Type) bool { 332 if t.T == TupleTy { 333 for _, elem := range t.TupleElems { 334 if isDynamicType(*elem) { 335 return true 336 } 337 } 338 return false 339 } 340 return t.T == StringTy || t.T == BytesTy || t.T == SliceTy || (t.T == ArrayTy && isDynamicType(*t.Elem)) 341 } 342 343 // getTypeSize returns the size that this type needs to occupy. 344 // We distinguish static and dynamic types. Static types are encoded in-place 345 // and dynamic types are encoded at a separately allocated location after the 346 // current block. 347 // So for a static variable, the size returned represents the size that the 348 // variable actually occupies. 349 // For a dynamic variable, the returned size is fixed 32 bytes, which is used 350 // to store the location reference for actual value storage. 351 func getTypeSize(t Type) int { 352 if t.T == ArrayTy && !isDynamicType(*t.Elem) { 353 // Recursively calculate type size if it is a nested array 354 if t.Elem.T == ArrayTy { 355 return t.Size * getTypeSize(*t.Elem) 356 } 357 return t.Size * 32 358 } else if t.T == TupleTy && !isDynamicType(t) { 359 total := 0 360 for _, elem := range t.TupleElems { 361 total += getTypeSize(*elem) 362 } 363 return total 364 } 365 return 32 366 }