github.com/n1ghtfa1l/go-vnt@v0.6.4-alpha.6/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 "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 MappingTy 36 AddressTy 37 FixedBytesTy 38 BytesTy 39 HashTy 40 FixedPointTy 41 FunctionTy 42 StructTy 43 ) 44 45 // Type is the reflection of the supported argument type 46 type Type struct { 47 // Used by mapping type 48 Key *Type 49 50 Elem *Type 51 52 Kind reflect.Kind 53 Type reflect.Type 54 Size int 55 T byte // Our own type checking 56 57 stringKind string // holds the unparsed string for deriving signatures 58 } 59 60 var ( 61 // typeRegex parses the abi sub types 62 typeRegex = regexp.MustCompile("([a-zA-Z]+)(([0-9]+)(x([0-9]+))?)?") 63 ) 64 65 // NewType creates a new reflection type of abi type given in t. 66 func NewType(t string) (typ Type, err error) { 67 // check that array brackets are equal if they exist 68 if strings.Count(t, "[") != strings.Count(t, "]") { 69 return Type{}, fmt.Errorf("invalid arg type in abi") 70 } 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 i := strings.LastIndex(t, "[") 78 // recursively embed the type 79 embeddedType, err := NewType(t[:i]) 80 if err != nil { 81 return Type{}, err 82 } 83 // grab the last cell and create a type from there 84 sliced := t[i:] 85 // grab the slice size with regexp 86 re := regexp.MustCompile("[0-9]+") 87 intz := re.FindAllString(sliced, -1) 88 89 if len(intz) == 0 { 90 // is a slice 91 typ.T = SliceTy 92 typ.Kind = reflect.Slice 93 typ.Elem = &embeddedType 94 typ.Type = reflect.SliceOf(embeddedType.Type) 95 } else if len(intz) == 1 { 96 // is a array 97 typ.T = ArrayTy 98 typ.Kind = reflect.Array 99 typ.Elem = &embeddedType 100 typ.Size, err = strconv.Atoi(intz[0]) 101 if err != nil { 102 return Type{}, fmt.Errorf("abi: error parsing variable size: %v", err) 103 } 104 typ.Type = reflect.ArrayOf(typ.Size, embeddedType.Type) 105 } else { 106 return Type{}, fmt.Errorf("invalid formatting of array type") 107 } 108 return typ, err 109 } 110 111 // parse the type and size of the abi-type. 112 parsedType := typeRegex.FindAllStringSubmatch(t, -1)[0] 113 // varSize is the size of the variable 114 var varSize int 115 if len(parsedType[3]) > 0 { 116 var err error 117 varSize, err = strconv.Atoi(parsedType[2]) 118 if err != nil { 119 return Type{}, fmt.Errorf("abi: error parsing variable size: %v", err) 120 } 121 } else { 122 if parsedType[0] == "uint" || parsedType[0] == "int" { 123 // this should fail because it means that there's something wrong with 124 // the abi type (the compiler should always format it to the size...always) 125 return Type{}, fmt.Errorf("unsupported arg type: %s", t) 126 } 127 } 128 // varType is the parsed abi type 129 switch varType := parsedType[1]; varType { 130 case "int": 131 typ.Kind, typ.Type = reflectIntKindAndType(false, varSize) 132 typ.Size = varSize 133 typ.T = IntTy 134 case "uint": 135 typ.Kind, typ.Type = reflectIntKindAndType(true, varSize) 136 typ.Size = varSize 137 typ.T = UintTy 138 case "bool": 139 typ.Kind = reflect.Bool 140 typ.T = BoolTy 141 typ.Type = reflect.TypeOf(bool(false)) 142 case "address": 143 typ.Kind = reflect.Array 144 typ.Type = addressT 145 typ.Size = 20 146 typ.T = AddressTy 147 case "string": 148 typ.Kind = reflect.String 149 typ.Type = reflect.TypeOf("") 150 typ.T = StringTy 151 case "bytes": 152 if varSize == 0 { 153 typ.T = BytesTy 154 typ.Kind = reflect.Slice 155 typ.Type = reflect.SliceOf(reflect.TypeOf(byte(0))) 156 } else { 157 typ.T = FixedBytesTy 158 typ.Kind = reflect.Array 159 typ.Size = varSize 160 typ.Type = reflect.ArrayOf(varSize, reflect.TypeOf(byte(0))) 161 } 162 case "function": 163 typ.Kind = reflect.Array 164 typ.T = FunctionTy 165 typ.Size = 24 166 typ.Type = reflect.ArrayOf(24, reflect.TypeOf(byte(0))) 167 case "mapping": 168 typ.T = MappingTy 169 case "array": 170 typ.T = ArrayTy 171 case "struct": 172 typ.T = StructTy 173 default: 174 return Type{}, fmt.Errorf("unsupported arg type: %s", t) 175 } 176 177 return 178 } 179 180 // String implements Stringer 181 func (t Type) String() (out string) { 182 return t.stringKind 183 } 184 185 func (t Type) pack(v reflect.Value) ([]byte, error) { 186 // dereference pointer first if it's a pointer 187 v = indirect(v) 188 if err := typeCheck(t, v); err != nil { 189 return nil, err 190 } 191 if t.T == SliceTy || t.T == ArrayTy { 192 var packed []byte 193 for i := 0; i < v.Len(); i++ { 194 val, err := t.Elem.pack(v.Index(i)) 195 if err != nil { 196 return nil, err 197 } 198 packed = append(packed, val...) 199 } 200 if t.T == SliceTy { 201 return packBytesSlice(packed, v.Len()), nil 202 } else if t.T == ArrayTy { 203 return packed, nil 204 } 205 } 206 return packElement(t, v), nil 207 } 208 209 // requireLengthPrefix returns whether the type requires any sort of length 210 // prefixing. 211 func (t Type) requiresLengthPrefix() bool { 212 return t.T == StringTy || t.T == BytesTy || t.T == SliceTy 213 }