forked from cerc-io/plugeth
accounts/abi/bind, cmd/abigen: implement alias for abigen (#20244)
* accounts/abi/bind, cmd/abigen: implement alias for abigen * accounts/abi/bind: minor fixes * accounts/abi/bind: address comments * cmd/abigen: address comments * accounts/abi/bind: print error log when identifier collision * accounts/abi/bind: address comments * accounts/abi/bind: address comment
This commit is contained in:
parent
bf5c6b29fa
commit
f8a95d996f
@ -47,7 +47,7 @@ const (
|
|||||||
// to be used as is in client code, but rather as an intermediate struct which
|
// to be used as is in client code, but rather as an intermediate struct which
|
||||||
// enforces compile time type safety and naming convention opposed to having to
|
// enforces compile time type safety and naming convention opposed to having to
|
||||||
// manually maintain hard coded strings that break on runtime.
|
// manually maintain hard coded strings that break on runtime.
|
||||||
func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string]string, pkg string, lang Lang, libs map[string]string) (string, error) {
|
func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string]string, pkg string, lang Lang, libs map[string]string, aliases map[string]string) (string, error) {
|
||||||
// Process each individual contract requested binding
|
// Process each individual contract requested binding
|
||||||
contracts := make(map[string]*tmplContract)
|
contracts := make(map[string]*tmplContract)
|
||||||
|
|
||||||
@ -74,12 +74,29 @@ func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string]
|
|||||||
transacts = make(map[string]*tmplMethod)
|
transacts = make(map[string]*tmplMethod)
|
||||||
events = make(map[string]*tmplEvent)
|
events = make(map[string]*tmplEvent)
|
||||||
structs = make(map[string]*tmplStruct)
|
structs = make(map[string]*tmplStruct)
|
||||||
|
|
||||||
|
// identifiers are used to detect duplicated identifier of function
|
||||||
|
// and event. For all calls, transacts and events, abigen will generate
|
||||||
|
// corresponding bindings. However we have to ensure there is no
|
||||||
|
// identifier coliision in the bindings of these categories.
|
||||||
|
callIdentifiers = make(map[string]bool)
|
||||||
|
transactIdentifiers = make(map[string]bool)
|
||||||
|
eventIdentifiers = make(map[string]bool)
|
||||||
)
|
)
|
||||||
for _, original := range evmABI.Methods {
|
for _, original := range evmABI.Methods {
|
||||||
// Normalize the method for capital cases and non-anonymous inputs/outputs
|
// Normalize the method for capital cases and non-anonymous inputs/outputs
|
||||||
normalized := original
|
normalized := original
|
||||||
normalized.Name = methodNormalizer[lang](original.Name)
|
normalizedName := methodNormalizer[lang](alias(aliases, original.Name))
|
||||||
|
// Ensure there is no duplicated identifier
|
||||||
|
var identifiers = callIdentifiers
|
||||||
|
if !original.Const {
|
||||||
|
identifiers = transactIdentifiers
|
||||||
|
}
|
||||||
|
if identifiers[normalizedName] {
|
||||||
|
return "", fmt.Errorf("duplicated identifier \"%s\"(normalized \"%s\"), use --alias for renaming", original.Name, normalizedName)
|
||||||
|
}
|
||||||
|
identifiers[normalizedName] = true
|
||||||
|
normalized.Name = normalizedName
|
||||||
normalized.Inputs = make([]abi.Argument, len(original.Inputs))
|
normalized.Inputs = make([]abi.Argument, len(original.Inputs))
|
||||||
copy(normalized.Inputs, original.Inputs)
|
copy(normalized.Inputs, original.Inputs)
|
||||||
for j, input := range normalized.Inputs {
|
for j, input := range normalized.Inputs {
|
||||||
@ -114,7 +131,14 @@ func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string]
|
|||||||
}
|
}
|
||||||
// Normalize the event for capital cases and non-anonymous outputs
|
// Normalize the event for capital cases and non-anonymous outputs
|
||||||
normalized := original
|
normalized := original
|
||||||
normalized.Name = methodNormalizer[lang](original.Name)
|
|
||||||
|
// Ensure there is no duplicated identifier
|
||||||
|
normalizedName := methodNormalizer[lang](alias(aliases, original.Name))
|
||||||
|
if eventIdentifiers[normalizedName] {
|
||||||
|
return "", fmt.Errorf("duplicated identifier \"%s\"(normalized \"%s\"), use --alias for renaming", original.Name, normalizedName)
|
||||||
|
}
|
||||||
|
eventIdentifiers[normalizedName] = true
|
||||||
|
normalized.Name = normalizedName
|
||||||
|
|
||||||
normalized.Inputs = make([]abi.Argument, len(original.Inputs))
|
normalized.Inputs = make([]abi.Argument, len(original.Inputs))
|
||||||
copy(normalized.Inputs, original.Inputs)
|
copy(normalized.Inputs, original.Inputs)
|
||||||
@ -483,6 +507,15 @@ func namedTypeJava(javaKind string, solKind abi.Type) string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// alias returns an alias of the given string based on the aliasing rules
|
||||||
|
// or returns itself if no rule is matched.
|
||||||
|
func alias(aliases map[string]string, n string) string {
|
||||||
|
if alias, exist := aliases[n]; exist {
|
||||||
|
return alias
|
||||||
|
}
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
// methodNormalizer is a name transformer that modifies Solidity method names to
|
// methodNormalizer is a name transformer that modifies Solidity method names to
|
||||||
// conform to target language naming concentions.
|
// conform to target language naming concentions.
|
||||||
var methodNormalizer = map[Lang]func(string) string{
|
var methodNormalizer = map[Lang]func(string) string{
|
||||||
|
@ -38,6 +38,7 @@ var bindTests = []struct {
|
|||||||
tester string
|
tester string
|
||||||
fsigs []map[string]string
|
fsigs []map[string]string
|
||||||
libs map[string]string
|
libs map[string]string
|
||||||
|
aliases map[string]string
|
||||||
types []string
|
types []string
|
||||||
}{
|
}{
|
||||||
// Test that the binding is available in combined and separate forms too
|
// Test that the binding is available in combined and separate forms too
|
||||||
@ -61,6 +62,7 @@ var bindTests = []struct {
|
|||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
|
nil,
|
||||||
},
|
},
|
||||||
// Test that all the official sample contracts bind correctly
|
// Test that all the official sample contracts bind correctly
|
||||||
{
|
{
|
||||||
@ -77,6 +79,7 @@ var bindTests = []struct {
|
|||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
|
nil,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
`Crowdsale`,
|
`Crowdsale`,
|
||||||
@ -92,6 +95,7 @@ var bindTests = []struct {
|
|||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
|
nil,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
`DAO`,
|
`DAO`,
|
||||||
@ -107,6 +111,7 @@ var bindTests = []struct {
|
|||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
|
nil,
|
||||||
},
|
},
|
||||||
// Test that named and anonymous inputs are handled correctly
|
// Test that named and anonymous inputs are handled correctly
|
||||||
{
|
{
|
||||||
@ -143,6 +148,7 @@ var bindTests = []struct {
|
|||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
|
nil,
|
||||||
},
|
},
|
||||||
// Test that named and anonymous outputs are handled correctly
|
// Test that named and anonymous outputs are handled correctly
|
||||||
{
|
{
|
||||||
@ -182,6 +188,7 @@ var bindTests = []struct {
|
|||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
|
nil,
|
||||||
},
|
},
|
||||||
// Tests that named, anonymous and indexed events are handled correctly
|
// Tests that named, anonymous and indexed events are handled correctly
|
||||||
{
|
{
|
||||||
@ -250,6 +257,7 @@ var bindTests = []struct {
|
|||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
|
nil,
|
||||||
},
|
},
|
||||||
// Test that contract interactions (deploy, transact and call) generate working code
|
// Test that contract interactions (deploy, transact and call) generate working code
|
||||||
{
|
{
|
||||||
@ -311,6 +319,7 @@ var bindTests = []struct {
|
|||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
|
nil,
|
||||||
},
|
},
|
||||||
// Tests that plain values can be properly returned and deserialized
|
// Tests that plain values can be properly returned and deserialized
|
||||||
{
|
{
|
||||||
@ -356,6 +365,7 @@ var bindTests = []struct {
|
|||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
|
nil,
|
||||||
},
|
},
|
||||||
// Tests that tuples can be properly returned and deserialized
|
// Tests that tuples can be properly returned and deserialized
|
||||||
{
|
{
|
||||||
@ -401,6 +411,7 @@ var bindTests = []struct {
|
|||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
|
nil,
|
||||||
},
|
},
|
||||||
// Tests that arrays/slices can be properly returned and deserialized.
|
// Tests that arrays/slices can be properly returned and deserialized.
|
||||||
// Only addresses are tested, remainder just compiled to keep the test small.
|
// Only addresses are tested, remainder just compiled to keep the test small.
|
||||||
@ -458,6 +469,7 @@ var bindTests = []struct {
|
|||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
|
nil,
|
||||||
},
|
},
|
||||||
// Tests that anonymous default methods can be correctly invoked
|
// Tests that anonymous default methods can be correctly invoked
|
||||||
{
|
{
|
||||||
@ -508,6 +520,7 @@ var bindTests = []struct {
|
|||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
|
nil,
|
||||||
},
|
},
|
||||||
// Tests that non-existent contracts are reported as such (though only simulator test)
|
// Tests that non-existent contracts are reported as such (though only simulator test)
|
||||||
{
|
{
|
||||||
@ -547,6 +560,7 @@ var bindTests = []struct {
|
|||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
|
nil,
|
||||||
},
|
},
|
||||||
// Tests that gas estimation works for contracts with weird gas mechanics too.
|
// Tests that gas estimation works for contracts with weird gas mechanics too.
|
||||||
{
|
{
|
||||||
@ -602,6 +616,7 @@ var bindTests = []struct {
|
|||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
|
nil,
|
||||||
},
|
},
|
||||||
// Test that constant functions can be called from an (optional) specified address
|
// Test that constant functions can be called from an (optional) specified address
|
||||||
{
|
{
|
||||||
@ -655,6 +670,7 @@ var bindTests = []struct {
|
|||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
|
nil,
|
||||||
},
|
},
|
||||||
// Tests that methods and returns with underscores inside work correctly.
|
// Tests that methods and returns with underscores inside work correctly.
|
||||||
{
|
{
|
||||||
@ -734,6 +750,7 @@ var bindTests = []struct {
|
|||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
|
nil,
|
||||||
},
|
},
|
||||||
// Tests that logs can be successfully filtered and decoded.
|
// Tests that logs can be successfully filtered and decoded.
|
||||||
{
|
{
|
||||||
@ -955,6 +972,7 @@ var bindTests = []struct {
|
|||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
|
nil,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
`DeeplyNestedArray`,
|
`DeeplyNestedArray`,
|
||||||
@ -1035,6 +1053,7 @@ var bindTests = []struct {
|
|||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
|
nil,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
`CallbackParam`,
|
`CallbackParam`,
|
||||||
@ -1076,6 +1095,7 @@ var bindTests = []struct {
|
|||||||
},
|
},
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
|
nil,
|
||||||
}, {
|
}, {
|
||||||
`Tuple`,
|
`Tuple`,
|
||||||
`
|
`
|
||||||
@ -1219,6 +1239,7 @@ var bindTests = []struct {
|
|||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
|
nil,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
`UseLibrary`,
|
`UseLibrary`,
|
||||||
@ -1287,6 +1308,7 @@ var bindTests = []struct {
|
|||||||
map[string]string{
|
map[string]string{
|
||||||
"b98c933f0a6ececcd167bd4f9d3299b1a0": "Math",
|
"b98c933f0a6ececcd167bd4f9d3299b1a0": "Math",
|
||||||
},
|
},
|
||||||
|
nil,
|
||||||
[]string{"UseLibrary", "Math"},
|
[]string{"UseLibrary", "Math"},
|
||||||
}, {
|
}, {
|
||||||
"Overload",
|
"Overload",
|
||||||
@ -1381,6 +1403,50 @@ var bindTests = []struct {
|
|||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
|
nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdentifierCollision",
|
||||||
|
`
|
||||||
|
pragma solidity >=0.4.19 <0.6.0;
|
||||||
|
|
||||||
|
contract IdentifierCollision {
|
||||||
|
uint public _myVar;
|
||||||
|
|
||||||
|
function MyVar() public view returns (uint) {
|
||||||
|
return _myVar;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
[]string{"60806040523480156100115760006000fd5b50610017565b60c3806100256000396000f3fe608060405234801560105760006000fd5b506004361060365760003560e01c806301ad4d8714603c5780634ef1f0ad146058576036565b60006000fd5b60426074565b6040518082815260200191505060405180910390f35b605e607d565b6040518082815260200191505060405180910390f35b60006000505481565b60006000600050549050608b565b9056fea265627a7a7231582067c8d84688b01c4754ba40a2a871cede94ea1f28b5981593ab2a45b46ac43af664736f6c634300050c0032"},
|
||||||
|
[]string{`[{"constant":true,"inputs":[],"name":"MyVar","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"_myVar","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"}]`},
|
||||||
|
`
|
||||||
|
"math/big"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
|
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
||||||
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
"github.com/ethereum/go-ethereum/core"
|
||||||
|
`,
|
||||||
|
`
|
||||||
|
// Initialize test accounts
|
||||||
|
key, _ := crypto.GenerateKey()
|
||||||
|
addr := crypto.PubkeyToAddress(key.PublicKey)
|
||||||
|
|
||||||
|
// Deploy registrar contract
|
||||||
|
sim := backends.NewSimulatedBackend(core.GenesisAlloc{addr: {Balance: big.NewInt(1000000000)}}, 10000000)
|
||||||
|
defer sim.Close()
|
||||||
|
|
||||||
|
transactOpts := bind.NewKeyedTransactor(key)
|
||||||
|
_, _, _, err := DeployIdentifierCollision(transactOpts, sim)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to deploy contract: %v", err)
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
map[string]string{"_myVar": "pubVar"}, // alias MyVar to PubVar
|
||||||
|
nil,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1412,7 +1478,7 @@ func TestGolangBindings(t *testing.T) {
|
|||||||
types = []string{tt.name}
|
types = []string{tt.name}
|
||||||
}
|
}
|
||||||
// Generate the binding and create a Go source file in the workspace
|
// Generate the binding and create a Go source file in the workspace
|
||||||
bind, err := Bind(types, tt.abi, tt.bytecode, tt.fsigs, "bindtest", LangGo, tt.libs)
|
bind, err := Bind(types, tt.abi, tt.bytecode, tt.fsigs, "bindtest", LangGo, tt.libs, tt.aliases)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("test %d: failed to generate binding: %v", i, err)
|
t.Fatalf("test %d: failed to generate binding: %v", i, err)
|
||||||
}
|
}
|
||||||
@ -1835,7 +1901,7 @@ public class Test {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
for i, c := range cases {
|
for i, c := range cases {
|
||||||
binding, err := Bind([]string{c.name}, []string{c.abi}, []string{c.bytecode}, nil, "bindtest", LangJava, nil)
|
binding, err := Bind([]string{c.name}, []string{c.abi}, []string{c.bytecode}, nil, "bindtest", LangJava, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("test %d: failed to generate binding: %v", i, err)
|
t.Fatalf("test %d: failed to generate binding: %v", i, err)
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
@ -103,6 +104,10 @@ var (
|
|||||||
Usage: "Destination language for the bindings (go, java, objc)",
|
Usage: "Destination language for the bindings (go, java, objc)",
|
||||||
Value: "go",
|
Value: "go",
|
||||||
}
|
}
|
||||||
|
aliasFlag = cli.StringFlag{
|
||||||
|
Name: "alias",
|
||||||
|
Usage: "Comma separated aliases for function and event renaming, e.g. foo=bar",
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@ -120,6 +125,7 @@ func init() {
|
|||||||
pkgFlag,
|
pkgFlag,
|
||||||
outFlag,
|
outFlag,
|
||||||
langFlag,
|
langFlag,
|
||||||
|
aliasFlag,
|
||||||
}
|
}
|
||||||
app.Action = utils.MigrateFlags(abigen)
|
app.Action = utils.MigrateFlags(abigen)
|
||||||
cli.CommandHelpTemplate = commandHelperTemplate
|
cli.CommandHelpTemplate = commandHelperTemplate
|
||||||
@ -144,11 +150,12 @@ func abigen(c *cli.Context) error {
|
|||||||
}
|
}
|
||||||
// If the entire solidity code was specified, build and bind based on that
|
// If the entire solidity code was specified, build and bind based on that
|
||||||
var (
|
var (
|
||||||
abis []string
|
abis []string
|
||||||
bins []string
|
bins []string
|
||||||
types []string
|
types []string
|
||||||
sigs []map[string]string
|
sigs []map[string]string
|
||||||
libs = make(map[string]string)
|
libs = make(map[string]string)
|
||||||
|
aliases = make(map[string]string)
|
||||||
)
|
)
|
||||||
if c.GlobalString(abiFlag.Name) != "" {
|
if c.GlobalString(abiFlag.Name) != "" {
|
||||||
// Load up the ABI, optional bytecode and type name from the parameters
|
// Load up the ABI, optional bytecode and type name from the parameters
|
||||||
@ -232,8 +239,20 @@ func abigen(c *cli.Context) error {
|
|||||||
libs[libPattern] = nameParts[len(nameParts)-1]
|
libs[libPattern] = nameParts[len(nameParts)-1]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Extract all aliases from the flags
|
||||||
|
if c.GlobalIsSet(aliasFlag.Name) {
|
||||||
|
// We support multi-versions for aliasing
|
||||||
|
// e.g.
|
||||||
|
// foo=bar,foo2=bar2
|
||||||
|
// foo:bar,foo2:bar2
|
||||||
|
re := regexp.MustCompile(`(?:(\w+)[:=](\w+))`)
|
||||||
|
submatches := re.FindAllStringSubmatch(c.GlobalString(aliasFlag.Name), -1)
|
||||||
|
for _, match := range submatches {
|
||||||
|
aliases[match[1]] = match[2]
|
||||||
|
}
|
||||||
|
}
|
||||||
// Generate the contract binding
|
// Generate the contract binding
|
||||||
code, err := bind.Bind(types, abis, bins, sigs, c.GlobalString(pkgFlag.Name), lang, libs)
|
code, err := bind.Bind(types, abis, bins, sigs, c.GlobalString(pkgFlag.Name), lang, libs, aliases)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Fatalf("Failed to generate ABI binding: %v", err)
|
utils.Fatalf("Failed to generate ABI binding: %v", err)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user