github.com/luckypickle/go-ethereum-vet@v1.14.2/accounts/abi/argument.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 "encoding/json" 21 "fmt" 22 "reflect" 23 "strings" 24 ) 25 26 // Argument holds the name of the argument and the corresponding type. 27 // Types are used when packing and testing arguments. 28 type Argument struct { 29 Name string 30 Type Type 31 Indexed bool // indexed is only used by events 32 } 33 34 type Arguments []Argument 35 36 // UnmarshalJSON implements json.Unmarshaler interface 37 func (argument *Argument) UnmarshalJSON(data []byte) error { 38 var extarg struct { 39 Name string 40 Type string 41 Indexed bool 42 } 43 err := json.Unmarshal(data, &extarg) 44 if err != nil { 45 return fmt.Errorf("argument json err: %v", err) 46 } 47 48 argument.Type, err = NewType(extarg.Type) 49 if err != nil { 50 return err 51 } 52 argument.Name = extarg.Name 53 argument.Indexed = extarg.Indexed 54 55 return nil 56 } 57 58 // LengthNonIndexed returns the number of arguments when not counting 'indexed' ones. Only events 59 // can ever have 'indexed' arguments, it should always be false on arguments for method input/output 60 func (arguments Arguments) LengthNonIndexed() int { 61 out := 0 62 for _, arg := range arguments { 63 if !arg.Indexed { 64 out++ 65 } 66 } 67 return out 68 } 69 70 // NonIndexed returns the arguments with indexed arguments filtered out 71 func (arguments Arguments) NonIndexed() Arguments { 72 var ret []Argument 73 for _, arg := range arguments { 74 if !arg.Indexed { 75 ret = append(ret, arg) 76 } 77 } 78 return ret 79 } 80 81 // isTuple returns true for non-atomic constructs, like (uint,uint) or uint[] 82 func (arguments Arguments) isTuple() bool { 83 return len(arguments) > 1 84 } 85 86 // Unpack performs the operation hexdata -> Go format 87 func (arguments Arguments) Unpack(v interface{}, data []byte) error { 88 89 // make sure the passed value is arguments pointer 90 if reflect.Ptr != reflect.ValueOf(v).Kind() { 91 return fmt.Errorf("abi: Unpack(non-pointer %T)", v) 92 } 93 marshalledValues, err := arguments.UnpackValues(data) 94 if err != nil { 95 return err 96 } 97 if arguments.isTuple() { 98 return arguments.unpackTuple(v, marshalledValues) 99 } 100 return arguments.unpackAtomic(v, marshalledValues) 101 } 102 103 func (arguments Arguments) unpackTuple(v interface{}, marshalledValues []interface{}) error { 104 105 var ( 106 value = reflect.ValueOf(v).Elem() 107 typ = value.Type() 108 kind = value.Kind() 109 ) 110 111 if err := requireUnpackKind(value, typ, kind, arguments); err != nil { 112 return err 113 } 114 115 // If the interface is a struct, get of abi->struct_field mapping 116 117 var abi2struct map[string]string 118 if kind == reflect.Struct { 119 var err error 120 abi2struct, err = mapAbiToStructFields(arguments, value) 121 if err != nil { 122 return err 123 } 124 } 125 for i, arg := range arguments.NonIndexed() { 126 127 reflectValue := reflect.ValueOf(marshalledValues[i]) 128 129 switch kind { 130 case reflect.Struct: 131 if structField, ok := abi2struct[arg.Name]; ok { 132 if err := set(value.FieldByName(structField), reflectValue, arg); err != nil { 133 return err 134 } 135 } 136 case reflect.Slice, reflect.Array: 137 if value.Len() < i { 138 return fmt.Errorf("abi: insufficient number of arguments for unpack, want %d, got %d", len(arguments), value.Len()) 139 } 140 v := value.Index(i) 141 if err := requireAssignable(v, reflectValue); err != nil { 142 return err 143 } 144 145 if err := set(v.Elem(), reflectValue, arg); err != nil { 146 return err 147 } 148 default: 149 return fmt.Errorf("abi:[2] cannot unmarshal tuple in to %v", typ) 150 } 151 } 152 return nil 153 } 154 155 // unpackAtomic unpacks ( hexdata -> go ) a single value 156 func (arguments Arguments) unpackAtomic(v interface{}, marshalledValues []interface{}) error { 157 if len(marshalledValues) != 1 { 158 return fmt.Errorf("abi: wrong length, expected single value, got %d", len(marshalledValues)) 159 } 160 161 elem := reflect.ValueOf(v).Elem() 162 kind := elem.Kind() 163 reflectValue := reflect.ValueOf(marshalledValues[0]) 164 165 var abi2struct map[string]string 166 if kind == reflect.Struct { 167 var err error 168 if abi2struct, err = mapAbiToStructFields(arguments, elem); err != nil { 169 return err 170 } 171 arg := arguments.NonIndexed()[0] 172 if structField, ok := abi2struct[arg.Name]; ok { 173 return set(elem.FieldByName(structField), reflectValue, arg) 174 } 175 return nil 176 } 177 178 return set(elem, reflectValue, arguments.NonIndexed()[0]) 179 180 } 181 182 // Computes the full size of an array; 183 // i.e. counting nested arrays, which count towards size for unpacking. 184 func getArraySize(arr *Type) int { 185 size := arr.Size 186 // Arrays can be nested, with each element being the same size 187 arr = arr.Elem 188 for arr.T == ArrayTy { 189 // Keep multiplying by elem.Size while the elem is an array. 190 size *= arr.Size 191 arr = arr.Elem 192 } 193 // Now we have the full array size, including its children. 194 return size 195 } 196 197 // UnpackValues can be used to unpack ABI-encoded hexdata according to the ABI-specification, 198 // without supplying a struct to unpack into. Instead, this method returns a list containing the 199 // values. An atomic argument will be a list with one element. 200 func (arguments Arguments) UnpackValues(data []byte) ([]interface{}, error) { 201 retval := make([]interface{}, 0, arguments.LengthNonIndexed()) 202 virtualArgs := 0 203 for index, arg := range arguments.NonIndexed() { 204 marshalledValue, err := toGoType((index+virtualArgs)*32, arg.Type, data) 205 if arg.Type.T == ArrayTy { 206 // If we have a static array, like [3]uint256, these are coded as 207 // just like uint256,uint256,uint256. 208 // This means that we need to add two 'virtual' arguments when 209 // we count the index from now on. 210 // 211 // Array values nested multiple levels deep are also encoded inline: 212 // [2][3]uint256: uint256,uint256,uint256,uint256,uint256,uint256 213 // 214 // Calculate the full array size to get the correct offset for the next argument. 215 // Decrement it by 1, as the normal index increment is still applied. 216 virtualArgs += getArraySize(&arg.Type) - 1 217 } 218 if err != nil { 219 return nil, err 220 } 221 retval = append(retval, marshalledValue) 222 } 223 return retval, nil 224 } 225 226 // PackValues performs the operation Go format -> Hexdata 227 // It is the semantic opposite of UnpackValues 228 func (arguments Arguments) PackValues(args []interface{}) ([]byte, error) { 229 return arguments.Pack(args...) 230 } 231 232 // Pack performs the operation Go format -> Hexdata 233 func (arguments Arguments) Pack(args ...interface{}) ([]byte, error) { 234 // Make sure arguments match up and pack them 235 abiArgs := arguments 236 if len(args) != len(abiArgs) { 237 return nil, fmt.Errorf("argument count mismatch: %d for %d", len(args), len(abiArgs)) 238 } 239 // variable input is the output appended at the end of packed 240 // output. This is used for strings and bytes types input. 241 var variableInput []byte 242 243 // input offset is the bytes offset for packed output 244 inputOffset := 0 245 for _, abiArg := range abiArgs { 246 if abiArg.Type.T == ArrayTy { 247 inputOffset += 32 * abiArg.Type.Size 248 } else { 249 inputOffset += 32 250 } 251 } 252 var ret []byte 253 for i, a := range args { 254 input := abiArgs[i] 255 // pack the input 256 packed, err := input.Type.pack(reflect.ValueOf(a)) 257 if err != nil { 258 return nil, err 259 } 260 // check for a slice type (string, bytes, slice) 261 if input.Type.requiresLengthPrefix() { 262 // calculate the offset 263 offset := inputOffset + len(variableInput) 264 // set the offset 265 ret = append(ret, packNum(reflect.ValueOf(offset))...) 266 // Append the packed output to the variable input. The variable input 267 // will be appended at the end of the input. 268 variableInput = append(variableInput, packed...) 269 } else { 270 // append the packed value to the input 271 ret = append(ret, packed...) 272 } 273 } 274 // append the variable input at the end of the packed input 275 ret = append(ret, variableInput...) 276 277 return ret, nil 278 } 279 280 // capitalise makes the first character of a string upper case, also removing any 281 // prefixing underscores from the variable names. 282 func capitalise(input string) string { 283 for len(input) > 0 && input[0] == '_' { 284 input = input[1:] 285 } 286 if len(input) == 0 { 287 return "" 288 } 289 return strings.ToUpper(input[:1]) + input[1:] 290 }