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  }