move contract dep tree, link-and-deploy to bind package. This is so that bind can build the dependency tree for each library to populate their exported deps.

This commit is contained in:
Jared Wasinger 2024-12-15 17:35:25 +07:00 committed by Felix Lange
parent 7000583654
commit 2421cc3ed5
6 changed files with 291 additions and 282 deletions

View File

@ -404,51 +404,6 @@ func bind(types []string, abis []string, bytecodes []string, fsigs []map[string]
contracts[types[i]].Library = ok
}
// compute the full set of libraries that each contract depends on.
for _, contract := range contracts {
if contract.Library {
continue
}
// recursively traverse the library dependency graph
// of the contract, flattening it into a set.
//
// For abigenv2, we do not generate contract deploy
// methods (which in v1 recursively deploy their
// library dependencies). So, the entire set of
// library dependencies is required, and we will
// determine the order to deploy and link them at
// runtime.
var findDeps func(contract *tmplContract) map[string]struct{}
findDeps = func(contract *tmplContract) map[string]struct{} {
// 1) match all libraries that this contract depends on
re, err := regexp.Compile(`__\$([a-f0-9]+)\$__`)
if err != nil {
panic(err)
}
libBin := contracts[contract.Type].InputBin
matches := re.FindAllStringSubmatch(libBin, -1)
result := make(map[string]struct{})
// 2) recurse, gathering nested library dependencies
for _, match := range matches {
pattern := match[1]
result[pattern] = struct{}{}
depContract := contracts[libs[pattern]]
for subPattern, _ := range findDeps(depContract) {
result[subPattern] = struct{}{}
}
}
return result
}
// take the set of library patterns, convert it to a map of type -> pattern
deps := findDeps(contract)
contract.AllLibraries = make(map[string]string)
for contractPattern, _ := range deps {
contractType := libs[contractPattern]
contract.AllLibraries[contractType] = contractPattern
}
}
// map of contract name -> pattern
invertedLibs := make(map[string]string)
// assume that this is invertible/onto because I assume library names are unique now
@ -457,6 +412,25 @@ func bind(types []string, abis []string, bytecodes []string, fsigs []map[string]
invertedLibs[name] = pattern
}
contractsBins := make(map[string]string)
for typ, contract := range contracts {
pattern := invertedLibs[typ]
contractsBins[pattern] = contract.InputBin
}
builder := newDepTreeBuilder(nil, contractsBins)
roots, deps := builder.BuildDepTrees()
allNodes := append(roots, deps...)
for _, dep := range allNodes {
contractType := libs[dep.pattern]
for subDepPattern, _ := range dep.Flatten() {
if subDepPattern == dep.pattern {
continue
}
subDepType := libs[subDepPattern]
contracts[contractType].AllLibraries[subDepType] = subDepPattern
}
}
// Generate the contract template data content and render it
data := &tmplData{
Package: pkg,

View File

@ -0,0 +1,242 @@
package bind
import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"regexp"
"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
// set of contracts, their dependency libraries. It takes an optional override
// list to specify libraries that have already been deployed on-chain.
type DeploymentParams struct {
Contracts []*MetaData
Inputs map[string][]byte
// Overrides is an optional map of pattern to deployment address.
// Contracts/libraries that refer to dependencies in the override
// set are linked to the provided address (an already-deployed contract).
Overrides map[string]common.Address
}
// DeploymentResult contains the relevant information from the deployment of
// multiple contracts: their deployment txs and addresses.
type DeploymentResult struct {
// map of contract library pattern -> deploy transaction
Txs map[string]*types.Transaction
// map of contract library pattern -> deployed address
Addrs map[string]common.Address
}
func (d *DeploymentResult) Accumulate(other *DeploymentResult) {
for pattern, tx := range other.Txs {
d.Txs[pattern] = tx
}
for pattern, addr := range other.Addrs {
d.Addrs[pattern] = addr
}
}
// depTreeBuilder turns a set of unlinked contracts and their dependent libraries into a collection of trees
// representing the relation of their dependencies.
type depTreeBuilder struct {
overrides map[string]common.Address
// map of pattern to unlinked contract bytecode (for libraries or contracts)
contracts map[string]string
// map of pattern to subtree represented by contract
subtrees map[string]*depTreeNode
// map of nodes that aren't referenced by other dependencies (these can be libraries too if user is doing lib-only deployment)
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 {
pattern string
unlinkedCode string
children []*depTreeNode
overrideAddr *common.Address
}
// returns the subtree as a map of pattern -> unlinked contract bytecode. it excludes the code of the top-level
// node.
func (n *depTreeNode) Flatten() (res map[string]string) {
res = map[string]string{n.pattern: n.unlinkedCode}
for _, child := range n.children {
subtree := child.Flatten()
for k, v := range subtree {
res[k] = v
}
}
return res
}
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 _, ok := d.subtrees[pattern]; ok {
return
}
node := &depTreeNode{
pattern: pattern,
unlinkedCode: contract,
}
if addr, ok := d.overrides[pattern]; ok {
node.overrideAddr = &addr
}
// iterate each referenced library in the unlinked code, recurse and built its subtree.
reMatchSpecificPattern, err := regexp.Compile(`__\$([a-f0-9]+)\$__`)
if err != nil {
panic(err)
}
for _, match := range reMatchSpecificPattern.FindAllStringSubmatch(contract, -1) {
depPattern := match[1]
d.buildDepTrees(depPattern, d.contracts[depPattern])
node.children = append(node.children, d.subtrees[depPattern])
// this library can't be a root dependency if it is referenced by other contracts.
delete(d.roots, depPattern)
}
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, nonRoots []*depTreeNode) {
// before the trees of dependencies are known, consider that any provided contract could be a root.
for pattern, _ := range d.contracts {
d.roots[pattern] = struct{}{}
}
// recursively build each part of the dependency subtree by starting at
for pattern, contract := range d.contracts {
d.buildDepTrees(pattern, contract)
}
for pattern, _ := range d.contracts {
if _, ok := d.roots[pattern]; ok {
roots = append(roots, d.subtrees[pattern])
} else {
nonRoots = append(nonRoots, d.subtrees[pattern])
}
}
return roots, nonRoots
}
func newDepTreeBuilder(overrides map[string]common.Address, contracts map[string]string) *depTreeBuilder {
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 {
deployedAddrs map[string]common.Address
deployerTxs map[string]*types.Transaction
input map[string][]byte // map of the root contract pattern to the constructor input (if there is any)
deploy deployFn
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) {
// 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.
if node.overrideAddr != nil {
return
}
// if this contract/library depends on other libraries deploy them (and their dependencies) first
for _, childNode := range node.children {
d.linkAndDeploy(childNode)
}
// 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
for _, child := range node.children {
var linkAddr common.Address
if child.overrideAddr != nil {
linkAddr = *child.overrideAddr
} else {
linkAddr = d.deployedAddrs[child.pattern]
}
deployerCode = strings.ReplaceAll(deployerCode, "__$"+child.pattern+"$__", strings.ToLower(linkAddr.String()[2:]))
}
// Finally, deploy the contract.
addr, tx, err := d.deploy(d.input[node.pattern], common.Hex2Bytes(deployerCode))
if err != nil {
d.err = err
} else {
d.deployedAddrs[node.pattern] = addr
d.deployerTxs[node.pattern] = tx
}
}
// result returns a result for this deployment, or an error if it failed.
func (d *depTreeDeployer) result() (*DeploymentResult, error) {
if d.err != nil {
return nil, d.err
}
return &DeploymentResult{
Txs: d.deployerTxs,
Addrs: d.deployedAddrs,
}, 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
// libraries. If an error occurs, only contracts which were successfully
// deployed are returned in the result.
func LinkAndDeploy(deployParams DeploymentParams, deploy deployFn) (res *DeploymentResult, err error) {
unlinkedContracts := make(map[string]string)
accumRes := &DeploymentResult{
Txs: make(map[string]*types.Transaction),
Addrs: make(map[string]common.Address),
}
for _, meta := range deployParams.Contracts {
unlinkedContracts[meta.Pattern] = meta.Bin[2:]
}
treeBuilder := newDepTreeBuilder(deployParams.Overrides, unlinkedContracts)
deps, _ := treeBuilder.BuildDepTrees()
for _, tr := range deps {
deployer := newDepTreeDeployer(deploy)
if deployParams.Inputs != nil {
deployer.input = map[string][]byte{tr.pattern: deployParams.Inputs[tr.pattern]}
}
deployer.linkAndDeploy(tr)
res, err := deployer.result()
if err != nil {
return accumRes, err
}
accumRes.Accumulate(res)
}
return accumRes, nil
}

View File

@ -13,13 +13,12 @@
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package v2
package bind
import (
"fmt"
"testing"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
@ -87,6 +86,8 @@ func makeLinkTestCase(input map[rune][]rune, overrides map[rune]common.Address)
}
}
var testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
type linkTestCaseInput struct {
input map[rune][]rune
overrides map[rune]struct{}
@ -141,10 +142,10 @@ func testLinkCase(t *testing.T, tcInput linkTestCaseInput) {
deployParams DeploymentParams
)
for pattern, bin := range tc.contractCodes {
deployParams.Contracts = append(deployParams.Contracts, &bind.MetaData{Pattern: pattern, Bin: "0x" + bin})
deployParams.Contracts = append(deployParams.Contracts, &MetaData{Pattern: pattern, Bin: "0x" + bin})
}
for pattern, bin := range tc.libCodes {
deployParams.Contracts = append(deployParams.Contracts, &bind.MetaData{
deployParams.Contracts = append(deployParams.Contracts, &MetaData{
Bin: "0x" + bin,
Pattern: pattern,
})

View File

@ -176,7 +176,9 @@ func (_L1 *L1) UnpackDo(data []byte) (*big.Int, error) {
}
var L2LibraryDeps = []*bind.MetaData{}
var L2LibraryDeps = []*bind.MetaData{
L1MetaData,
}
// TODO: convert this type to value type after everything works.
// L2MetaData contains all meta data concerning the L2 contract.
@ -224,7 +226,9 @@ func (_L2 *L2) UnpackDo(data []byte) (*big.Int, error) {
}
var L2bLibraryDeps = []*bind.MetaData{}
var L2bLibraryDeps = []*bind.MetaData{
L1MetaData,
}
// TODO: convert this type to value type after everything works.
// L2bMetaData contains all meta data concerning the L2b contract.
@ -320,7 +324,11 @@ func (_L3 *L3) UnpackDo(data []byte) (*big.Int, error) {
}
var L4LibraryDeps = []*bind.MetaData{}
var L4LibraryDeps = []*bind.MetaData{
L1MetaData,
L2MetaData,
L3MetaData,
}
// TODO: convert this type to value type after everything works.
// L4MetaData contains all meta data concerning the L4 contract.
@ -368,7 +376,10 @@ func (_L4 *L4) UnpackDo(data []byte) (*big.Int, error) {
}
var L4bLibraryDeps = []*bind.MetaData{}
var L4bLibraryDeps = []*bind.MetaData{
L1MetaData,
L2bMetaData,
}
// TODO: convert this type to value type after everything works.
// L4bMetaData contains all meta data concerning the L4b contract.

View File

@ -17,9 +17,6 @@
package v2
import (
"regexp"
"strings"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
@ -28,222 +25,6 @@ import (
"github.com/ethereum/go-ethereum/event"
)
// 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 *bind.MetaData
// Input is the ABI-encoded constructor input for the contract deployment.
Input []byte
}
// DeploymentParams represents parameters needed to deploy a
// set of contracts, their dependency libraries. It takes an optional override
// list to specify libraries that have already been deployed on-chain.
type DeploymentParams struct {
Contracts []*bind.MetaData
Inputs map[string][]byte
// Overrides is an optional map of pattern to deployment address.
// Contracts/libraries that refer to dependencies in the override
// set are linked to the provided address (an already-deployed contract).
Overrides map[string]common.Address
}
// DeploymentResult contains the relevant information from the deployment of
// multiple contracts: their deployment txs and addresses.
type DeploymentResult struct {
// map of contract library pattern -> deploy transaction
Txs map[string]*types.Transaction
// map of contract library pattern -> deployed address
Addrs map[string]common.Address
}
func (d *DeploymentResult) Accumulate(other *DeploymentResult) {
for pattern, tx := range other.Txs {
d.Txs[pattern] = tx
}
for pattern, addr := range other.Addrs {
d.Addrs[pattern] = addr
}
}
// depTreeBuilder turns a set of unlinked contracts and their dependent libraries into a collection of trees
// representing the relation of their dependencies.
type depTreeBuilder struct {
overrides map[string]common.Address
// map of pattern to unlinked contract bytecode (for libraries or contracts)
contracts map[string]string
// map of pattern to subtree represented by contract
subtrees map[string]*depTreeNode
// map of nodes that aren't referenced by other dependencies (these can be libraries too if user is doing lib-only deployment)
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 {
pattern string
unlinkedCode string
nodes []*depTreeNode
overrideAddr *common.Address
}
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 _, ok := d.subtrees[pattern]; ok {
return
}
node := &depTreeNode{
pattern: pattern,
unlinkedCode: contract,
}
if addr, ok := d.overrides[pattern]; ok {
node.overrideAddr = &addr
}
// iterate each referenced library in the unlinked code, recurse and built its subtree.
reMatchSpecificPattern, err := regexp.Compile(`__\$([a-f0-9]+)\$__`)
if err != nil {
panic(err)
}
for _, match := range reMatchSpecificPattern.FindAllStringSubmatch(contract, -1) {
depPattern := match[1]
d.buildDepTrees(depPattern, d.contracts[depPattern])
node.nodes = append(node.nodes, d.subtrees[depPattern])
// this library can't be a root dependency if it is referenced by other contracts.
delete(d.roots, depPattern)
}
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) {
// before the trees of dependencies are known, consider that any provided contract could be a root.
for pattern, _ := range d.contracts {
d.roots[pattern] = struct{}{}
}
// recursively build each part of the dependency subtree by starting at
for pattern, contract := range d.contracts {
d.buildDepTrees(pattern, contract)
}
for pattern, _ := range d.roots {
roots = append(roots, d.subtrees[pattern])
}
return roots
}
func newDepTreeBuilder(overrides map[string]common.Address, contracts map[string]string) *depTreeBuilder {
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 {
deployedAddrs map[string]common.Address
deployerTxs map[string]*types.Transaction
input map[string][]byte // map of the root contract pattern to the constructor input (if there is any)
deploy deployFn
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) {
// 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.
if node.overrideAddr != nil {
return
}
// if this contract/library depends on other libraries deploy them (and their dependencies) first
for _, childNode := range node.nodes {
d.linkAndDeploy(childNode)
}
// 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
for _, child := range node.nodes {
var linkAddr common.Address
if child.overrideAddr != nil {
linkAddr = *child.overrideAddr
} else {
linkAddr = d.deployedAddrs[child.pattern]
}
deployerCode = strings.ReplaceAll(deployerCode, "__$"+child.pattern+"$__", strings.ToLower(linkAddr.String()[2:]))
}
// Finally, deploy the contract.
addr, tx, err := d.deploy(d.input[node.pattern], common.Hex2Bytes(deployerCode))
if err != nil {
d.err = err
} else {
d.deployedAddrs[node.pattern] = addr
d.deployerTxs[node.pattern] = tx
}
}
// result returns a result for this deployment, or an error if it failed.
func (d *depTreeDeployer) result() (*DeploymentResult, error) {
if d.err != nil {
return nil, d.err
}
return &DeploymentResult{
Txs: d.deployerTxs,
Addrs: d.deployedAddrs,
}, 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
// libraries. If an error occurs, only contracts which were successfully
// deployed are returned in the result.
func LinkAndDeploy(deployParams DeploymentParams, deploy deployFn) (res *DeploymentResult, err error) {
unlinkedContracts := make(map[string]string)
accumRes := &DeploymentResult{
Txs: make(map[string]*types.Transaction),
Addrs: make(map[string]common.Address),
}
for _, meta := range deployParams.Contracts {
unlinkedContracts[meta.Pattern] = meta.Bin[2:]
}
treeBuilder := newDepTreeBuilder(deployParams.Overrides, unlinkedContracts)
deps := treeBuilder.BuildDepTrees()
for _, tr := range deps {
deployer := newDepTreeDeployer(deploy)
if deployParams.Inputs != nil {
deployer.input = map[string][]byte{tr.pattern: deployParams.Inputs[tr.pattern]}
}
deployer.linkAndDeploy(tr)
res, err := deployer.result()
if err != nil {
return accumRes, err
}
accumRes.Accumulate(res)
}
return accumRes, nil
}
// TODO: this will be generated as part of the bindings, contain the ABI (or metadata object?) and errors
type ContractInstance struct {
Address common.Address

View File

@ -121,13 +121,13 @@ func TestDeploymentLibraries(t *testing.T) {
if err != nil {
t.Fatalf("failed to pack constructor: %v", err)
}
deploymentParams := DeploymentParams{
deploymentParams := bind.DeploymentParams{
Contracts: append(nested_libraries.C1LibraryDeps, nested_libraries.C1MetaData),
Inputs: map[string][]byte{nested_libraries.C1MetaData.Pattern: constructorInput},
Overrides: nil,
}
res, err := LinkAndDeploy(deploymentParams, makeTestDeployer(opts, bindBackend))
res, err := bind.LinkAndDeploy(deploymentParams, makeTestDeployer(opts, bindBackend))
if err != nil {
t.Fatalf("err: %+v\n", err)
}
@ -180,11 +180,11 @@ func TestDeploymentWithOverrides(t *testing.T) {
defer bindBackend.Backend.Close()
// deploy some library deps
deploymentParams := DeploymentParams{
deploymentParams := bind.DeploymentParams{
Contracts: nested_libraries.C1LibraryDeps,
}
res, err := LinkAndDeploy(deploymentParams, makeTestDeployer(opts, bindBackend))
res, err := bind.LinkAndDeploy(deploymentParams, makeTestDeployer(opts, bindBackend))
if err != nil {
t.Fatalf("err: %+v\n", err)
}
@ -210,12 +210,12 @@ func TestDeploymentWithOverrides(t *testing.T) {
}
overrides := res.Addrs
// deploy the contract
deploymentParams = DeploymentParams{
deploymentParams = bind.DeploymentParams{
Contracts: []*bind.MetaData{nested_libraries.C1MetaData},
Inputs: map[string][]byte{nested_libraries.C1MetaData.Pattern: constructorInput},
Overrides: overrides,
}
res, err = LinkAndDeploy(deploymentParams, makeTestDeployer(opts, bindBackend))
res, err = bind.LinkAndDeploy(deploymentParams, makeTestDeployer(opts, bindBackend))
if err != nil {
t.Fatalf("err: %+v\n", err)
}
@ -271,11 +271,11 @@ func TestEvents(t *testing.T) {
t.Fatalf("error setting up testing env: %v", err)
}
deploymentParams := DeploymentParams{
deploymentParams := bind.DeploymentParams{
Contracts: []*bind.MetaData{events.CMetaData},
}
res, err := LinkAndDeploy(deploymentParams, makeTestDeployer(txAuth, backend))
res, err := bind.LinkAndDeploy(deploymentParams, makeTestDeployer(txAuth, backend))
if err != nil {
t.Fatalf("error deploying contract for testing: %v", err)
}
@ -387,11 +387,11 @@ func TestErrors(t *testing.T) {
t.Fatalf("error setting up testing env: %v", err)
}
deploymentParams := DeploymentParams{
deploymentParams := bind.DeploymentParams{
Contracts: []*bind.MetaData{solc_errors.CMetaData},
}
res, err := LinkAndDeploy(deploymentParams, makeTestDeployer(txAuth, backend))
res, err := bind.LinkAndDeploy(deploymentParams, makeTestDeployer(txAuth, backend))
if err != nil {
t.Fatalf("error deploying contract for testing: %v", err)
}