github.com/smalaichami/go-bowhead@v0.0.0-20180311002552-16302db95eaa/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 // If the output interface is a struct, make sure names don't collide 115 if kind == reflect.Struct { 116 exists := make(map[string]bool) 117 for _, arg := range arguments { 118 field := capitalise(arg.Name) 119 if field == "" { 120 return fmt.Errorf("abi: purely underscored output cannot unpack to struct") 121 } 122 if exists[field] { 123 return fmt.Errorf("abi: multiple outputs mapping to the same struct field '%s'", field) 124 } 125 exists[field] = true 126 } 127 } 128 for i, arg := range arguments.NonIndexed() { 129 130 reflectValue := reflect.ValueOf(marshalledValues[i]) 131 132 switch kind { 133 case reflect.Struct: 134 name := capitalise(arg.Name) 135 for j := 0; j < typ.NumField(); j++ { 136 // TODO read tags: `abi:"fieldName"` 137 if typ.Field(j).Name == name { 138 if err := set(value.Field(j), reflectValue, arg); err != nil { 139 return err 140 } 141 } 142 } 143 case reflect.Slice, reflect.Array: 144 if value.Len() < i { 145 return fmt.Errorf("abi: insufficient number of arguments for unpack, want %d, got %d", len(arguments), value.Len()) 146 } 147 v := value.Index(i) 148 if err := requireAssignable(v, reflectValue); err != nil { 149 return err 150 } 151 152 if err := set(v.Elem(), reflectValue, arg); err != nil { 153 return err 154 } 155 default: 156 return fmt.Errorf("abi:[2] cannot unmarshal tuple in to %v", typ) 157 } 158 } 159 return nil 160 } 161 162 // unpackAtomic unpacks ( hexdata -> go ) a single value 163 func (arguments Arguments) unpackAtomic(v interface{}, marshalledValues []interface{}) error { 164 if len(marshalledValues) != 1 { 165 return fmt.Errorf("abi: wrong length, expected single value, got %d", len(marshalledValues)) 166 } 167 elem := reflect.ValueOf(v).Elem() 168 reflectValue := reflect.ValueOf(marshalledValues[0]) 169 return set(elem, reflectValue, arguments.NonIndexed()[0]) 170 } 171 172 // Computes the full size of an array; 173 // i.e. counting nested arrays, which count towards size for unpacking. 174 func getArraySize(arr *Type) int { 175 size := arr.Size 176 // Arrays can be nested, with each element being the same size 177 arr = arr.Elem 178 for arr.T == ArrayTy { 179 // Keep multiplying by elem.Size while the elem is an array. 180 size *= arr.Size 181 arr = arr.Elem 182 } 183 // Now we have the full array size, including its children. 184 return size 185 } 186 187 // UnpackValues can be used to unpack ABI-encoded hexdata according to the ABI-specification, 188 // without supplying a struct to unpack into. Instead, this method returns a list containing the 189 // values. An atomic argument will be a list with one element. 190 func (arguments Arguments) UnpackValues(data []byte) ([]interface{}, error) { 191 retval := make([]interface{}, 0, arguments.LengthNonIndexed()) 192 virtualArgs := 0 193 for index, arg := range arguments.NonIndexed() { 194 marshalledValue, err := toGoType((index+virtualArgs)*32, arg.Type, data) 195 if arg.Type.T == ArrayTy { 196 // If we have a static array, like [3]uint256, these are coded as 197 // just like uint256,uint256,uint256. 198 // This means that we need to add two 'virtual' arguments when 199 // we count the index from now on. 200 // 201 // Array values nested multiple levels deep are also encoded inline: 202 // [2][3]uint256: uint256,uint256,uint256,uint256,uint256,uint256 203 // 204 // Calculate the full array size to get the correct offset for the next argument. 205 // Decrement it by 1, as the normal index increment is still applied. 206 virtualArgs += getArraySize(&arg.Type) - 1 207 } 208 if err != nil { 209 return nil, err 210 } 211 retval = append(retval, marshalledValue) 212 } 213 return retval, nil 214 } 215 216 // PackValues performs the operation Go format -> Hexdata 217 // It is the semantic opposite of UnpackValues 218 func (arguments Arguments) PackValues(args []interface{}) ([]byte, error) { 219 return arguments.Pack(args...) 220 } 221 222 // Pack performs the operation Go format -> Hexdata 223 func (arguments Arguments) Pack(args ...interface{}) ([]byte, error) { 224 // Make sure arguments match up and pack them 225 abiArgs := arguments 226 if len(args) != len(abiArgs) { 227 return nil, fmt.Errorf("argument count mismatch: %d for %d", len(args), len(abiArgs)) 228 } 229 // variable input is the output appended at the end of packed 230 // output. This is used for strings and bytes types input. 231 var variableInput []byte 232 233 // input offset is the bytes offset for packed output 234 inputOffset := 0 235 for _, abiArg := range abiArgs { 236 if abiArg.Type.T == ArrayTy { 237 inputOffset += 32 * abiArg.Type.Size 238 } else { 239 inputOffset += 32 240 } 241 } 242 var ret []byte 243 for i, a := range args { 244 input := abiArgs[i] 245 // pack the input 246 packed, err := input.Type.pack(reflect.ValueOf(a)) 247 if err != nil { 248 return nil, err 249 } 250 // check for a slice type (string, bytes, slice) 251 if input.Type.requiresLengthPrefix() { 252 // calculate the offset 253 offset := inputOffset + len(variableInput) 254 // set the offset 255 ret = append(ret, packNum(reflect.ValueOf(offset))...) 256 // Append the packed output to the variable input. The variable input 257 // will be appended at the end of the input. 258 variableInput = append(variableInput, packed...) 259 } else { 260 // append the packed value to the input 261 ret = append(ret, packed...) 262 } 263 } 264 // append the variable input at the end of the packed input 265 ret = append(ret, variableInput...) 266 267 return ret, nil 268 } 269 270 // capitalise makes the first character of a string upper case, also removing any 271 // prefixing underscores from the variable names. 272 func capitalise(input string) string { 273 for len(input) > 0 && input[0] == '_' { 274 input = input[1:] 275 } 276 if len(input) == 0 { 277 return "" 278 } 279 return strings.ToUpper(input[:1]) + input[1:] 280 }