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