github.com/digdeepmining/go-atheios@v1.5.13-0.20180902133602-d5687a2e6f43/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 ) 25 26 const ( 27 IntTy byte = iota 28 UintTy 29 BoolTy 30 StringTy 31 SliceTy 32 AddressTy 33 FixedBytesTy 34 BytesTy 35 HashTy 36 FixedpointTy 37 FunctionTy 38 ) 39 40 // Type is the reflection of the supported argument type 41 type Type struct { 42 IsSlice, IsArray bool 43 SliceSize int 44 45 Elem *Type 46 47 Kind reflect.Kind 48 Type reflect.Type 49 Size int 50 T byte // Our own type checking 51 52 stringKind string // holds the unparsed string for deriving signatures 53 } 54 55 var ( 56 // fullTypeRegex parses the abi types 57 // 58 // Types can be in the format of: 59 // 60 // Input = Type [ "[" [ Number ] "]" ] Name . 61 // Type = [ "u" ] "int" [ Number ] [ x ] [ Number ]. 62 // 63 // Examples: 64 // 65 // string int uint fixed 66 // string32 int8 uint8 uint[] 67 // address int256 uint256 fixed128x128[2] 68 fullTypeRegex = regexp.MustCompile(`([a-zA-Z0-9]+)(\[([0-9]*)\])?`) 69 // typeRegex parses the abi sub types 70 typeRegex = regexp.MustCompile("([a-zA-Z]+)(([0-9]+)(x([0-9]+))?)?") 71 ) 72 73 // NewType creates a new reflection type of abi type given in t. 74 func NewType(t string) (typ Type, err error) { 75 res := fullTypeRegex.FindAllStringSubmatch(t, -1)[0] 76 // check if type is slice and parse type. 77 switch { 78 case res[3] != "": 79 // err is ignored. Already checked for number through the regexp 80 typ.SliceSize, _ = strconv.Atoi(res[3]) 81 typ.IsArray = true 82 case res[2] != "": 83 typ.IsSlice, typ.SliceSize = true, -1 84 case res[0] == "": 85 return Type{}, fmt.Errorf("abi: type parse error: %s", t) 86 } 87 if typ.IsArray || typ.IsSlice { 88 sliceType, err := NewType(res[1]) 89 if err != nil { 90 return Type{}, err 91 } 92 typ.Elem = &sliceType 93 typ.stringKind = sliceType.stringKind + t[len(res[1]):] 94 // Although we know that this is an array, we cannot return 95 // as we don't know the type of the element, however, if it 96 // is still an array, then don't determine the type. 97 if typ.Elem.IsArray || typ.Elem.IsSlice { 98 return typ, nil 99 } 100 } 101 102 // parse the type and size of the abi-type. 103 parsedType := typeRegex.FindAllStringSubmatch(res[1], -1)[0] 104 // varSize is the size of the variable 105 var varSize int 106 if len(parsedType[3]) > 0 { 107 var err error 108 varSize, err = strconv.Atoi(parsedType[2]) 109 if err != nil { 110 return Type{}, fmt.Errorf("abi: error parsing variable size: %v", err) 111 } 112 } 113 // varType is the parsed abi type 114 varType := parsedType[1] 115 // substitute canonical integer 116 if varSize == 0 && (varType == "int" || varType == "uint") { 117 varSize = 256 118 t += "256" 119 } 120 121 // only set stringKind if not array or slice, as for those, 122 // the correct string type has been set 123 if !(typ.IsArray || typ.IsSlice) { 124 typ.stringKind = t 125 } 126 127 switch varType { 128 case "int": 129 typ.Kind = reflectIntKind(false, varSize) 130 typ.Type = big_t 131 typ.Size = varSize 132 typ.T = IntTy 133 case "uint": 134 typ.Kind = reflectIntKind(true, varSize) 135 typ.Type = ubig_t 136 typ.Size = varSize 137 typ.T = UintTy 138 case "bool": 139 typ.Kind = reflect.Bool 140 typ.T = BoolTy 141 case "address": 142 typ.Kind = reflect.Array 143 typ.Type = address_t 144 typ.Size = 20 145 typ.T = AddressTy 146 case "string": 147 typ.Kind = reflect.String 148 typ.Size = -1 149 typ.T = StringTy 150 case "bytes": 151 sliceType, _ := NewType("uint8") 152 typ.Elem = &sliceType 153 if varSize == 0 { 154 typ.IsSlice = true 155 typ.T = BytesTy 156 typ.SliceSize = -1 157 } else { 158 typ.IsArray = true 159 typ.T = FixedBytesTy 160 typ.SliceSize = varSize 161 } 162 case "function": 163 sliceType, _ := NewType("uint8") 164 typ.Elem = &sliceType 165 typ.IsArray = true 166 typ.T = FunctionTy 167 typ.SliceSize = 24 168 default: 169 return Type{}, fmt.Errorf("unsupported arg type: %s", t) 170 } 171 172 return 173 } 174 175 // String implements Stringer 176 func (t Type) String() (out string) { 177 return t.stringKind 178 } 179 180 func (t Type) pack(v reflect.Value) ([]byte, error) { 181 // dereference pointer first if it's a pointer 182 v = indirect(v) 183 184 if err := typeCheck(t, v); err != nil { 185 return nil, err 186 } 187 188 if (t.IsSlice || t.IsArray) && t.T != BytesTy && t.T != FixedBytesTy && t.T != FunctionTy { 189 var packed []byte 190 191 for i := 0; i < v.Len(); i++ { 192 val, err := t.Elem.pack(v.Index(i)) 193 if err != nil { 194 return nil, err 195 } 196 packed = append(packed, val...) 197 } 198 if t.IsSlice { 199 return packBytesSlice(packed, v.Len()), nil 200 } else if t.IsArray { 201 return packed, nil 202 } 203 } 204 205 return packElement(t, v), nil 206 } 207 208 // requireLengthPrefix returns whether the type requires any sort of length 209 // prefixing. 210 func (t Type) requiresLengthPrefix() bool { 211 return t.T != FixedBytesTy && (t.T == StringTy || t.T == BytesTy || t.IsSlice) 212 }