github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/accounts/abi/argument.go (about) 1 2 //<developer> 3 // <name>linapex 曹一峰</name> 4 // <email>linapex@163.com</email> 5 // <wx>superexc</wx> 6 // <qqgroup>128148617</qqgroup> 7 // <url>https://jsq.ink</url> 8 // <role>pku engineer</role> 9 // <date>2019-03-16 12:09:26</date> 10 //</624342582406680576> 11 12 13 package abi 14 15 import ( 16 "encoding/json" 17 "fmt" 18 "reflect" 19 "strings" 20 ) 21 22 //参数包含参数的名称和相应的类型。 23 //类型在打包和测试参数时使用。 24 type Argument struct { 25 Name string 26 Type Type 27 Indexed bool //索引仅由事件使用 28 } 29 30 type Arguments []Argument 31 32 //unmashaljson实现json.unmasheler接口 33 func (argument *Argument) UnmarshalJSON(data []byte) error { 34 var extarg struct { 35 Name string 36 Type string 37 Indexed bool 38 } 39 err := json.Unmarshal(data, &extarg) 40 if err != nil { 41 return fmt.Errorf("argument json err: %v", err) 42 } 43 44 argument.Type, err = NewType(extarg.Type) 45 if err != nil { 46 return err 47 } 48 argument.Name = extarg.Name 49 argument.Indexed = extarg.Indexed 50 51 return nil 52 } 53 54 //lengthnonindexed返回不计算“indexed”参数时的参数数。只有事件 55 //不能有“indexed”参数,方法输入/输出的参数应始终为false 56 func (arguments Arguments) LengthNonIndexed() int { 57 out := 0 58 for _, arg := range arguments { 59 if !arg.Indexed { 60 out++ 61 } 62 } 63 return out 64 } 65 66 //无索引返回已筛选出索引参数的参数 67 func (arguments Arguments) NonIndexed() Arguments { 68 var ret []Argument 69 for _, arg := range arguments { 70 if !arg.Indexed { 71 ret = append(ret, arg) 72 } 73 } 74 return ret 75 } 76 77 //Istuple为非原子结构返回true,如(uint、uint)或uint[] 78 func (arguments Arguments) isTuple() bool { 79 return len(arguments) > 1 80 } 81 82 //unpack执行hexdata->go-format操作 83 func (arguments Arguments) Unpack(v interface{}, data []byte) error { 84 85 //确保传递的值是参数指针 86 if reflect.Ptr != reflect.ValueOf(v).Kind() { 87 return fmt.Errorf("abi: Unpack(non-pointer %T)", v) 88 } 89 marshalledValues, err := arguments.UnpackValues(data) 90 if err != nil { 91 return err 92 } 93 if arguments.isTuple() { 94 return arguments.unpackTuple(v, marshalledValues) 95 } 96 return arguments.unpackAtomic(v, marshalledValues) 97 } 98 99 func (arguments Arguments) unpackTuple(v interface{}, marshalledValues []interface{}) error { 100 101 var ( 102 value = reflect.ValueOf(v).Elem() 103 typ = value.Type() 104 kind = value.Kind() 105 ) 106 107 if err := requireUnpackKind(value, typ, kind, arguments); err != nil { 108 return err 109 } 110 111 //如果接口是结构,则获取abi->struct_字段映射 112 113 var abi2struct map[string]string 114 if kind == reflect.Struct { 115 var err error 116 abi2struct, err = mapAbiToStructFields(arguments, value) 117 if err != nil { 118 return err 119 } 120 } 121 for i, arg := range arguments.NonIndexed() { 122 123 reflectValue := reflect.ValueOf(marshalledValues[i]) 124 125 switch kind { 126 case reflect.Struct: 127 if structField, ok := abi2struct[arg.Name]; ok { 128 if err := set(value.FieldByName(structField), reflectValue, arg); err != nil { 129 return err 130 } 131 } 132 case reflect.Slice, reflect.Array: 133 if value.Len() < i { 134 return fmt.Errorf("abi: insufficient number of arguments for unpack, want %d, got %d", len(arguments), value.Len()) 135 } 136 v := value.Index(i) 137 if err := requireAssignable(v, reflectValue); err != nil { 138 return err 139 } 140 141 if err := set(v.Elem(), reflectValue, arg); err != nil { 142 return err 143 } 144 default: 145 return fmt.Errorf("abi:[2] cannot unmarshal tuple in to %v", typ) 146 } 147 } 148 return nil 149 } 150 151 //解包原子解包(hexdata->go)单个值 152 func (arguments Arguments) unpackAtomic(v interface{}, marshalledValues []interface{}) error { 153 if len(marshalledValues) != 1 { 154 return fmt.Errorf("abi: wrong length, expected single value, got %d", len(marshalledValues)) 155 } 156 157 elem := reflect.ValueOf(v).Elem() 158 kind := elem.Kind() 159 reflectValue := reflect.ValueOf(marshalledValues[0]) 160 161 var abi2struct map[string]string 162 if kind == reflect.Struct { 163 var err error 164 if abi2struct, err = mapAbiToStructFields(arguments, elem); err != nil { 165 return err 166 } 167 arg := arguments.NonIndexed()[0] 168 if structField, ok := abi2struct[arg.Name]; ok { 169 return set(elem.FieldByName(structField), reflectValue, arg) 170 } 171 return nil 172 } 173 174 return set(elem, reflectValue, arguments.NonIndexed()[0]) 175 176 } 177 178 //计算数组的完整大小; 179 //也就是说,对嵌套数组进行计数,这些数组将计入解包的大小。 180 func getArraySize(arr *Type) int { 181 size := arr.Size 182 //数组可以嵌套,每个元素的大小相同 183 arr = arr.Elem 184 for arr.T == ArrayTy { 185 //当elem是数组时,继续乘以elem.size。 186 size *= arr.Size 187 arr = arr.Elem 188 } 189 //现在我们有了完整的数组大小,包括它的子数组。 190 return size 191 } 192 193 //解包值可用于根据ABI规范解包ABI编码的十六进制数据。 194 //不提供要解包的结构。相反,此方法返回一个包含 195 //价值观。原子参数将是一个包含一个元素的列表。 196 func (arguments Arguments) UnpackValues(data []byte) ([]interface{}, error) { 197 retval := make([]interface{}, 0, arguments.LengthNonIndexed()) 198 virtualArgs := 0 199 for index, arg := range arguments.NonIndexed() { 200 marshalledValue, err := toGoType((index+virtualArgs)*32, arg.Type, data) 201 if arg.Type.T == ArrayTy { 202 //如果我们有一个静态数组,比如[3]uint256,那么这些数组被编码为 203 //就像uint256、uint256、uint256一样。 204 //这意味着当 205 //我们从现在开始计算索引。 206 // 207 //嵌套多层深度的数组值也以内联方式编码: 208 //[2][3]uint256:uint256、uint256、uint256、uint256、uint256、uint256、uint256 209 // 210 //计算完整的数组大小以获得下一个参数的正确偏移量。 211 //将其减小1,因为仍应用正常索引增量。 212 virtualArgs += getArraySize(&arg.Type) - 1 213 } 214 if err != nil { 215 return nil, err 216 } 217 retval = append(retval, marshalledValue) 218 } 219 return retval, nil 220 } 221 222 //packvalues执行操作go format->hexdata 223 //它在语义上与unpackvalues相反 224 func (arguments Arguments) PackValues(args []interface{}) ([]byte, error) { 225 return arguments.Pack(args...) 226 } 227 228 //pack执行操作go format->hexdata 229 func (arguments Arguments) Pack(args ...interface{}) ([]byte, error) { 230 //确保参数匹配并打包 231 abiArgs := arguments 232 if len(args) != len(abiArgs) { 233 return nil, fmt.Errorf("argument count mismatch: %d for %d", len(args), len(abiArgs)) 234 } 235 //变量输入是在压缩结束时附加的输出 236 //输出。这用于字符串和字节类型输入。 237 var variableInput []byte 238 239 //输入偏移量是压缩输出的字节偏移量 240 inputOffset := 0 241 for _, abiArg := range abiArgs { 242 if abiArg.Type.T == ArrayTy { 243 inputOffset += 32 * abiArg.Type.Size 244 } else { 245 inputOffset += 32 246 } 247 } 248 var ret []byte 249 for i, a := range args { 250 input := abiArgs[i] 251 //打包输入 252 packed, err := input.Type.pack(reflect.ValueOf(a)) 253 if err != nil { 254 return nil, err 255 } 256 //检查切片类型(字符串、字节、切片) 257 if input.Type.requiresLengthPrefix() { 258 //计算偏移量 259 offset := inputOffset + len(variableInput) 260 //设置偏移量 261 ret = append(ret, packNum(reflect.ValueOf(offset))...) 262 //将打包输出附加到变量输入。变量输入 263 //将附加在输入的末尾。 264 variableInput = append(variableInput, packed...) 265 } else { 266 //将压缩值追加到输入 267 ret = append(ret, packed...) 268 } 269 } 270 //在压缩输入的末尾附加变量输入 271 ret = append(ret, variableInput...) 272 273 return ret, nil 274 } 275 276 //大写将字符串的第一个字符设为大写,同时删除 277 //在变量名中添加下划线前缀。 278 func capitalise(input string) string { 279 for len(input) > 0 && input[0] == '_' { 280 input = input[1:] 281 } 282 if len(input) == 0 { 283 return "" 284 } 285 return strings.ToUpper(input[:1]) + input[1:] 286 } 287