Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Parallelize bootstrap rootchain CLI commands #1468

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ test-e2e-polybft:
# We can not build with race because of a bug in boltdb dependency
go build -o artifacts/polygon-edge .
env EDGE_BINARY=${PWD}/artifacts/polygon-edge E2E_TESTS=true E2E_LOGS=true \
go test -v -timeout=1h30m ./e2e-polybft/e2e/...
go test -v -timeout=1h ./e2e-polybft/e2e/...

.PHONY: test-property-polybft
test-property-polybft:
Expand Down
157 changes: 112 additions & 45 deletions command/rootchain/deploy/deploy.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
package deploy

import (
"context"
"errors"
"fmt"
"math/big"

"github.com/spf13/cobra"
"github.com/umbracle/ethgo"
"github.com/umbracle/ethgo/jsonrpc"
"golang.org/x/sync/errgroup"

"github.com/0xPolygon/polygon-edge/chain"
"github.com/0xPolygon/polygon-edge/command"
Expand Down Expand Up @@ -98,6 +100,53 @@ var (
rootchainConfig.StakeManagerAddress = addr
},
}

// initializersMap maps rootchain contract names to initializer function callbacks
initializersMap = map[string]func(command.OutputFormatter, txrelayer.TxRelayer,
*polybft.RootchainConfig, ethgo.Key) error{
stakeManagerName: func(fmt command.OutputFormatter,
relayer txrelayer.TxRelayer,
config *polybft.RootchainConfig,
key ethgo.Key) error {

return initializeStakeManager(fmt, relayer, config, key)
},
customSupernetManagerName: func(fmt command.OutputFormatter,
relayer txrelayer.TxRelayer,
config *polybft.RootchainConfig,
key ethgo.Key) error {

return initializeSupernetManager(fmt, relayer, config, key)
},
exitHelperName: func(fmt command.OutputFormatter,
relayer txrelayer.TxRelayer,
config *polybft.RootchainConfig,
key ethgo.Key) error {

return initializeExitHelper(fmt, relayer, config, key)
},
rootERC20PredicateName: func(fmt command.OutputFormatter,
relayer txrelayer.TxRelayer,
config *polybft.RootchainConfig,
key ethgo.Key) error {

return initializeRootERC20Predicate(fmt, relayer, config, key)
},
rootERC721PredicateName: func(fmt command.OutputFormatter,
relayer txrelayer.TxRelayer,
config *polybft.RootchainConfig,
key ethgo.Key) error {

return initializeRootERC721Predicate(fmt, relayer, config, key)
},
rootERC1155PredicateName: func(fmt command.OutputFormatter,
relayer txrelayer.TxRelayer,
config *polybft.RootchainConfig,
key ethgo.Key) error {

return initializeRootERC1155Predicate(fmt, relayer, config, key)
},
}
)

// GetCommand returns the rootchain deploy command
Expand Down Expand Up @@ -213,7 +262,7 @@ func runCommand(cmd *cobra.Command, _ []string) {
}
}

rootchainCfg, chainID, err := deployContracts(outputter, client, consensusConfig.InitialValidatorSet)
rootchainCfg, chainID, err := deployContracts(outputter, client, consensusConfig.InitialValidatorSet, cmd.Context())
if err != nil {
outputter.SetError(fmt.Errorf("failed to deploy rootchain contracts: %w", err))

Expand Down Expand Up @@ -253,8 +302,7 @@ func runCommand(cmd *cobra.Command, _ []string) {

// deployContracts deploys and initializes rootchain smart contracts
func deployContracts(outputter command.OutputFormatter, client *jsonrpc.Client,
initialValidators []*polybft.Validator) (*polybft.RootchainConfig, int64, error) {
// if the bridge contract is not created, we have to deploy all the contracts
initialValidators []*polybft.Validator, cmdCtx context.Context) (*polybft.RootchainConfig, int64, error) {
txRelayer, err := txrelayer.NewTxRelayer(txrelayer.WithClient(client))
if err != nil {
return nil, 0, fmt.Errorf("failed to initialize tx relayer: %w", err)
Expand Down Expand Up @@ -378,43 +426,82 @@ func deployContracts(outputter command.OutputFormatter, client *jsonrpc.Client,

allContracts = append(tokenContracts, allContracts...)

for _, contract := range allContracts {
txn := &ethgo.Transaction{
To: nil, // contract deployment
Input: contract.artifact.Bytecode,
}
g, ctx := errgroup.WithContext(cmdCtx)
resultsCh := make(chan *deployContractResult, len(allContracts))

receipt, err := txRelayer.SendTransaction(txn, deployerKey)
if err != nil {
return nil, 0, err
}
for _, contract := range allContracts {
contract := contract

g.Go(func() error {
select {
case <-ctx.Done():
return ctx.Err()
default:
txn := &ethgo.Transaction{
To: nil, // contract deployment
Input: contract.artifact.Bytecode,
}

receipt, err := txRelayer.SendTransaction(txn, deployerKey)
if err != nil {
return err
}

if receipt == nil || receipt.Status != uint64(types.ReceiptSuccess) {
return fmt.Errorf("deployment of %s contract failed", contract.name)
}

resultsCh <- newDeployContractsResult(contract.name,
types.Address(receipt.ContractAddress),
receipt.TransactionHash)

return nil
}
})
}

if receipt == nil || receipt.Status != uint64(types.ReceiptSuccess) {
return nil, 0, fmt.Errorf("deployment of %s contract failed", contract.name)
}
if err := g.Wait(); err != nil {
return nil, 0, err
}

contractAddr := types.Address(receipt.ContractAddress)
close(resultsCh)

populatorFn, ok := metadataPopulatorMap[contract.name]
for result := range resultsCh {
populatorFn, ok := metadataPopulatorMap[result.Name]
if !ok {
return nil, 0, fmt.Errorf("rootchain metadata populator not registered for contract '%s'", contract.name)
return nil, 0, fmt.Errorf("rootchain metadata populator not registered for contract '%s'", result.Name)
}

populatorFn(rootchainConfig, contractAddr)
populatorFn(rootchainConfig, result.Address)

outputter.WriteCommandResult(newDeployContractsResult(contract.name, contractAddr, receipt.TransactionHash))
outputter.WriteCommandResult(result)
}

// init StakeManager
if err := initializeStakeManager(outputter, txRelayer, rootchainConfig, deployerKey); err != nil {
return nil, 0, err
g, ctx = errgroup.WithContext(cmdCtx)

for _, contract := range allContracts {
contract := contract

initializer, exists := initializersMap[contract.name]
if !exists {
continue
}

g.Go(func() error {
select {
case <-cmdCtx.Done():
return cmdCtx.Err()
default:
return initializer(outputter, txRelayer, rootchainConfig, deployerKey)
}
})
}

// init SupernetManager
if err := initializeSupernetManager(outputter, txRelayer, rootchainConfig, deployerKey); err != nil {
if err := g.Wait(); err != nil {
return nil, 0, err
}

// register supernets manager on stake manager
chainID, err := registerChainOnStakeManager(txRelayer, rootchainConfig, deployerKey)
if err != nil {
return nil, 0, err
Expand All @@ -426,26 +513,6 @@ func deployContracts(outputter command.OutputFormatter, client *jsonrpc.Client,
return nil, 0, err
}

// init ExitHelper
if err := initializeExitHelper(outputter, txRelayer, rootchainConfig, deployerKey); err != nil {
return nil, 0, err
}

// init RootERC20Predicate
if err := initializeRootERC20Predicate(outputter, txRelayer, rootchainConfig, deployerKey); err != nil {
return nil, 0, err
}

// init RootERC721Predicate
if err := initializeRootERC721Predicate(outputter, txRelayer, rootchainConfig, deployerKey); err != nil {
return nil, 0, err
}

// init RootERC1155Predicate
if err := initializeRootERC1155Predicate(outputter, txRelayer, rootchainConfig, deployerKey); err != nil {
return rootchainConfig, 0, err
}

return rootchainConfig, chainID, nil
}

Expand Down
3 changes: 2 additions & 1 deletion command/rootchain/deploy/deploy_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package deploy

import (
"context"
"os"
"testing"

Expand Down Expand Up @@ -37,7 +38,7 @@ func TestDeployContracts_NoPanics(t *testing.T) {
outputter := command.InitializeOutputter(GetCommand())

require.NotPanics(t, func() {
_, _, err = deployContracts(outputter, client, []*polybft.Validator{})
_, _, err = deployContracts(outputter, client, []*polybft.Validator{}, context.Background())
})
require.NoError(t, err)
}
Loading