github.com/waltonchain/waltonchain_gwtc_src@v1.1.4-0.20201225072101-8a298c95a819/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-wtc 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-wtc 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, typ.Type = reflectIntKindAndType(false, varSize) 130 typ.Size = varSize 131 typ.T = IntTy 132 case "uint": 133 typ.Kind, typ.Type = reflectIntKindAndType(true, varSize) 134 typ.Size = varSize 135 typ.T = UintTy 136 case "bool": 137 typ.Kind = reflect.Bool 138 typ.T = BoolTy 139 case "address": 140 typ.Kind = reflect.Array 141 typ.Type = address_t 142 typ.Size = 20 143 typ.T = AddressTy 144 case "string": 145 typ.Kind = reflect.String 146 typ.Size = -1 147 typ.T = StringTy 148 case "bytes": 149 sliceType, _ := NewType("uint8") 150 typ.Elem = &sliceType 151 if varSize == 0 { 152 typ.IsSlice = true 153 typ.T = BytesTy 154 typ.SliceSize = -1 155 } else { 156 typ.IsArray = true 157 typ.T = FixedBytesTy 158 typ.SliceSize = varSize 159 } 160 case "function": 161 sliceType, _ := NewType("uint8") 162 typ.Elem = &sliceType 163 typ.IsArray = true 164 typ.T = FunctionTy 165 typ.SliceSize = 24 166 default: 167 return Type{}, fmt.Errorf("unsupported arg type: %s", t) 168 } 169 170 return 171 } 172 173 // String implements Stringer 174 func (t Type) String() (out string) { 175 return t.stringKind 176 } 177 178 func (t Type) pack(v reflect.Value) ([]byte, error) { 179 // dereference pointer first if it's a pointer 180 v = indirect(v) 181 182 if err := typeCheck(t, v); err != nil { 183 return nil, err 184 } 185 186 if (t.IsSlice || t.IsArray) && t.T != BytesTy && t.T != FixedBytesTy && t.T != FunctionTy { 187 var packed []byte 188 189 for i := 0; i < v.Len(); i++ { 190 val, err := t.Elem.pack(v.Index(i)) 191 if err != nil { 192 return nil, err 193 } 194 packed = append(packed, val...) 195 } 196 if t.IsSlice { 197 return packBytesSlice(packed, v.Len()), nil 198 } else if t.IsArray { 199 return packed, nil 200 } 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 != FixedBytesTy && (t.T == StringTy || t.T == BytesTy || t.IsSlice) 210 }