mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-12 06:53:46 +00:00
clean up link/deploy code. add docs
This commit is contained in:
parent
47192a758c
commit
645c844f4b
1 changed files with 50 additions and 26 deletions
|
|
@ -77,6 +77,9 @@ type depTreeBuilder struct {
|
||||||
roots map[string]struct{}
|
roots map[string]struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// depTreeNode represents a node (contract) in a dependency tree. it contains its unlinked code, and references to any
|
||||||
|
// library contracts that it requires. If it is specified as an override, it contains the address where it has already
|
||||||
|
// been deployed at.
|
||||||
type depTreeNode struct {
|
type depTreeNode struct {
|
||||||
pattern string
|
pattern string
|
||||||
unlinkedCode string
|
unlinkedCode string
|
||||||
|
|
@ -85,11 +88,10 @@ type depTreeNode struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *depTreeBuilder) buildDepTrees(pattern, contract string) {
|
func (d *depTreeBuilder) buildDepTrees(pattern, contract string) {
|
||||||
// if the node is in the subtree set already, bail out early
|
// 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 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
node := &depTreeNode{
|
node := &depTreeNode{
|
||||||
pattern: pattern,
|
pattern: pattern,
|
||||||
unlinkedCode: contract,
|
unlinkedCode: contract,
|
||||||
|
|
@ -97,7 +99,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.
|
||||||
reMatchSpecificPattern, err := regexp.Compile("__\\$([a-f0-9]+)\\$__")
|
reMatchSpecificPattern, err := regexp.Compile("__\\$([a-f0-9]+)\\$__")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
|
@ -107,12 +109,15 @@ func (d *depTreeBuilder) buildDepTrees(pattern, contract string) {
|
||||||
d.buildDepTrees(depPattern, d.contracts[depPattern])
|
d.buildDepTrees(depPattern, d.contracts[depPattern])
|
||||||
node.nodes = append(node.nodes, d.subtrees[depPattern])
|
node.nodes = append(node.nodes, d.subtrees[depPattern])
|
||||||
|
|
||||||
// this dep can't be a root dependency if it is referenced by other contracts.
|
// this library can't be a root dependency if it is referenced by other contracts.
|
||||||
delete(d.roots, depPattern)
|
delete(d.roots, depPattern)
|
||||||
}
|
}
|
||||||
d.subtrees[pattern] = node
|
d.subtrees[pattern] = node
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
// its library dependencies.
|
||||||
func (d *depTreeBuilder) BuildDepTrees() (roots []*depTreeNode) {
|
func (d *depTreeBuilder) BuildDepTrees() (roots []*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 {
|
||||||
|
|
@ -129,26 +134,46 @@ func (d *depTreeBuilder) BuildDepTrees() (roots []*depTreeNode) {
|
||||||
return roots
|
return roots
|
||||||
}
|
}
|
||||||
|
|
||||||
// depTreeDeployer is responsible for taking a built dependency, deploying-and-linking its components in the proper
|
func newDepTreeBuilder(overrides map[string]common.Address, contracts map[string]string) *depTreeBuilder {
|
||||||
// order.
|
return &depTreeBuilder{
|
||||||
|
overrides: overrides,
|
||||||
|
contracts: contracts,
|
||||||
|
subtrees: make(map[string]*depTreeNode),
|
||||||
|
roots: make(map[string]struct{}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
// order. A depTreeDeployer cannot be used after calling LinkAndDeploy other than to retrieve the deployment result.
|
||||||
type depTreeDeployer struct {
|
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 func(input, deployer []byte) (common.Address, *types.Transaction, error)
|
deploy deployFn
|
||||||
err error
|
err error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// linkAndDeploy recursively deploys a contract/library: starting by linking/deploying its dependencies.
|
||||||
|
// 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) {
|
||||||
if node.overrideAddr != nil {
|
// short-circuit further deployment of contracts if a previous deployment encountered an error.
|
||||||
// don't recurse on override nodes
|
if d.err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// don't deploy contracts specified as overrides. don't deploy their dependencies.
|
||||||
|
if node.overrideAddr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// if this contract/library depends on other libraries deploy them (and their dependencies) first
|
||||||
for _, childNode := range node.nodes {
|
for _, childNode := range node.nodes {
|
||||||
d.linkAndDeploy(childNode)
|
d.linkAndDeploy(childNode)
|
||||||
}
|
}
|
||||||
// link in all node dependencies and produce the deployer bytecode
|
// if we just deployed any prerequisite contracts, link their deployed addresses into the bytecode to produce
|
||||||
|
// a deployer bytecode for this contract.
|
||||||
deployerCode := node.unlinkedCode
|
deployerCode := node.unlinkedCode
|
||||||
for _, child := range node.nodes {
|
for _, child := range node.nodes {
|
||||||
var linkAddr common.Address
|
var linkAddr common.Address
|
||||||
|
|
@ -160,7 +185,7 @@ func (d *depTreeDeployer) linkAndDeploy(node *depTreeNode) {
|
||||||
deployerCode = strings.ReplaceAll(deployerCode, "__$"+child.pattern+"$__", strings.ToLower(linkAddr.String()[2:]))
|
deployerCode = strings.ReplaceAll(deployerCode, "__$"+child.pattern+"$__", strings.ToLower(linkAddr.String()[2:]))
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
d.err = err
|
||||||
|
|
@ -170,7 +195,8 @@ func (d *depTreeDeployer) linkAndDeploy(node *depTreeNode) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *depTreeDeployer) Result() (*DeploymentResult, error) {
|
// result returns a result for this deployment, or an error if it failed.
|
||||||
|
func (d *depTreeDeployer) result() (*DeploymentResult, error) {
|
||||||
if d.err != nil {
|
if d.err != nil {
|
||||||
return nil, d.err
|
return nil, d.err
|
||||||
}
|
}
|
||||||
|
|
@ -180,10 +206,17 @@ func (d *depTreeDeployer) Result() (*DeploymentResult, error) {
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func newDepTreeDeployer(deploy deployFn) *depTreeDeployer {
|
||||||
|
return &depTreeDeployer{
|
||||||
|
deploy: deploy,
|
||||||
|
deployedAddrs: make(map[string]common.Address),
|
||||||
|
deployerTxs: make(map[string]*types.Transaction)}
|
||||||
|
}
|
||||||
|
|
||||||
// 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 func(input, deployer []byte) (common.Address, *types.Transaction, error)) (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),
|
||||||
|
|
@ -192,25 +225,16 @@ func LinkAndDeploy(deployParams DeploymentParams, deploy func(input, deployer []
|
||||||
for _, meta := range deployParams.Contracts {
|
for _, meta := range deployParams.Contracts {
|
||||||
unlinkedContracts[meta.Pattern] = meta.Bin[2:]
|
unlinkedContracts[meta.Pattern] = meta.Bin[2:]
|
||||||
}
|
}
|
||||||
// TODO: instantiate this using constructor
|
treeBuilder := newDepTreeBuilder(deployParams.Overrides, unlinkedContracts)
|
||||||
treeBuilder := depTreeBuilder{
|
|
||||||
overrides: deployParams.Overrides,
|
|
||||||
contracts: unlinkedContracts,
|
|
||||||
subtrees: make(map[string]*depTreeNode),
|
|
||||||
roots: make(map[string]struct{}),
|
|
||||||
}
|
|
||||||
|
|
||||||
deps := treeBuilder.BuildDepTrees()
|
deps := treeBuilder.BuildDepTrees()
|
||||||
|
|
||||||
for _, tr := range deps {
|
for _, tr := range deps {
|
||||||
deployer := depTreeDeployer{
|
deployer := newDepTreeDeployer(deploy)
|
||||||
deploy: deploy,
|
|
||||||
deployedAddrs: make(map[string]common.Address),
|
|
||||||
deployerTxs: make(map[string]*types.Transaction)}
|
|
||||||
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)
|
deployer.linkAndDeploy(tr)
|
||||||
res, err := deployer.Result()
|
res, err := deployer.result()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return accumRes, err
|
return accumRes, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue