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