github.com/aquanetwork/aquachain@v1.7.8/aqua/accounts/abi/argument.go (about) 1 // Copyright 2015 The aquachain Authors 2 // This file is part of the aquachain library. 3 // 4 // The aquachain 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 aquachain 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 aquachain 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 // UnpackValues can be used to unpack ABI-encoded hexdata according to the ABI-specification, 173 // without supplying a struct to unpack into. Instead, this method returns a list containing the 174 // values. An atomic argument will be a list with one element. 175 func (arguments Arguments) UnpackValues(data []byte) ([]interface{}, error) { 176 retval := make([]interface{}, 0, arguments.LengthNonIndexed()) 177 virtualArgs := 0 178 for index, arg := range arguments.NonIndexed() { 179 marshalledValue, err := toGoType((index+virtualArgs)*32, arg.Type, data) 180 if arg.Type.T == ArrayTy { 181 // If we have a static array, like [3]uint256, these are coded as 182 // just like uint256,uint256,uint256. 183 // This means that we need to add two 'virtual' arguments when 184 // we count the index from now on 185 186 virtualArgs += arg.Type.Size - 1 187 } 188 if err != nil { 189 return nil, err 190 } 191 retval = append(retval, marshalledValue) 192 } 193 return retval, nil 194 } 195 196 // PackValues performs the operation Go format -> Hexdata 197 // It is the semantic opposite of UnpackValues 198 func (arguments Arguments) PackValues(args []interface{}) ([]byte, error) { 199 return arguments.Pack(args...) 200 } 201 202 // Pack performs the operation Go format -> Hexdata 203 func (arguments Arguments) Pack(args ...interface{}) ([]byte, error) { 204 // Make sure arguments match up and pack them 205 abiArgs := arguments 206 if len(args) != len(abiArgs) { 207 return nil, fmt.Errorf("argument count mismatch: %d for %d", len(args), len(abiArgs)) 208 } 209 // variable input is the output appended at the end of packed 210 // output. This is used for strings and bytes types input. 211 var variableInput []byte 212 213 // input offset is the bytes offset for packed output 214 inputOffset := 0 215 for _, abiArg := range abiArgs { 216 if abiArg.Type.T == ArrayTy { 217 inputOffset += 32 * abiArg.Type.Size 218 } else { 219 inputOffset += 32 220 } 221 } 222 var ret []byte 223 for i, a := range args { 224 input := abiArgs[i] 225 // pack the input 226 packed, err := input.Type.pack(reflect.ValueOf(a)) 227 if err != nil { 228 return nil, err 229 } 230 // check for a slice type (string, bytes, slice) 231 if input.Type.requiresLengthPrefix() { 232 // calculate the offset 233 offset := inputOffset + len(variableInput) 234 // set the offset 235 ret = append(ret, packNum(reflect.ValueOf(offset))...) 236 // Append the packed output to the variable input. The variable input 237 // will be appended at the end of the input. 238 variableInput = append(variableInput, packed...) 239 } else { 240 // append the packed value to the input 241 ret = append(ret, packed...) 242 } 243 } 244 // append the variable input at the end of the packed input 245 ret = append(ret, variableInput...) 246 247 return ret, nil 248 } 249 250 // capitalise makes the first character of a string upper case, also removing any 251 // prefixing underscores from the variable names. 252 func capitalise(input string) string { 253 for len(input) > 0 && input[0] == '_' { 254 input = input[1:] 255 } 256 if len(input) == 0 { 257 return "" 258 } 259 return strings.ToUpper(input[:1]) + input[1:] 260 }