github.com/SmartMeshFoundation/Spectrum@v0.0.0-20220621030607-452a266fee1e/accounts/abi/argument.go (about) 1 // Copyright 2015 The Spectrum Authors 2 // This file is part of the Spectrum library. 3 // 4 // The Spectrum 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 Spectrum 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 Spectrum 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 // isTuple returns true for non-atomic constructs, like (uint,uint) or uint[] 71 func (arguments Arguments) isTuple() bool { 72 return len(arguments) > 1 73 } 74 75 // Unpack performs the operation hexdata -> Go format 76 func (arguments Arguments) Unpack(v interface{}, data []byte) error { 77 if arguments.isTuple() { 78 return arguments.unpackTuple(v, data) 79 } 80 return arguments.unpackAtomic(v, data) 81 } 82 83 func (arguments Arguments) unpackTuple(v interface{}, output []byte) error { 84 // make sure the passed value is arguments pointer 85 valueOf := reflect.ValueOf(v) 86 if reflect.Ptr != valueOf.Kind() { 87 return fmt.Errorf("abi: Unpack(non-pointer %T)", v) 88 } 89 90 var ( 91 value = valueOf.Elem() 92 typ = value.Type() 93 kind = value.Kind() 94 ) 95 96 if err := requireUnpackKind(value, typ, kind, arguments); err != nil { 97 return err 98 } 99 // If the output interface is a struct, make sure names don't collide 100 if kind == reflect.Struct { 101 exists := make(map[string]bool) 102 for _, arg := range arguments { 103 field := capitalise(arg.Name) 104 if field == "" { 105 return fmt.Errorf("abi: purely underscored output cannot unpack to struct") 106 } 107 if exists[field] { 108 return fmt.Errorf("abi: multiple outputs mapping to the same struct field '%s'", field) 109 } 110 exists[field] = true 111 } 112 } 113 // `i` counts the nonindexed arguments. 114 // `j` counts the number of complex types. 115 // both `i` and `j` are used to to correctly compute `data` offset. 116 117 i, j := -1, 0 118 for _, arg := range arguments { 119 120 if arg.Indexed { 121 // can't read, continue 122 continue 123 } 124 i++ 125 marshalledValue, err := toGoType((i+j)*32, arg.Type, output) 126 if err != nil { 127 return err 128 } 129 130 if arg.Type.T == ArrayTy { 131 // combined index ('i' + 'j') need to be adjusted only by size of array, thus 132 // we need to decrement 'j' because 'i' was incremented 133 j += arg.Type.Size - 1 134 } 135 136 reflectValue := reflect.ValueOf(marshalledValue) 137 138 switch kind { 139 case reflect.Struct: 140 name := capitalise(arg.Name) 141 for j := 0; j < typ.NumField(); j++ { 142 // TODO read tags: `abi:"fieldName"` 143 if typ.Field(j).Name == name { 144 if err := set(value.Field(j), reflectValue, arg); err != nil { 145 return err 146 } 147 } 148 } 149 case reflect.Slice, reflect.Array: 150 if value.Len() < i { 151 return fmt.Errorf("abi: insufficient number of arguments for unpack, want %d, got %d", len(arguments), value.Len()) 152 } 153 v := value.Index(i) 154 if err := requireAssignable(v, reflectValue); err != nil { 155 return err 156 } 157 158 if err := set(v.Elem(), reflectValue, arg); err != nil { 159 return err 160 } 161 default: 162 return fmt.Errorf("abi:[2] cannot unmarshal tuple in to %v", typ) 163 } 164 } 165 return nil 166 } 167 168 // unpackAtomic unpacks ( hexdata -> go ) a single value 169 func (arguments Arguments) unpackAtomic(v interface{}, output []byte) error { 170 // make sure the passed value is arguments pointer 171 valueOf := reflect.ValueOf(v) 172 if reflect.Ptr != valueOf.Kind() { 173 return fmt.Errorf("abi: Unpack(non-pointer %T)", v) 174 } 175 arg := arguments[0] 176 if arg.Indexed { 177 return fmt.Errorf("abi: attempting to unpack indexed variable into element.") 178 } 179 180 value := valueOf.Elem() 181 182 marshalledValue, err := toGoType(0, arg.Type, output) 183 if err != nil { 184 return err 185 } 186 return set(value, reflect.ValueOf(marshalledValue), arg) 187 } 188 189 // Unpack performs the operation Go format -> Hexdata 190 func (arguments Arguments) Pack(args ...interface{}) ([]byte, error) { 191 // Make sure arguments match up and pack them 192 abiArgs := arguments 193 if len(args) != len(abiArgs) { 194 return nil, fmt.Errorf("argument count mismatch: %d for %d", len(args), len(abiArgs)) 195 } 196 197 // variable input is the output appended at the end of packed 198 // output. This is used for strings and bytes types input. 199 var variableInput []byte 200 201 // input offset is the bytes offset for packed output 202 inputOffset := 0 203 for _, abiArg := range abiArgs { 204 if abiArg.Type.T == ArrayTy { 205 inputOffset += (32 * abiArg.Type.Size) 206 } else { 207 inputOffset += 32 208 } 209 } 210 211 var ret []byte 212 for i, a := range args { 213 input := abiArgs[i] 214 // pack the input 215 packed, err := input.Type.pack(reflect.ValueOf(a)) 216 if err != nil { 217 return nil, err 218 } 219 220 // check for a slice type (string, bytes, slice) 221 if input.Type.requiresLengthPrefix() { 222 // calculate the offset 223 offset := inputOffset + len(variableInput) 224 // set the offset 225 ret = append(ret, packNum(reflect.ValueOf(offset))...) 226 // Append the packed output to the variable input. The variable input 227 // will be appended at the end of the input. 228 variableInput = append(variableInput, packed...) 229 } else { 230 // append the packed value to the input 231 ret = append(ret, packed...) 232 } 233 } 234 // append the variable input at the end of the packed input 235 ret = append(ret, variableInput...) 236 237 return ret, nil 238 } 239 240 // capitalise makes the first character of a string upper case, also removing any 241 // prefixing underscores from the variable names. 242 func capitalise(input string) string { 243 for len(input) > 0 && input[0] == '_' { 244 input = input[1:] 245 } 246 if len(input) == 0 { 247 return "" 248 } 249 return strings.ToUpper(input[:1]) + input[1:] 250 }