From 4f04fc89bb22c47bedd3868b1eb18c9b43d13e80 Mon Sep 17 00:00:00 2001 From: Guillaume Ballet Date: Fri, 14 Jun 2019 17:14:01 +0200 Subject: [PATCH] accounts, abigen: link dependent libs in deploy --- accounts/abi/bind/bind.go | 15 ++++++++++++++- accounts/abi/bind/template.go | 8 +++++++- cmd/abigen/main.go | 7 ++++++- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/accounts/abi/bind/bind.go b/accounts/abi/bind/bind.go index 6106b380c7..5da1b2b7a1 100644 --- a/accounts/abi/bind/bind.go +++ b/accounts/abi/bind/bind.go @@ -25,6 +25,7 @@ import ( "errors" "fmt" "go/format" + "log" "regexp" "strings" "text/template" @@ -46,7 +47,7 @@ const ( // 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 // 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) (string, error) { +func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string]string, pkg string, lang Lang, libs map[string]string) (string, error) { // Process each individual contract requested binding contracts := make(map[string]*tmplContract) @@ -142,16 +143,28 @@ func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string] Calls: calls, Transacts: transacts, Events: events, + Libraries: make(map[string]string), Structs: structs, } if len(fsigs) > i { contracts[types[i]].FuncSigs = fsigs[i] } + + for pattern, name := range libs { + matched, err := regexp.Match("__\\$"+pattern+"\\$__", []byte(contracts[types[i]].InputBin)) + if err != nil { + log.Fatalf("Could not search for pattern %v in %v: %v", pattern, contracts[types[i]], err) + } + if matched { + contracts[types[i]].Libraries[pattern] = name + } + } } // Generate the contract template data content and render it data := &tmplData{ Package: pkg, Contracts: contracts, + Libraries: libs, } buffer := new(bytes.Buffer) diff --git a/accounts/abi/bind/template.go b/accounts/abi/bind/template.go index 32e7eb1e8c..884d08b432 100644 --- a/accounts/abi/bind/template.go +++ b/accounts/abi/bind/template.go @@ -22,6 +22,7 @@ import "github.com/ethereum/go-ethereum/accounts/abi" type tmplData struct { Package string // Name of the package to place the generated file in Contracts map[string]*tmplContract // List of contracts to generate into this file + Libraries map[string]string // Map the bytecode's link pattern to the library name } // tmplContract contains the data needed to generate an individual contract binding. @@ -34,6 +35,7 @@ type tmplContract struct { Calls map[string]*tmplMethod // Contract calls that only read state data Transacts map[string]*tmplMethod // Contract calls that write state data Events map[string]*tmplEvent // Contract events accessors + Libraries map[string]string // Same as tmplData, but filtered to only keep what the contract needs Structs map[string]*tmplStruct // Contract struct type definitions } @@ -121,7 +123,7 @@ var ( {{if .InputBin}} // {{.Type}}Bin is the compiled bytecode used for deploying new contracts. - const {{.Type}}Bin = ` + "`" + `{{.InputBin}}` + "`" + ` + var {{.Type}}Bin = ` + "`" + `{{.InputBin}}` + "`" + ` // Deploy{{.Type}} deploys a new Ethereum contract, binding an instance of {{.Type}} to it. func Deploy{{.Type}}(auth *bind.TransactOpts, backend bind.ContractBackend {{range .Constructor.Inputs}}, {{.Name}} {{bindtype .Type $structs}}{{end}}) (common.Address, *types.Transaction, *{{.Type}}, error) { @@ -129,6 +131,10 @@ var ( if err != nil { return common.Address{}, nil, nil, err } + {{range $pattern, $name := .Libraries}} + {{decapitalise $name}}Addr, _, _, _ := Deploy{{capitalise $name}}(auth, backend) + {{$contract.Type}}Bin = strings.Replace({{$contract.Type}}Bin, "__${{$pattern}}$__", {{decapitalise $name}}Addr.String()[2:]) + {{end}} address, tx, contract, err := bind.DeployContract(auth, parsed, common.FromHex({{.Type}}Bin), backend {{range .Constructor.Inputs}}, {{.Name}}{{end}}) if err != nil { return common.Address{}, nil, nil, err diff --git a/cmd/abigen/main.go b/cmd/abigen/main.go index f9e0486238..df6b1803f4 100644 --- a/cmd/abigen/main.go +++ b/cmd/abigen/main.go @@ -24,6 +24,7 @@ import ( "os" "strings" + "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common/compiler" ) @@ -81,6 +82,7 @@ func main() { bins []string types []string sigs []map[string]string + libs map[string]string ) if *solFlag != "" || *vyFlag != "" || *abiFlag == "-" { // Generate the list of types to exclude from binding @@ -128,6 +130,9 @@ func main() { nameParts := strings.Split(name, ":") types = append(types, nameParts[len(nameParts)-1]) + + libPattern := crypto.Keccak256Hash([]byte(name)).String()[2:36] + libs[libPattern] = nameParts[len(nameParts)-1] } } else { // Otherwise load up the ABI, optional bytecode and type name from the parameters @@ -155,7 +160,7 @@ func main() { types = append(types, kind) } // Generate the contract binding - code, err := bind.Bind(types, abis, bins, sigs, *pkgFlag, lang) + code, err := bind.Bind(types, abis, bins, sigs, *pkgFlag, lang, libs) if err != nil { fmt.Printf("Failed to generate ABI binding: %v\n", err) os.Exit(-1)