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