github.com/SmartMeshFoundation/Spectrum@v0.0.0-20220621030607-452a266fee1e/accounts/abi/type.go (about) 1 // Copyright 2015 The Spectrum Authors 2 // This file is part of the Spectrum library. 3 // 4 // The Spectrum 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 Spectrum 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 Spectrum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package abi 18 19 import ( 20 "fmt" 21 "reflect" 22 "regexp" 23 "strconv" 24 "strings" 25 ) 26 27 // Type enumerator 28 const ( 29 IntTy byte = iota 30 UintTy 31 BoolTy 32 StringTy 33 SliceTy 34 ArrayTy 35 AddressTy 36 FixedBytesTy 37 BytesTy 38 HashTy 39 FixedPointTy 40 FunctionTy 41 UserTy 42 ) 43 44 // Type is the reflection of the supported argument type 45 type Type struct { 46 Elem *Type 47 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 56 var ( 57 // typeRegex parses the abi sub types 58 typeRegex = regexp.MustCompile("([a-zA-Z]+)(([0-9]+)(x([0-9]+))?)?") 59 ) 60 61 // NewType creates a new reflection type of abi type given in t. 62 func NewType(t string) (typ Type, err error) { 63 // check that array brackets are equal if they exist 64 if strings.Count(t, "[") != strings.Count(t, "]") { 65 return Type{}, fmt.Errorf("invalid arg type in abi") 66 } 67 68 typ.stringKind = t 69 70 // if there are brackets, get ready to go into slice/array mode and 71 // recursively create the type 72 if strings.Count(t, "[") != 0 { 73 i := strings.LastIndex(t, "[") 74 // recursively embed the type 75 embeddedType, err := NewType(t[:i]) 76 if err != nil { 77 return Type{}, err 78 } 79 // grab the last cell and create a type from there 80 sliced := t[i:] 81 // grab the slice size with regexp 82 re := regexp.MustCompile("[0-9]+") 83 intz := re.FindAllString(sliced, -1) 84 85 if len(intz) == 0 { 86 // is a slice 87 typ.T = SliceTy 88 typ.Kind = reflect.Slice 89 typ.Elem = &embeddedType 90 typ.Type = reflect.SliceOf(embeddedType.Type) 91 } else if len(intz) == 1 { 92 // is a array 93 typ.T = ArrayTy 94 typ.Kind = reflect.Array 95 typ.Elem = &embeddedType 96 typ.Size, err = strconv.Atoi(intz[0]) 97 if err != nil { 98 return Type{}, fmt.Errorf("abi: error parsing variable size: %v", err) 99 } 100 typ.Type = reflect.ArrayOf(typ.Size, embeddedType.Type) 101 } else { 102 return Type{}, fmt.Errorf("invalid formatting of array type") 103 } 104 return typ, err 105 } 106 // parse the type and size of the abi-type. 107 parsedType := typeRegex.FindAllStringSubmatch(t, -1)[0] 108 // varSize is the size of the variable 109 var varSize int 110 if len(parsedType[3]) > 0 { 111 var err error 112 varSize, err = strconv.Atoi(parsedType[2]) 113 if err != nil { 114 return Type{}, fmt.Errorf("abi: error parsing variable size: %v", err) 115 } 116 } else { 117 if parsedType[0] == "uint" || parsedType[0] == "int" { 118 // this should fail because it means that there's something wrong with 119 // the abi type (the compiler should always format it to the size...always) 120 return Type{}, fmt.Errorf("unsupported arg type: %s", t) 121 } 122 } 123 // varType is the parsed abi type 124 switch varType := parsedType[1]; varType { 125 case "int": 126 typ.Kind, typ.Type = reflectIntKindAndType(false, varSize) 127 typ.Size = varSize 128 typ.T = IntTy 129 case "uint": 130 typ.Kind, typ.Type = reflectIntKindAndType(true, varSize) 131 typ.Size = varSize 132 typ.T = UintTy 133 case "bool": 134 typ.Kind = reflect.Bool 135 typ.T = BoolTy 136 typ.Type = reflect.TypeOf(bool(false)) 137 case "address": 138 typ.Kind = reflect.Array 139 typ.Type = address_t 140 typ.Size = 20 141 typ.T = AddressTy 142 case "string": 143 typ.Kind = reflect.String 144 typ.Type = reflect.TypeOf("") 145 typ.T = StringTy 146 case "bytes": 147 if varSize == 0 { 148 typ.T = BytesTy 149 typ.Kind = reflect.Slice 150 typ.Type = reflect.SliceOf(reflect.TypeOf(byte(0))) 151 } else { 152 typ.T = FixedBytesTy 153 typ.Kind = reflect.Array 154 typ.Size = varSize 155 typ.Type = reflect.ArrayOf(varSize, reflect.TypeOf(byte(0))) 156 } 157 case "function": 158 typ.Kind = reflect.Array 159 typ.T = FunctionTy 160 typ.Size = 24 161 typ.Type = reflect.ArrayOf(24, reflect.TypeOf(byte(0))) 162 default: 163 //return Type{}, fmt.Errorf("unsupported arg type: %s", t) 164 //user defined types 165 typ.Kind = reflect.Struct 166 typ.T = UserTy 167 typ.Size = -1 168 typ.Type = reflect.TypeOf(struct{}{}) 169 } 170 171 return 172 } 173 174 // String implements Stringer 175 func (t Type) String() (out string) { 176 return t.stringKind 177 } 178 179 func (t Type) pack(v reflect.Value) ([]byte, error) { 180 // dereference pointer first if it's a pointer 181 v = indirect(v) 182 183 if err := typeCheck(t, v); err != nil { 184 return nil, err 185 } 186 187 if t.T == SliceTy || t.T == ArrayTy { 188 var packed []byte 189 190 for i := 0; i < v.Len(); i++ { 191 val, err := t.Elem.pack(v.Index(i)) 192 if err != nil { 193 return nil, err 194 } 195 packed = append(packed, val...) 196 } 197 if t.T == SliceTy { 198 return packBytesSlice(packed, v.Len()), nil 199 } else if t.T == ArrayTy { 200 return packed, nil 201 } 202 } 203 return packElement(t, v), nil 204 } 205 206 // requireLengthPrefix returns whether the type requires any sort of length 207 // prefixing. 208 func (t Type) requiresLengthPrefix() bool { 209 return t.T == StringTy || t.T == BytesTy || t.T == SliceTy 210 }