mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-31 00:53:46 +00:00
accounts/abi: rename contract MetaData field 'Pattern' to 'Id'. This reflects the fact that this field will not hold the solidity library pattern when it cannot be defined (when not using the --combined-json option). Modify LinkAndDeploy to return an error upfront if any of the provided metadatas in the DeploymentParams do not have deployer code embedded. Add comment clarifying semantics of link and deploy wrt contracts that share common dependency libraries
This commit is contained in:
parent
ddb9390bae
commit
d43e375683
5 changed files with 49 additions and 28 deletions
|
|
@ -37,7 +37,9 @@ var (
|
|||
var {{.Type}}MetaData = bind.MetaData{
|
||||
ABI: "{{.InputABI}}",
|
||||
{{if (index $.Libraries .Type) -}}
|
||||
Pattern: "{{index $.Libraries .Type}}",
|
||||
Id: "{{index $.Libraries .Type}}",
|
||||
{{ else -}}
|
||||
Id: "{{.Type}}",
|
||||
{{end -}}
|
||||
{{if .InputBin -}}
|
||||
Bin: "0x{{.InputBin}}",
|
||||
|
|
|
|||
|
|
@ -93,14 +93,18 @@ type MetaData struct {
|
|||
ABI string // the raw ABI definition (JSON)
|
||||
Deps []*MetaData // library dependencies of the contract
|
||||
|
||||
// Solidity library placeholder name. This is a unique identifier of a contract within
|
||||
// a compilation unit. The Pattern is used to link contracts during deployment using
|
||||
// [LinkAndDeploy].
|
||||
// For bindings that were compiled from combined-json Id is the Solidity library pattern: a 34 character prefix
|
||||
// of the hex encoding of the keccak256
|
||||
// hash of the fully qualified 'library name', i.e. the path of the source file.
|
||||
//
|
||||
// The library pattern is a 34 character prefix of the hex encoding of the keccak256
|
||||
// hash of the fully qualified 'library name', i.e. the path of the source file
|
||||
// containing the library code.
|
||||
Pattern string
|
||||
// For contracts compiled from the ABI definition alone, this is the type name of the contract (as specified
|
||||
// in the ABI definition or overridden via the --type flag).
|
||||
//
|
||||
// This is a unique identifier of a contract within a compilation unit. When used as part of a multi-contract
|
||||
// deployment with library dependencies, the Id is used to link
|
||||
// contracts during deployment using
|
||||
// [LinkAndDeploy].
|
||||
Id string
|
||||
|
||||
mu sync.Mutex
|
||||
parsedABI *abi.ABI
|
||||
|
|
|
|||
|
|
@ -25,14 +25,24 @@ type DeploymentParams struct {
|
|||
Overrides map[string]common.Address
|
||||
}
|
||||
|
||||
// validate determines whether the contracts specified in the DeploymentParams instance have provided deployer bytecode.
|
||||
func (d *DeploymentParams) validate() error {
|
||||
for _, meta := range d.Contracts {
|
||||
if meta.Bin == "" {
|
||||
return fmt.Errorf("cannot deploy contract %s: deployer code missing from metadata", meta.Id)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeploymentResult encapsulates information about the result of the deployment
|
||||
// of a set of contracts: the pending deployment transactions, and the addresses
|
||||
// where the contracts will be deployed at.
|
||||
type DeploymentResult struct {
|
||||
// map of contract library pattern -> deploy transaction
|
||||
// map of contract MetaData Id to deploy transaction
|
||||
Txs map[string]*types.Transaction
|
||||
|
||||
// map of contract library pattern -> deployed address
|
||||
// map of contract MetaData Id to deployed contract address
|
||||
Addrs map[string]common.Address
|
||||
}
|
||||
|
||||
|
|
@ -71,7 +81,7 @@ func newDepTreeDeployer(deployParams *DeploymentParams, deployFn DeployFn) *depT
|
|||
// The deployment result (deploy addresses/txs or an error) is stored in the depTreeDeployer object.
|
||||
func (d *depTreeDeployer) linkAndDeploy(metadata *MetaData) (common.Address, error) {
|
||||
// Don't deploy already deployed contracts
|
||||
if addr, ok := d.deployedAddrs[metadata.Pattern]; ok {
|
||||
if addr, ok := d.deployedAddrs[metadata.Id]; ok {
|
||||
return addr, nil
|
||||
}
|
||||
// if this contract/library depends on other libraries deploy them (and their dependencies) first
|
||||
|
|
@ -82,19 +92,19 @@ func (d *depTreeDeployer) linkAndDeploy(metadata *MetaData) (common.Address, err
|
|||
return common.Address{}, err
|
||||
}
|
||||
// link their deployed addresses into the bytecode to produce
|
||||
deployerCode = strings.ReplaceAll(deployerCode, "__$"+dep.Pattern+"$__", strings.ToLower(addr.String()[2:]))
|
||||
deployerCode = strings.ReplaceAll(deployerCode, "__$"+dep.Id+"$__", strings.ToLower(addr.String()[2:]))
|
||||
}
|
||||
// Finally, deploy the contract.
|
||||
code, err := hex.DecodeString(deployerCode[2:])
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("error decoding contract deployer hex %s:\n%v", deployerCode[2:], err))
|
||||
}
|
||||
addr, tx, err := d.deployFn(d.inputs[metadata.Pattern], code)
|
||||
addr, tx, err := d.deployFn(d.inputs[metadata.Id], code)
|
||||
if err != nil {
|
||||
return common.Address{}, err
|
||||
}
|
||||
d.deployedAddrs[metadata.Pattern] = addr
|
||||
d.deployerTxs[metadata.Pattern] = tx
|
||||
d.deployedAddrs[metadata.Id] = addr
|
||||
d.deployerTxs[metadata.Id] = tx
|
||||
return addr, nil
|
||||
}
|
||||
|
||||
|
|
@ -115,7 +125,12 @@ func (d *depTreeDeployer) result() *DeploymentResult {
|
|||
// LinkAndDeploy deploys a specified set of contracts and their dependent
|
||||
// libraries. If an error occurs, only contracts which were successfully
|
||||
// deployed are returned in the result.
|
||||
//
|
||||
// In the case where multiple contracts share a common dependency: the shared dependency will only be deployed once.
|
||||
func LinkAndDeploy(deployParams *DeploymentParams, deploy DeployFn) (res *DeploymentResult, err error) {
|
||||
if err := deployParams.validate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
deployer := newDepTreeDeployer(deployParams, deploy)
|
||||
for _, contract := range deployParams.Contracts {
|
||||
if _, err := deployer.linkAndDeploy(contract); err != nil {
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ func copyMetaData(m *MetaData) *MetaData {
|
|||
Bin: m.Bin,
|
||||
ABI: m.ABI,
|
||||
Deps: deps,
|
||||
Pattern: m.Pattern,
|
||||
Id: m.Id,
|
||||
mu: sync.Mutex{},
|
||||
parsedABI: m.parsedABI,
|
||||
}
|
||||
|
|
@ -200,12 +200,12 @@ func testLinkCase(tcInput linkTestCaseInput) error {
|
|||
overrides := make(map[string]common.Address)
|
||||
|
||||
for pattern, bin := range tc.contractCodes {
|
||||
contracts[pattern] = &MetaData{Pattern: pattern, Bin: "0x" + bin}
|
||||
contracts[pattern] = &MetaData{Id: pattern, Bin: "0x" + bin}
|
||||
}
|
||||
for pattern, bin := range tc.libCodes {
|
||||
contracts[pattern] = &MetaData{
|
||||
Bin: "0x" + bin,
|
||||
Pattern: pattern,
|
||||
Bin: "0x" + bin,
|
||||
Id: pattern,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@ func TestDeploymentLibraries(t *testing.T) {
|
|||
constructorInput := c.PackConstructor(big.NewInt(42), big.NewInt(1))
|
||||
deploymentParams := &bind.DeploymentParams{
|
||||
Contracts: []*bind.MetaData{&nested_libraries.C1MetaData},
|
||||
Inputs: map[string][]byte{nested_libraries.C1MetaData.Pattern: constructorInput},
|
||||
Inputs: map[string][]byte{nested_libraries.C1MetaData.Id: constructorInput},
|
||||
}
|
||||
res, err := bind.LinkAndDeploy(deploymentParams, makeTestDeployer(opts, bindBackend))
|
||||
if err != nil {
|
||||
|
|
@ -129,7 +129,7 @@ func TestDeploymentLibraries(t *testing.T) {
|
|||
}
|
||||
|
||||
doInput := c.PackDo(big.NewInt(1))
|
||||
contractAddr := res.Addrs[nested_libraries.C1MetaData.Pattern]
|
||||
contractAddr := res.Addrs[nested_libraries.C1MetaData.Id]
|
||||
callOpts := &bind.CallOpts{From: common.Address{}, Context: context.Background()}
|
||||
instance := c.Instance(bindBackend, contractAddr)
|
||||
internalCallCount, err := bind.Call(instance, callOpts, doInput, c.UnpackDo)
|
||||
|
|
@ -177,7 +177,7 @@ func TestDeploymentWithOverrides(t *testing.T) {
|
|||
// deploy the contract
|
||||
deploymentParams = &bind.DeploymentParams{
|
||||
Contracts: []*bind.MetaData{&nested_libraries.C1MetaData},
|
||||
Inputs: map[string][]byte{nested_libraries.C1MetaData.Pattern: constructorInput},
|
||||
Inputs: map[string][]byte{nested_libraries.C1MetaData.Id: constructorInput},
|
||||
Overrides: overrides,
|
||||
}
|
||||
res, err = bind.LinkAndDeploy(deploymentParams, makeTestDeployer(opts, bindBackend))
|
||||
|
|
@ -198,7 +198,7 @@ func TestDeploymentWithOverrides(t *testing.T) {
|
|||
|
||||
// call the deployed contract and make sure it returns the correct result
|
||||
doInput := c.PackDo(big.NewInt(1))
|
||||
instance := c.Instance(bindBackend, res.Addrs[nested_libraries.C1MetaData.Pattern])
|
||||
instance := c.Instance(bindBackend, res.Addrs[nested_libraries.C1MetaData.Id])
|
||||
callOpts := new(bind.CallOpts)
|
||||
internalCallCount, err := bind.Call(instance, callOpts, doInput, c.UnpackDo)
|
||||
if err != nil {
|
||||
|
|
@ -223,12 +223,12 @@ func TestEvents(t *testing.T) {
|
|||
}
|
||||
|
||||
backend.Commit()
|
||||
if _, err := bind.WaitDeployed(context.Background(), backend, res.Txs[events.CMetaData.Pattern].Hash()); err != nil {
|
||||
if _, err := bind.WaitDeployed(context.Background(), backend, res.Txs[events.CMetaData.Id].Hash()); err != nil {
|
||||
t.Fatalf("WaitDeployed failed %v", err)
|
||||
}
|
||||
|
||||
c := events.NewC()
|
||||
instance := c.Instance(backend, res.Addrs[events.CMetaData.Pattern])
|
||||
instance := c.Instance(backend, res.Addrs[events.CMetaData.Id])
|
||||
|
||||
newCBasic1Ch := make(chan *events.CBasic1)
|
||||
newCBasic2Ch := make(chan *events.CBasic2)
|
||||
|
|
@ -322,14 +322,14 @@ func TestErrors(t *testing.T) {
|
|||
}
|
||||
|
||||
backend.Commit()
|
||||
if _, err := bind.WaitDeployed(context.Background(), backend, res.Txs[solc_errors.CMetaData.Pattern].Hash()); err != nil {
|
||||
if _, err := bind.WaitDeployed(context.Background(), backend, res.Txs[solc_errors.CMetaData.Id].Hash()); err != nil {
|
||||
t.Fatalf("WaitDeployed failed %v", err)
|
||||
}
|
||||
|
||||
c := solc_errors.NewC()
|
||||
instance := c.Instance(backend, res.Addrs[solc_errors.CMetaData.Pattern])
|
||||
instance := c.Instance(backend, res.Addrs[solc_errors.CMetaData.Id])
|
||||
packedInput := c.PackFoo()
|
||||
opts := &bind.CallOpts{From: res.Addrs[solc_errors.CMetaData.Pattern]}
|
||||
opts := &bind.CallOpts{From: res.Addrs[solc_errors.CMetaData.Id]}
|
||||
_, err = bind.Call[struct{}](instance, opts, packedInput, nil)
|
||||
if err == nil {
|
||||
t.Fatalf("expected call to fail")
|
||||
|
|
|
|||
Loading…
Reference in a new issue