diff --git a/cmd/cartesi-rollups-cli/root/deploy/application.go b/cmd/cartesi-rollups-cli/root/deploy/application.go index a00337bac..3ee48b233 100644 --- a/cmd/cartesi-rollups-cli/root/deploy/application.go +++ b/cmd/cartesi-rollups-cli/root/deploy/application.go @@ -117,6 +117,19 @@ func runDeployApplication(cmd *cobra.Command, args []string) { ctx := cmd.Context() + // Validate required application name when registering + if applicationRegisterParam && len(args) < 1 { + err := cmd.Help() + cobra.CheckErr(err) + cobra.CheckErr(fmt.Errorf("missing application name: positional argument [application-name] is required when --register=true")) + } + // Validate that a template is provided either as positional [template-path] or via --template-hash + if cmd.Flags().Changed("template-hash") && len(args) < 2 { + err := cmd.Help() + cobra.CheckErr(err) + cobra.CheckErr(fmt.Errorf("missing template: provide either positional [template-path] or --template-hash")) + } + ethEndpoint, err := config.GetBlockchainHttpEndpoint() cobra.CheckErr(err) diff --git a/pkg/ethutil/application.go b/pkg/ethutil/application.go index 80c7f05b7..fcdcd6120 100644 --- a/pkg/ethutil/application.go +++ b/pkg/ethutil/application.go @@ -75,6 +75,21 @@ func (me *ApplicationDeployment) Deploy( return zero, nil, fmt.Errorf("failed to instantiate contract: %v", err) } + // check if addresses are available (have no code) + applicationAddress, err := factory.CalculateApplicationAddress(nil, me.Consensus, me.OwnerAddress, me.TemplateHash, me.DataAvailability, me.Salt) + if err != nil { + return zero, nil, err + } + + applicationCode, err := client.CodeAt(ctx, applicationAddress, nil) + if err != nil { + return zero, nil, err + } + if len(applicationCode) != 0 { + return zero, nil, fmt.Errorf("application with address: %v already exists. Try a different salt.", applicationAddress) + } + + // deploy the contracts tx, err := factory.NewApplication(txOpts, me.Consensus, me.OwnerAddress, me.TemplateHash, me.DataAvailability, me.Salt) if err != nil { return zero, nil, fmt.Errorf("transaction failed: %v", err) diff --git a/pkg/ethutil/authority.go b/pkg/ethutil/authority.go index a835f5ea8..efb466958 100644 --- a/pkg/ethutil/authority.go +++ b/pkg/ethutil/authority.go @@ -34,17 +34,33 @@ func (me *AuthorityDeployment) String() string { return result } -func (me AuthorityDeployment) Deploy( +func (me *AuthorityDeployment) Deploy( ctx context.Context, client *ethclient.Client, txOpts *bind.TransactOpts, ) (common.Address, error) { - contract, err := iauthorityfactory.NewIAuthorityFactory(me.FactoryAddress, client) + zero := common.Address{} + factory, err := iauthorityfactory.NewIAuthorityFactory(me.FactoryAddress, client) if err != nil { return common.Address{}, fmt.Errorf("failed to instantiate contract: %v", err) } - tx, err := contract.NewAuthority0(txOpts, me.OwnerAddress, big.NewInt(int64(me.EpochLength)), me.Salt) + // check if addresses are available (have no code) + authorityAddress, err := factory.CalculateAuthorityAddress(nil, me.OwnerAddress, new(big.Int).SetUint64(me.EpochLength), me.Salt) + if err != nil { + return zero, err + } + + authorityCode, err := client.CodeAt(ctx, authorityAddress, nil) + if err != nil { + return zero, err + } + if len(authorityCode) != 0 { + return zero, fmt.Errorf("authority with address: %v already exists. Try a different salt.", authorityAddress) + } + + // deploy the contracts + tx, err := factory.NewAuthority0(txOpts, me.OwnerAddress, new(big.Int).SetUint64(me.EpochLength), me.Salt) if err != nil { return common.Address{}, fmt.Errorf("failed to create new authority: %v", err) } @@ -60,7 +76,7 @@ func (me AuthorityDeployment) Deploy( // search for the matching event for _, vLog := range receipt.Logs { - event, err := contract.ParseAuthorityCreated(*vLog) + event, err := factory.ParseAuthorityCreated(*vLog) if err != nil { continue // Skip logs that don't match } diff --git a/pkg/ethutil/prt.go b/pkg/ethutil/prt.go index b7e29fda6..eeb6838e4 100644 --- a/pkg/ethutil/prt.go +++ b/pkg/ethutil/prt.go @@ -61,6 +61,29 @@ func (me *PRTApplicationDeployment) deployPRT( if err != nil { return zero, zero, fmt.Errorf("failed to instantiate contract binding: %v", err) } + + // check if addresses are available (have no code) + addresses, err := factory.CalculateDaveAppAddress(nil, me.TemplateHash, me.Salt) + if err != nil { + return zero, zero, err + } + applicationCode, err := client.CodeAt(ctx, addresses.AppContractAddress, nil) + if err != nil { + return zero, zero, err + } + if len(applicationCode) != 0 { + return zero, zero, fmt.Errorf("application with address: %v already exists. Try a different salt.", addresses.AppContractAddress) + } + + daveConsensusCode, err := client.CodeAt(ctx, addresses.DaveConsensusAddress, nil) + if err != nil { + return zero, zero, err + } + if len(daveConsensusCode) != 0 { + return zero, zero, fmt.Errorf("dave consensus with address: %v already exists. Try a different salt.", addresses.DaveConsensusAddress) + } + + // deploy the contracts tx, err := factory.NewDaveApp(txOpts, me.TemplateHash, me.Salt) if err != nil { return zero, zero, fmt.Errorf("transaction failed: %v", err) diff --git a/pkg/ethutil/selfhosted.go b/pkg/ethutil/selfhosted.go index dac94931c..846a613ee 100644 --- a/pkg/ethutil/selfhosted.go +++ b/pkg/ethutil/selfhosted.go @@ -81,6 +81,29 @@ func (me *SelfhostedApplicationDeployment) Deploy( return zero, nil, err } + // check if addresses are available (have no code) + applicationAddress, authorityAddress, err := factory.CalculateAddresses(nil, me.AuthorityOwnerAddress, new(big.Int).SetUint64(me.EpochLength), me.ApplicationOwnerAddress, me.TemplateHash, me.DataAvailability, me.Salt) + if err != nil { + return zero, nil, err + } + + applicationCode, err := client.CodeAt(ctx, applicationAddress, nil) + if err != nil { + return zero, nil, err + } + if len(applicationCode) != 0 { + return zero, nil, fmt.Errorf("application with address: %v already exists. Try a different salt.", applicationAddress) + } + + authorityCode, err := client.CodeAt(ctx, authorityAddress, nil) + if err != nil { + return zero, nil, err + } + if len(authorityCode) != 0 { + return zero, nil, fmt.Errorf("authority with address: %v already exists. Try a different salt.", authorityAddress) + } + + // deploy the contracts receipt, err := sendTransaction( ctx, client, txOpts, big.NewInt(0), GasLimit, func(txOpts *bind.TransactOpts) (*types.Transaction, error) {