github.com/sberex/go-sberex@v1.8.2-0.20181113200658-ed96ac38f7d7/accounts/abi/type.go (about) 1 // This file is part of the go-sberex library. The go-sberex library is 2 // free software: you can redistribute it and/or modify it under the terms 3 // of the GNU Lesser General Public License as published by the Free 4 // Software Foundation, either version 3 of the License, or (at your option) 5 // any later version. 6 // 7 // The go-sberex library is distributed in the hope that it will be useful, 8 // but WITHOUT ANY WARRANTY; without even the implied warranty of 9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 10 // General Public License <http://www.gnu.org/licenses/> for more details. 11 12 package abi 13 14 import ( 15 "fmt" 16 "reflect" 17 "regexp" 18 "strconv" 19 "strings" 20 ) 21 22 // Type enumerator 23 const ( 24 IntTy byte = iota 25 UintTy 26 BoolTy 27 StringTy 28 SliceTy 29 ArrayTy 30 AddressTy 31 FixedBytesTy 32 BytesTy 33 HashTy 34 FixedPointTy 35 FunctionTy 36 ) 37 38 // Type is the reflection of the supported argument type 39 type Type struct { 40 Elem *Type 41 42 Kind reflect.Kind 43 Type reflect.Type 44 Size int 45 T byte // Our own type checking 46 47 stringKind string // holds the unparsed string for deriving signatures 48 } 49 50 var ( 51 // typeRegex parses the abi sub types 52 typeRegex = regexp.MustCompile("([a-zA-Z]+)(([0-9]+)(x([0-9]+))?)?") 53 ) 54 55 // NewType creates a new reflection type of abi type given in t. 56 func NewType(t string) (typ Type, err error) { 57 // check that array brackets are equal if they exist 58 if strings.Count(t, "[") != strings.Count(t, "]") { 59 return Type{}, fmt.Errorf("invalid arg type in abi") 60 } 61 62 typ.stringKind = t 63 64 // if there are brackets, get ready to go into slice/array mode and 65 // recursively create the type 66 if strings.Count(t, "[") != 0 { 67 i := strings.LastIndex(t, "[") 68 // recursively embed the type 69 embeddedType, err := NewType(t[:i]) 70 if err != nil { 71 return Type{}, err 72 } 73 // grab the last cell and create a type from there 74 sliced := t[i:] 75 // grab the slice size with regexp 76 re := regexp.MustCompile("[0-9]+") 77 intz := re.FindAllString(sliced, -1) 78 79 if len(intz) == 0 { 80 // is a slice 81 typ.T = SliceTy 82 typ.Kind = reflect.Slice 83 typ.Elem = &embeddedType 84 typ.Type = reflect.SliceOf(embeddedType.Type) 85 } else if len(intz) == 1 { 86 // is a array 87 typ.T = ArrayTy 88 typ.Kind = reflect.Array 89 typ.Elem = &embeddedType 90 typ.Size, err = strconv.Atoi(intz[0]) 91 if err != nil { 92 return Type{}, fmt.Errorf("abi: error parsing variable size: %v", err) 93 } 94 typ.Type = reflect.ArrayOf(typ.Size, embeddedType.Type) 95 } else { 96 return Type{}, fmt.Errorf("invalid formatting of array type") 97 } 98 return typ, err 99 } 100 // parse the type and size of the abi-type. 101 parsedType := typeRegex.FindAllStringSubmatch(t, -1)[0] 102 // varSize is the size of the variable 103 var varSize int 104 if len(parsedType[3]) > 0 { 105 var err error 106 varSize, err = strconv.Atoi(parsedType[2]) 107 if err != nil { 108 return Type{}, fmt.Errorf("abi: error parsing variable size: %v", err) 109 } 110 } else { 111 if parsedType[0] == "uint" || parsedType[0] == "int" { 112 // this should fail because it means that there's something wrong with 113 // the abi type (the compiler should always format it to the size...always) 114 return Type{}, fmt.Errorf("unsupported arg type: %s", t) 115 } 116 } 117 // varType is the parsed abi type 118 switch varType := parsedType[1]; varType { 119 case "int": 120 typ.Kind, typ.Type = reflectIntKindAndType(false, varSize) 121 typ.Size = varSize 122 typ.T = IntTy 123 case "uint": 124 typ.Kind, typ.Type = reflectIntKindAndType(true, varSize) 125 typ.Size = varSize 126 typ.T = UintTy 127 case "bool": 128 typ.Kind = reflect.Bool 129 typ.T = BoolTy 130 typ.Type = reflect.TypeOf(bool(false)) 131 case "address": 132 typ.Kind = reflect.Array 133 typ.Type = address_t 134 typ.Size = 20 135 typ.T = AddressTy 136 case "string": 137 typ.Kind = reflect.String 138 typ.Type = reflect.TypeOf("") 139 typ.T = StringTy 140 case "bytes": 141 if varSize == 0 { 142 typ.T = BytesTy 143 typ.Kind = reflect.Slice 144 typ.Type = reflect.SliceOf(reflect.TypeOf(byte(0))) 145 } else { 146 typ.T = FixedBytesTy 147 typ.Kind = reflect.Array 148 typ.Size = varSize 149 typ.Type = reflect.ArrayOf(varSize, reflect.TypeOf(byte(0))) 150 } 151 case "function": 152 typ.Kind = reflect.Array 153 typ.T = FunctionTy 154 typ.Size = 24 155 typ.Type = reflect.ArrayOf(24, reflect.TypeOf(byte(0))) 156 default: 157 return Type{}, fmt.Errorf("unsupported arg type: %s", t) 158 } 159 160 return 161 } 162 163 // String implements Stringer 164 func (t Type) String() (out string) { 165 return t.stringKind 166 } 167 168 func (t Type) pack(v reflect.Value) ([]byte, error) { 169 // dereference pointer first if it's a pointer 170 v = indirect(v) 171 172 if err := typeCheck(t, v); err != nil { 173 return nil, err 174 } 175 176 if t.T == SliceTy || t.T == ArrayTy { 177 var packed []byte 178 179 for i := 0; i < v.Len(); i++ { 180 val, err := t.Elem.pack(v.Index(i)) 181 if err != nil { 182 return nil, err 183 } 184 packed = append(packed, val...) 185 } 186 if t.T == SliceTy { 187 return packBytesSlice(packed, v.Len()), nil 188 } else if t.T == ArrayTy { 189 return packed, nil 190 } 191 } 192 return packElement(t, v), nil 193 } 194 195 // requireLengthPrefix returns whether the type requires any sort of length 196 // prefixing. 197 func (t Type) requiresLengthPrefix() bool { 198 return t.T == StringTy || t.T == BytesTy || t.T == SliceTy 199 }