github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/accounts/abi/bind/bind.go (about) 1 2 //此源码被清华学神尹成大魔王专业翻译分析并修改 3 //尹成QQ77025077 4 //尹成微信18510341407 5 //尹成所在QQ群721929980 6 //尹成邮箱 yinc13@mails.tsinghua.edu.cn 7 //尹成毕业于清华大学,微软区块链领域全球最有价值专家 8 //https://mvp.microsoft.com/zh-cn/PublicProfile/4033620 9 //版权所有2016 Go Ethereum作者 10 //此文件是Go以太坊库的一部分。 11 // 12 //Go-Ethereum库是免费软件:您可以重新分发它和/或修改 13 //根据GNU发布的较低通用公共许可证的条款 14 //自由软件基金会,或者许可证的第3版,或者 15 //(由您选择)任何更高版本。 16 // 17 //Go以太坊图书馆的发行目的是希望它会有用, 18 //但没有任何保证;甚至没有 19 //适销性或特定用途的适用性。见 20 //GNU较低的通用公共许可证,了解更多详细信息。 21 // 22 //你应该收到一份GNU较低级别的公共许可证副本 23 //以及Go以太坊图书馆。如果没有,请参见<http://www.gnu.org/licenses/>。 24 25 //包绑定生成以太坊契约go绑定。 26 // 27 //有关详细的使用文档和教程,请访问以太坊wiki页面: 28 //https://github.com/ethereum/go-ethereum/wiki/native-dapps:-转到绑定到ethereum合同 29 package bind 30 31 import ( 32 "bytes" 33 "fmt" 34 "regexp" 35 "strings" 36 "text/template" 37 "unicode" 38 39 "github.com/ethereum/go-ethereum/accounts/abi" 40 "golang.org/x/tools/imports" 41 ) 42 43 //lang是为其生成绑定的目标编程语言选择器。 44 type Lang int 45 46 const ( 47 LangGo Lang = iota 48 LangJava 49 LangObjC 50 ) 51 52 //bind围绕一个契约abi生成一个go包装器。这个包装不代表 53 //在客户端代码中使用,而不是作为中间结构使用, 54 //强制执行编译时类型安全和命名约定,而不是必须 55 //手动维护在运行时中断的硬编码字符串。 56 func Bind(types []string, abis []string, bytecodes []string, pkg string, lang Lang) (string, error) { 57 //处理每个要求约束的单独合同 58 contracts := make(map[string]*tmplContract) 59 60 for i := 0; i < len(types); i++ { 61 //分析实际的ABI以生成绑定 62 evmABI, err := abi.JSON(strings.NewReader(abis[i])) 63 if err != nil { 64 return "", err 65 } 66 //从JSONABI中删除任何空白 67 strippedABI := strings.Map(func(r rune) rune { 68 if unicode.IsSpace(r) { 69 return -1 70 } 71 return r 72 }, abis[i]) 73 74 //提取调用和事务处理方法;事件;并按字母顺序排序 75 var ( 76 calls = make(map[string]*tmplMethod) 77 transacts = make(map[string]*tmplMethod) 78 events = make(map[string]*tmplEvent) 79 ) 80 for _, original := range evmABI.Methods { 81 //规范资本案例和非匿名输入/输出的方法 82 normalized := original 83 normalized.Name = methodNormalizer[lang](original.Name) 84 85 normalized.Inputs = make([]abi.Argument, len(original.Inputs)) 86 copy(normalized.Inputs, original.Inputs) 87 for j, input := range normalized.Inputs { 88 if input.Name == "" { 89 normalized.Inputs[j].Name = fmt.Sprintf("arg%d", j) 90 } 91 } 92 normalized.Outputs = make([]abi.Argument, len(original.Outputs)) 93 copy(normalized.Outputs, original.Outputs) 94 for j, output := range normalized.Outputs { 95 if output.Name != "" { 96 normalized.Outputs[j].Name = capitalise(output.Name) 97 } 98 } 99 //将方法附加到调用或事务处理列表中 100 if original.Const { 101 calls[original.Name] = &tmplMethod{Original: original, Normalized: normalized, Structured: structured(original.Outputs)} 102 } else { 103 transacts[original.Name] = &tmplMethod{Original: original, Normalized: normalized, Structured: structured(original.Outputs)} 104 } 105 } 106 for _, original := range evmABI.Events { 107 //跳过匿名事件,因为它们不支持显式筛选 108 if original.Anonymous { 109 continue 110 } 111 //规范资本案例和非匿名输出的事件 112 normalized := original 113 normalized.Name = methodNormalizer[lang](original.Name) 114 115 normalized.Inputs = make([]abi.Argument, len(original.Inputs)) 116 copy(normalized.Inputs, original.Inputs) 117 for j, input := range normalized.Inputs { 118 //索引字段是输入,非索引字段是输出 119 if input.Indexed { 120 if input.Name == "" { 121 normalized.Inputs[j].Name = fmt.Sprintf("arg%d", j) 122 } 123 } 124 } 125 //将事件追加到累加器列表 126 events[original.Name] = &tmplEvent{Original: original, Normalized: normalized} 127 } 128 contracts[types[i]] = &tmplContract{ 129 Type: capitalise(types[i]), 130 InputABI: strings.Replace(strippedABI, "\"", "\\\"", -1), 131 InputBin: strings.TrimSpace(bytecodes[i]), 132 Constructor: evmABI.Constructor, 133 Calls: calls, 134 Transacts: transacts, 135 Events: events, 136 } 137 } 138 //生成合同模板数据内容并呈现 139 data := &tmplData{ 140 Package: pkg, 141 Contracts: contracts, 142 } 143 buffer := new(bytes.Buffer) 144 145 funcs := map[string]interface{}{ 146 "bindtype": bindType[lang], 147 "bindtopictype": bindTopicType[lang], 148 "namedtype": namedType[lang], 149 "capitalise": capitalise, 150 "decapitalise": decapitalise, 151 } 152 tmpl := template.Must(template.New("").Funcs(funcs).Parse(tmplSource[lang])) 153 if err := tmpl.Execute(buffer, data); err != nil { 154 return "", err 155 } 156 //for go绑定通过goimports传递代码以清除它并进行双重检查 157 if lang == LangGo { 158 code, err := imports.Process(".", buffer.Bytes(), nil) 159 if err != nil { 160 return "", fmt.Errorf("%v\n%s", err, buffer) 161 } 162 return string(code), nil 163 } 164 //对于所有其他人来说,现在就按原样返回 165 return buffer.String(), nil 166 } 167 168 //bindtype是一组类型绑定器,可以将solidity类型转换为支持的类型 169 //编程语言类型。 170 var bindType = map[Lang]func(kind abi.Type) string{ 171 LangGo: bindTypeGo, 172 LangJava: bindTypeJava, 173 } 174 175 //绑定生成器的助手函数。 176 //在内部类型匹配后读取不匹配的字符, 177 //(因为内部类型是total类型声明的前缀), 178 //查找包装内部类型的有效数组(可能是动态数组), 179 //并返回这些数组的大小。 180 // 181 //返回的数组大小与solidity签名的顺序相同;首先是内部数组大小。 182 //数组大小也可以为“”,表示动态数组。 183 func wrapArray(stringKind string, innerLen int, innerMapping string) (string, []string) { 184 remainder := stringKind[innerLen:] 185 //找到所有尺寸 186 matches := regexp.MustCompile(`\[(\d*)\]`).FindAllStringSubmatch(remainder, -1) 187 parts := make([]string, 0, len(matches)) 188 for _, match := range matches { 189 //从正则表达式匹配中获取组1 190 parts = append(parts, match[1]) 191 } 192 return innerMapping, parts 193 } 194 195 //将数组大小转换为内部类型(嵌套)数组的Go-Lang声明。 196 //如果arraysizes为空,只返回内部类型。 197 func arrayBindingGo(inner string, arraySizes []string) string { 198 out := "" 199 //预先处理所有阵列大小,从外部(结束阵列大小)到内部(开始阵列大小) 200 for i := len(arraySizes) - 1; i >= 0; i-- { 201 out += "[" + arraySizes[i] + "]" 202 } 203 out += inner 204 return out 205 } 206 207 //bindtypego将solidity类型转换为go类型。因为没有清晰的地图 208 //从所有solidity类型到go类型(例如uint17),那些不能精确 209 //mapped将使用升序类型(例如*big.int)。 210 func bindTypeGo(kind abi.Type) string { 211 stringKind := kind.String() 212 innerLen, innerMapping := bindUnnestedTypeGo(stringKind) 213 return arrayBindingGo(wrapArray(stringKind, innerLen, innerMapping)) 214 } 215 216 //bindtypego的内部函数,它查找StringKind的内部类型。 217 //(或者,如果类型本身不是数组或切片,则仅限于该类型本身) 218 //将返回匹配部分的长度和转换后的类型。 219 func bindUnnestedTypeGo(stringKind string) (int, string) { 220 221 switch { 222 case strings.HasPrefix(stringKind, "address"): 223 return len("address"), "common.Address" 224 225 case strings.HasPrefix(stringKind, "bytes"): 226 parts := regexp.MustCompile(`bytes([0-9]*)`).FindStringSubmatch(stringKind) 227 return len(parts[0]), fmt.Sprintf("[%s]byte", parts[1]) 228 229 case strings.HasPrefix(stringKind, "int") || strings.HasPrefix(stringKind, "uint"): 230 parts := regexp.MustCompile(`(u)?int([0-9]*)`).FindStringSubmatch(stringKind) 231 switch parts[2] { 232 case "8", "16", "32", "64": 233 return len(parts[0]), fmt.Sprintf("%sint%s", parts[1], parts[2]) 234 } 235 return len(parts[0]), "*big.Int" 236 237 case strings.HasPrefix(stringKind, "bool"): 238 return len("bool"), "bool" 239 240 case strings.HasPrefix(stringKind, "string"): 241 return len("string"), "string" 242 243 default: 244 return len(stringKind), stringKind 245 } 246 } 247 248 //将数组大小转换为内部类型(嵌套)数组的Java声明。 249 //如果arraysizes为空,只返回内部类型。 250 func arrayBindingJava(inner string, arraySizes []string) string { 251 //Java数组类型声明不包括长度。 252 return inner + strings.Repeat("[]", len(arraySizes)) 253 } 254 255 //bdType Java将一个稳固类型转换为Java类型。因为没有清晰的地图 256 //从所有Solidity类型到Java类型(例如UIT17),那些不能精确的类型。 257 //mapped将使用升序类型(例如bigdecimal)。 258 func bindTypeJava(kind abi.Type) string { 259 stringKind := kind.String() 260 innerLen, innerMapping := bindUnnestedTypeJava(stringKind) 261 return arrayBindingJava(wrapArray(stringKind, innerLen, innerMapping)) 262 } 263 264 //bindtypejava的内部函数,它查找StringKind的内部类型。 265 //(或者,如果类型本身不是数组或切片,则仅限于该类型本身) 266 //将返回匹配部分的长度和转换后的类型。 267 func bindUnnestedTypeJava(stringKind string) (int, string) { 268 269 switch { 270 case strings.HasPrefix(stringKind, "address"): 271 parts := regexp.MustCompile(`address(\[[0-9]*\])?`).FindStringSubmatch(stringKind) 272 if len(parts) != 2 { 273 return len(stringKind), stringKind 274 } 275 if parts[1] == "" { 276 return len("address"), "Address" 277 } 278 return len(parts[0]), "Addresses" 279 280 case strings.HasPrefix(stringKind, "bytes"): 281 parts := regexp.MustCompile(`bytes([0-9]*)`).FindStringSubmatch(stringKind) 282 if len(parts) != 2 { 283 return len(stringKind), stringKind 284 } 285 return len(parts[0]), "byte[]" 286 287 case strings.HasPrefix(stringKind, "int") || strings.HasPrefix(stringKind, "uint"): 288 //注意,uint和int(不带数字)也匹配, 289 //它们的大小为256,将转换为bigint(默认值)。 290 parts := regexp.MustCompile(`(u)?int([0-9]*)`).FindStringSubmatch(stringKind) 291 if len(parts) != 3 { 292 return len(stringKind), stringKind 293 } 294 295 namedSize := map[string]string{ 296 "8": "byte", 297 "16": "short", 298 "32": "int", 299 "64": "long", 300 }[parts[2]] 301 302 //默认为bigint 303 if namedSize == "" { 304 namedSize = "BigInt" 305 } 306 return len(parts[0]), namedSize 307 308 case strings.HasPrefix(stringKind, "bool"): 309 return len("bool"), "boolean" 310 311 case strings.HasPrefix(stringKind, "string"): 312 return len("string"), "String" 313 314 default: 315 return len(stringKind), stringKind 316 } 317 } 318 319 //bindtopictype是一组类型绑定器,将solidity类型转换为 320 //支持的编程语言主题类型。 321 var bindTopicType = map[Lang]func(kind abi.Type) string{ 322 LangGo: bindTopicTypeGo, 323 LangJava: bindTopicTypeJava, 324 } 325 326 //bindtypego将solidity主题类型转换为go类型。几乎是一样的 327 //功能与简单类型相同,但动态类型转换为哈希。 328 func bindTopicTypeGo(kind abi.Type) string { 329 bound := bindTypeGo(kind) 330 if bound == "string" || bound == "[]byte" { 331 bound = "common.Hash" 332 } 333 return bound 334 } 335 336 //bdIdTyGO将一个坚固性主题类型转换为Java主题类型。几乎是一样的 337 //功能与简单类型相同,但动态类型转换为哈希。 338 func bindTopicTypeJava(kind abi.Type) string { 339 bound := bindTypeJava(kind) 340 if bound == "String" || bound == "Bytes" { 341 bound = "Hash" 342 } 343 return bound 344 } 345 346 //NamedType是一组将特定语言类型转换为 347 //方法名中使用的命名版本。 348 var namedType = map[Lang]func(string, abi.Type) string{ 349 LangGo: func(string, abi.Type) string { panic("this shouldn't be needed") }, 350 LangJava: namedTypeJava, 351 } 352 353 //NamedTypeJava将一些基元数据类型转换为可以 354 //用作方法名称的一部分。 355 func namedTypeJava(javaKind string, solKind abi.Type) string { 356 switch javaKind { 357 case "byte[]": 358 return "Binary" 359 case "byte[][]": 360 return "Binaries" 361 case "string": 362 return "String" 363 case "string[]": 364 return "Strings" 365 case "boolean": 366 return "Bool" 367 case "boolean[]": 368 return "Bools" 369 case "BigInt[]": 370 return "BigInts" 371 default: 372 parts := regexp.MustCompile(`(u)?int([0-9]*)(\[[0-9]*\])?`).FindStringSubmatch(solKind.String()) 373 if len(parts) != 4 { 374 return javaKind 375 } 376 switch parts[2] { 377 case "8", "16", "32", "64": 378 if parts[3] == "" { 379 return capitalise(fmt.Sprintf("%sint%s", parts[1], parts[2])) 380 } 381 return capitalise(fmt.Sprintf("%sint%ss", parts[1], parts[2])) 382 383 default: 384 return javaKind 385 } 386 } 387 } 388 389 //methodNormalizer是一个名称转换器,它将solidity方法名称修改为 390 //符合目标语言命名概念。 391 var methodNormalizer = map[Lang]func(string) string{ 392 LangGo: capitalise, 393 LangJava: decapitalise, 394 } 395 396 //capitale生成一个以大写字符开头的驼色大小写字符串。 397 func capitalise(input string) string { 398 for len(input) > 0 && input[0] == '_' { 399 input = input[1:] 400 } 401 if len(input) == 0 { 402 return "" 403 } 404 return toCamelCase(strings.ToUpper(input[:1]) + input[1:]) 405 } 406 407 //无头化生成一个以小写字符开头的驼色大小写字符串。 408 func decapitalise(input string) string { 409 for len(input) > 0 && input[0] == '_' { 410 input = input[1:] 411 } 412 if len(input) == 0 { 413 return "" 414 } 415 return toCamelCase(strings.ToLower(input[:1]) + input[1:]) 416 } 417 418 //to camel case将欠分数字符串转换为驼色大小写字符串 419 func toCamelCase(input string) string { 420 toupper := false 421 422 result := "" 423 for k, v := range input { 424 switch { 425 case k == 0: 426 result = strings.ToUpper(string(input[0])) 427 428 case toupper: 429 result += strings.ToUpper(string(v)) 430 toupper = false 431 432 case v == '_': 433 toupper = true 434 435 default: 436 result += string(v) 437 } 438 } 439 return result 440 } 441 442 //结构化检查ABI数据类型列表是否有足够的信息 443 //通过适当的go结构或如果需要平面返回,则进行操作。 444 func structured(args abi.Arguments) bool { 445 if len(args) < 2 { 446 return false 447 } 448 exists := make(map[string]bool) 449 for _, out := range args { 450 //如果名称是匿名的,则无法组织成结构 451 if out.Name == "" { 452 return false 453 } 454 //如果规范化或冲突时字段名为空(var、var、_var、_var), 455 //我们不能组织成一个结构 456 field := capitalise(out.Name) 457 if field == "" || exists[field] { 458 return false 459 } 460 exists[field] = true 461 } 462 return true 463 }