update dep tree

This commit is contained in:
Jared Wasinger 2024-12-16 15:06:32 +07:00 committed by Felix Lange
parent 3129593b3f
commit d93a152298
2 changed files with 39 additions and 52 deletions

View File

@ -70,10 +70,6 @@ func isKeyWord(arg string) bool {
return true return true
} }
func add(val1, val2 int) int {
return val1 + val2
}
// Bind generates a Go wrapper around a contract ABI. This wrapper isn't meant // Bind generates a Go wrapper around a contract ABI. This wrapper isn't meant
// 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 as opposed to having to // enforces compile time type safety and naming convention as opposed to having to
@ -179,7 +175,9 @@ func BindV2(types []string, abis []string, bytecodes []string, fsigs []map[strin
"bindtopictype": bindTopicType, "bindtopictype": bindTopicType,
"capitalise": capitalise, "capitalise": capitalise,
"decapitalise": decapitalise, "decapitalise": decapitalise,
"add": add, "add": func(val1, val2 int) int {
return val1 + val2
},
} }
tmpl := template.Must(template.New("").Funcs(funcs).Parse(tmplSourceV2)) tmpl := template.Must(template.New("").Funcs(funcs).Parse(tmplSourceV2))
if err := tmpl.Execute(buffer, data); err != nil { if err := tmpl.Execute(buffer, data); err != nil {

View File

@ -7,19 +7,12 @@ import (
"strings" "strings"
) )
// ContractDeployParams represents state needed to deploy a contract:
// the metdata and constructor input (which can be nil if no input is specified).
type ContractDeployParams struct {
Meta *MetaData
// Input is the ABI-encoded constructor input for the contract deployment.
Input []byte
}
// DeploymentParams represents parameters needed to deploy a // DeploymentParams represents parameters needed to deploy a
// set of contracts, their dependency libraries. It takes an optional override // set of contracts. It takes an optional override
// list to specify libraries that have already been deployed on-chain. // list to specify contracts/libraries that have already been deployed on-chain.
type DeploymentParams struct { type DeploymentParams struct {
Contracts []*MetaData Contracts []*MetaData
// map of solidity library pattern to constructor input.
Inputs map[string][]byte Inputs map[string][]byte
// Overrides is an optional map of pattern to deployment address. // Overrides is an optional map of pattern to deployment address.
// Contracts/libraries that refer to dependencies in the override // Contracts/libraries that refer to dependencies in the override
@ -27,8 +20,9 @@ type DeploymentParams struct {
Overrides map[string]common.Address Overrides map[string]common.Address
} }
// DeploymentResult contains the relevant information from the deployment of // DeploymentResult encapsulates information about the result of the deployment
// multiple contracts: their deployment txs and addresses. // of a set of contracts: the pending deployment transactions, and the addresses
// where the contracts will be deployed at.
type DeploymentResult struct { type DeploymentResult struct {
// map of contract library pattern -> deploy transaction // map of contract library pattern -> deploy transaction
Txs map[string]*types.Transaction Txs map[string]*types.Transaction
@ -36,6 +30,7 @@ type DeploymentResult struct {
Addrs map[string]common.Address Addrs map[string]common.Address
} }
// Accumulate merges two DeploymentResult objects together.
func (d *DeploymentResult) Accumulate(other *DeploymentResult) { func (d *DeploymentResult) Accumulate(other *DeploymentResult) {
for pattern, tx := range other.Txs { for pattern, tx := range other.Txs {
d.Txs[pattern] = tx d.Txs[pattern] = tx
@ -45,8 +40,8 @@ func (d *DeploymentResult) Accumulate(other *DeploymentResult) {
} }
} }
// depTreeBuilder turns a set of unlinked contracts and their dependent libraries into a collection of trees // depTreeBuilder turns a set of unlinked contracts libraries into a set of one
// representing the relation of their dependencies. // or more dependency trees.
type depTreeBuilder struct { type depTreeBuilder struct {
overrides map[string]common.Address overrides map[string]common.Address
// map of pattern to unlinked contract bytecode (for libraries or contracts) // map of pattern to unlinked contract bytecode (for libraries or contracts)
@ -67,8 +62,7 @@ type depTreeNode struct {
overrideAddr *common.Address overrideAddr *common.Address
} }
// returns the subtree as a map of pattern -> unlinked contract bytecode. it excludes the code of the top-level // Flatten returns the subtree into a map of pattern -> unlinked contract bytecode.
// node.
func (n *depTreeNode) Flatten() (res map[string]string) { func (n *depTreeNode) Flatten() (res map[string]string) {
res = map[string]string{n.pattern: n.unlinkedCode} res = map[string]string{n.pattern: n.unlinkedCode}
for _, child := range n.children { for _, child := range n.children {
@ -81,6 +75,7 @@ func (n *depTreeNode) Flatten() (res map[string]string) {
return res return res
} }
// buildDepTrees is the internal version of BuildDepTrees that recursively calls itself.
func (d *depTreeBuilder) buildDepTrees(pattern, contract string) { func (d *depTreeBuilder) buildDepTrees(pattern, contract string) {
// if the node is in the subtree set already, it has already been fully recursed/built so we can bail out. // if the node is in the subtree set already, it has already been fully recursed/built so we can bail out.
if _, ok := d.subtrees[pattern]; ok { if _, ok := d.subtrees[pattern]; ok {
@ -93,7 +88,7 @@ func (d *depTreeBuilder) buildDepTrees(pattern, contract string) {
if addr, ok := d.overrides[pattern]; ok { if addr, ok := d.overrides[pattern]; ok {
node.overrideAddr = &addr node.overrideAddr = &addr
} }
// iterate each referenced library in the unlinked code, recurse and built its subtree. // iterate each referenced library in the unlinked code, recurse and build its subtree.
reMatchSpecificPattern, err := regexp.Compile(`__\$([a-f0-9]+)\$__`) reMatchSpecificPattern, err := regexp.Compile(`__\$([a-f0-9]+)\$__`)
if err != nil { if err != nil {
panic(err) panic(err)
@ -111,14 +106,12 @@ func (d *depTreeBuilder) buildDepTrees(pattern, contract string) {
// BuildDepTrees will compute a set of dependency trees from a set of unlinked contracts. The root of each tree // BuildDepTrees will compute a set of dependency trees from a set of unlinked contracts. The root of each tree
// corresponds to a contract/library that is not referenced as a dependency anywhere else. Children of each node are // corresponds to a contract/library that is not referenced as a dependency anywhere else. Children of each node are
// its library dependencies. // its library dependencies. It returns nodes that are roots of a dependency tree and nodes that aren't.
func (d *depTreeBuilder) BuildDepTrees() (roots []*depTreeNode, nonRoots []*depTreeNode) { func (d *depTreeBuilder) BuildDepTrees() (roots []*depTreeNode, nonRoots []*depTreeNode) {
// before the trees of dependencies are known, consider that any provided contract could be a root. // before the trees of dependencies are known, consider that any provided contract could be a root.
for pattern, _ := range d.contracts { for pattern, _ := range d.contracts {
d.roots[pattern] = struct{}{} d.roots[pattern] = struct{}{}
} }
// recursively build each part of the dependency subtree by starting at
for pattern, contract := range d.contracts { for pattern, contract := range d.contracts {
d.buildDepTrees(pattern, contract) d.buildDepTrees(pattern, contract)
} }
@ -141,7 +134,9 @@ func newDepTreeBuilder(overrides map[string]common.Address, contracts map[string
} }
} }
type deployFn func(input, deployer []byte) (common.Address, *types.Transaction, error) // DeployFn deploys a contract given a deployer and optional input. It returns
// the address and a pending transaction, or an error if the deployment failed.
type DeployFn func(input, deployer []byte) (common.Address, *types.Transaction, error)
// depTreeDeployer is responsible for taking a dependency, deploying-and-linking its components in the proper // depTreeDeployer is responsible for taking a dependency, deploying-and-linking its components in the proper
// order. A depTreeDeployer cannot be used after calling LinkAndDeploy other than to retrieve the deployment result. // order. A depTreeDeployer cannot be used after calling LinkAndDeploy other than to retrieve the deployment result.
@ -149,26 +144,22 @@ type depTreeDeployer struct {
deployedAddrs map[string]common.Address deployedAddrs map[string]common.Address
deployerTxs map[string]*types.Transaction deployerTxs map[string]*types.Transaction
input map[string][]byte // map of the root contract pattern to the constructor input (if there is any) input map[string][]byte // map of the root contract pattern to the constructor input (if there is any)
deploy deployFn deploy DeployFn
err error
} }
// linkAndDeploy recursively deploys a contract/library: starting by linking/deploying its dependencies. // linkAndDeploy recursively deploys a contract and its dependencies: starting by linking/deploying its dependencies.
// The deployment result (deploy addresses/txs or an error) is stored in the depTreeDeployer object. // The deployment result (deploy addresses/txs or an error) is stored in the depTreeDeployer object.
func (d *depTreeDeployer) linkAndDeploy(node *depTreeNode) { func (d *depTreeDeployer) linkAndDeploy(node *depTreeNode) error {
// short-circuit further deployment of contracts if a previous deployment encountered an error.
if d.err != nil {
return
}
// don't deploy contracts specified as overrides. don't deploy their dependencies. // don't deploy contracts specified as overrides. don't deploy their dependencies.
if node.overrideAddr != nil { if node.overrideAddr != nil {
return return nil
} }
// if this contract/library depends on other libraries deploy them (and their dependencies) first // if this contract/library depends on other libraries deploy them (and their dependencies) first
for _, childNode := range node.children { for _, childNode := range node.children {
d.linkAndDeploy(childNode) if err := d.linkAndDeploy(childNode); err != nil {
return err
}
} }
// if we just deployed any prerequisite contracts, link their deployed addresses into the bytecode to produce // if we just deployed any prerequisite contracts, link their deployed addresses into the bytecode to produce
// a deployer bytecode for this contract. // a deployer bytecode for this contract.
@ -186,25 +177,23 @@ func (d *depTreeDeployer) linkAndDeploy(node *depTreeNode) {
// Finally, deploy the contract. // Finally, deploy the contract.
addr, tx, err := d.deploy(d.input[node.pattern], common.Hex2Bytes(deployerCode)) addr, tx, err := d.deploy(d.input[node.pattern], common.Hex2Bytes(deployerCode))
if err != nil { if err != nil {
d.err = err return err
} else { }
d.deployedAddrs[node.pattern] = addr d.deployedAddrs[node.pattern] = addr
d.deployerTxs[node.pattern] = tx d.deployerTxs[node.pattern] = tx
} return nil
} }
// result returns a result for this deployment, or an error if it failed. // result returns a result for this deployment, or an error if it failed.
func (d *depTreeDeployer) result() (*DeploymentResult, error) { func (d *depTreeDeployer) result() *DeploymentResult {
if d.err != nil {
return nil, d.err
}
return &DeploymentResult{ return &DeploymentResult{
Txs: d.deployerTxs, Txs: d.deployerTxs,
Addrs: d.deployedAddrs, Addrs: d.deployedAddrs,
}, nil }
} }
func newDepTreeDeployer(deploy deployFn) *depTreeDeployer { func newDepTreeDeployer(deploy DeployFn) *depTreeDeployer {
return &depTreeDeployer{ return &depTreeDeployer{
deploy: deploy, deploy: deploy,
deployedAddrs: make(map[string]common.Address), deployedAddrs: make(map[string]common.Address),
@ -214,7 +203,7 @@ func newDepTreeDeployer(deploy deployFn) *depTreeDeployer {
// LinkAndDeploy deploys a specified set of contracts and their dependent // LinkAndDeploy deploys a specified set of contracts and their dependent
// libraries. If an error occurs, only contracts which were successfully // libraries. If an error occurs, only contracts which were successfully
// deployed are returned in the result. // deployed are returned in the result.
func LinkAndDeploy(deployParams DeploymentParams, deploy deployFn) (res *DeploymentResult, err error) { func LinkAndDeploy(deployParams DeploymentParams, deploy DeployFn) (res *DeploymentResult, err error) {
unlinkedContracts := make(map[string]string) unlinkedContracts := make(map[string]string)
accumRes := &DeploymentResult{ accumRes := &DeploymentResult{
Txs: make(map[string]*types.Transaction), Txs: make(map[string]*types.Transaction),
@ -231,12 +220,12 @@ func LinkAndDeploy(deployParams DeploymentParams, deploy deployFn) (res *Deploym
if deployParams.Inputs != nil { if deployParams.Inputs != nil {
deployer.input = map[string][]byte{tr.pattern: deployParams.Inputs[tr.pattern]} deployer.input = map[string][]byte{tr.pattern: deployParams.Inputs[tr.pattern]}
} }
deployer.linkAndDeploy(tr) err := deployer.linkAndDeploy(tr)
res, err := deployer.result() res := deployer.result()
accumRes.Accumulate(res)
if err != nil { if err != nil {
return accumRes, err return accumRes, err
} }
accumRes.Accumulate(res)
} }
return accumRes, nil return accumRes, nil
} }