Skip to content

Commit 7f16599

Browse files
mpolitzervfusco
authored andcommitted
feat(cli): add PRT consensus to deploy application
1 parent 8744a26 commit 7f16599

5 files changed

Lines changed: 251 additions & 9 deletions

File tree

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ env:
9797
@echo export CARTESI_CONTRACTS_AUTHORITY_FACTORY_ADDRESS="0xC7003566dD09Aa0fC0Ce201aC2769aFAe3BF0051"
9898
@echo export CARTESI_CONTRACTS_APPLICATION_FACTORY_ADDRESS="0xc7006f70875BaDe89032001262A846D3Ee160051"
9999
@echo export CARTESI_CONTRACTS_SELF_HOSTED_APPLICATION_FACTORY_ADDRESS="0xc700285Ab555eeB5201BC00CFD4b2CC8DED90051"
100+
@echo export CARTESI_CONTRACTS_PRT_FACTORY_ADDRESS="0x6e362c9458fE812D4aA796651C64D02C87AbD1cB"
100101
@echo export CARTESI_AUTH_MNEMONIC=\"test test test test test test test test test test test junk\"
101102
@echo export CARTESI_DATABASE_CONNECTION="postgres://postgres:password@localhost:5432/rollupsdb?sslmode=disable"
102103
@echo export CARTESI_SNAPSHOTS_DIR="snapshots"

cmd/cartesi-rollups-cli/root/deploy/application.go

Lines changed: 79 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ var (
3232
applicationTemplateHashParam string
3333
factoryAddressParam string
3434
executionParametersFileParam string
35+
prtFactoryAddressParam string
36+
deploymentTypePRT bool
3537
)
3638

3739
var applicationCmd = &cobra.Command{
@@ -52,7 +54,8 @@ Supported Environment Variables:
5254
CARTESI_BLOCKCHAIN_HTTP_ENDPOINT Blockchain HTTP endpoint
5355
CARTESI_CONTRACTS_INPUT_BOX_ADDRESS Input Box contract address
5456
CARTESI_CONTRACTS_APPLICATION_FACTORY_ADDRESS Application Factory address
55-
CARTESI_CONTRACTS_SELF_HOSTED_APPLICATION_FACTORY_ADDRESS Self Hosted Application Factory address`,
57+
CARTESI_CONTRACTS_SELF_HOSTED_APPLICATION_FACTORY_ADDRESS Self Hosted Application Factory address
58+
CARTESI_CONTRACTS_PRT_FACTORY_ADDRESS PRT Factory address`,
5659
}
5760

5861
const applicationExamples = `
@@ -62,20 +65,25 @@ const applicationExamples = `
6265
# deploy an application contract using an existing consensus, then register the application
6366
- cli deploy application echo-dapp applications/echo-dapp/ --consensus=0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
6467
68+
# deploy an application contract with a PRT consensus, then register the application
69+
- cli deploy application echo-dapp applications/echo-dapp/ --prt
70+
6571
# deploy but don't register into the database
6672
- cli deploy application echo-dapp applications/echo-dapp/ --register=false
6773
6874
# deploy and register into the database, but disabled
6975
- cli deploy application echo-dapp applications/echo-dapp/ --enable=false
7076
71-
# deploy an application without a machine template path (both application-name and template-path may be ommited in this case)
77+
# deploy an application without a machine template path (both application-name and template-path may be omitted in this case)
7278
- cli deploy application --template-hash=0x0000000000000000000000000000000000000000000000000000000000000000 --register=false`
7379

7480
func init() {
7581
applicationCmd.Flags().StringVarP(&applicationConsensusAddressParam, "consensus", "c", "",
7682
"Consensus address. A new authority consensus will be created if this field is left empty.")
7783
applicationCmd.Flags().StringVarP(&factoryAddressParam, "factory", "f", "",
7884
"Application factory address. Default value is retrieved from configuration.")
85+
applicationCmd.Flags().StringVarP(&prtFactoryAddressParam, "prt-factory", "", "",
86+
"PRT Application factory address. Default value is retrieved from configuration.")
7987
applicationCmd.Flags().StringVarP(&applicationOwnerAddressParam, "application-owner", "o", "",
8088
"Application owner address. If not defined, it will be derived from the auth method.")
8189
applicationCmd.Flags().StringVarP(&applicationDataAvailabilityParam, "data-availability", "d", "",
@@ -90,6 +98,8 @@ func init() {
9098
"Start processing the application, requires 'register=true'.")
9199
applicationCmd.Flags().StringVarP(&authorityOwnerAddressParam, "authority-owner", "O", "",
92100
"Authority Owner address. If not defined, it will be derived from the auth method.")
101+
applicationCmd.Flags().BoolVarP(&deploymentTypePRT, "prt", "", false,
102+
"Deploy a PRT application.")
93103

94104
origHelpFunc := applicationCmd.HelpFunc()
95105
applicationCmd.SetHelpFunc(func(command *cobra.Command, strings []string) {
@@ -146,7 +156,9 @@ func runDeployApplication(cmd *cobra.Command, args []string) {
146156
}
147157

148158
var deployment ethutil.IApplicationDeployment
149-
if deploySelfhosted := !cmd.Flags().Changed("consensus"); deploySelfhosted {
159+
if deploymentTypePRT {
160+
deployment, err = buildPrtApplicationDeployment(ctx, cmd, args, client, txOpts)
161+
} else if deploySelfhosted := !cmd.Flags().Changed("consensus"); deploySelfhosted {
150162
deployment, err = buildSelfhostedApplicationDeployment(ctx, cmd, args, client, txOpts)
151163
} else {
152164
deployment, err = buildApplicationOnlyDeployment(ctx, cmd, args, client, txOpts)
@@ -235,6 +247,15 @@ func runDeployApplication(cmd *cobra.Command, args []string) {
235247
application.EpochLength = res.Deployment.EpochLength
236248
application.DataAvailability = res.Deployment.DataAvailability
237249
application.IInputBoxBlock = res.Deployment.IInputBoxBlock
250+
251+
case *ethutil.PRTApplicationDeploymentResult:
252+
application.IApplicationAddress = res.ApplicationResult.ApplicationAddress
253+
application.IConsensusAddress = res.ApplicationResult.Deployment.Consensus
254+
application.IInputBoxAddress = res.ApplicationResult.Deployment.InputBoxAddress
255+
application.TemplateHash = res.ApplicationResult.Deployment.TemplateHash
256+
application.EpochLength = res.ApplicationResult.Deployment.EpochLength
257+
application.DataAvailability = res.ApplicationResult.Deployment.DataAvailability
258+
application.IInputBoxBlock = res.ApplicationResult.Deployment.IInputBoxBlock
238259
default:
239260
panic("unimplemented deployment type\n")
240261
}
@@ -382,7 +403,7 @@ func buildSelfhostedApplicationDeployment(
382403
return request, nil
383404
}
384405

385-
func buildApplicationOnlyDeployment(
406+
func buildApplicationOnlyDeploymentWithoutConsensus(
386407
ctx context.Context,
387408
cmd *cobra.Command,
388409
args []string,
@@ -404,11 +425,6 @@ func buildApplicationOnlyDeployment(
404425
return nil, fmt.Errorf("error on parameter factory: %w", err)
405426
}
406427

407-
request.Consensus, err = parseHexAddress(applicationConsensusAddressParam)
408-
if err != nil {
409-
return nil, fmt.Errorf("error on parameter consensus: %w", err)
410-
}
411-
412428
if !cmd.Flags().Changed("template-hash") {
413429
if len(args) >= 2 { // args[1] is mandatory if `template-hash` was absent
414430
request.TemplateHash, err = readHash(args[1])
@@ -470,6 +486,60 @@ func buildApplicationOnlyDeployment(
470486
return request, nil
471487
}
472488

489+
func buildApplicationOnlyDeployment(
490+
ctx context.Context,
491+
cmd *cobra.Command,
492+
args []string,
493+
client *ethclient.Client,
494+
txOpts *bind.TransactOpts,
495+
) (
496+
*ethutil.ApplicationDeployment,
497+
error,
498+
) {
499+
request, err := buildApplicationOnlyDeploymentWithoutConsensus(ctx, cmd, args, client, txOpts)
500+
501+
request.Consensus, err = parseHexAddress(applicationConsensusAddressParam)
502+
if err != nil {
503+
return nil, fmt.Errorf("error on parameter consensus: %w", err)
504+
}
505+
506+
request.Consensus, request.EpochLength, err = customConsensus(client, applicationConsensusAddressParam)
507+
if err != nil {
508+
return nil, fmt.Errorf("error on parameter consensus: %w", err)
509+
}
510+
511+
return request, nil
512+
}
513+
514+
func buildPrtApplicationDeployment(
515+
ctx context.Context,
516+
cmd *cobra.Command,
517+
args []string,
518+
client *ethclient.Client,
519+
txOpts *bind.TransactOpts,
520+
) (
521+
*ethutil.PRTApplicationDeployment,
522+
error,
523+
) {
524+
var err error
525+
request := &ethutil.PRTApplicationDeployment{}
526+
if !cmd.Flags().Changed("prt-factory") {
527+
request.FactoryAddress, err = config.GetContractsPrtFactoryAddress()
528+
} else {
529+
request.FactoryAddress, err = parseHexAddress(factoryAddressParam)
530+
}
531+
if err != nil {
532+
return nil, fmt.Errorf("error on parameter factory: %w", err)
533+
}
534+
535+
request.Application, err = buildApplicationOnlyDeploymentWithoutConsensus(ctx, cmd, args, client, txOpts)
536+
if err != nil {
537+
return nil, fmt.Errorf("error on application: %w", err)
538+
}
539+
540+
return request, nil
541+
}
542+
473543
// read the hash value from the cartesi machine hash file
474544
func readHash(machineDir string) (common.Hash, error) {
475545
zero := common.Hash{}

internal/config/generate/Config.toml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,13 @@ Address of the SelfHostedApplicationFactory contract. Not required, used only by
210210
omit = true
211211
used-by = ["cli"]
212212

213+
[contracts.CARTESI_CONTRACTS_PRT_CONSENSUS_FACTORY_ADDRESS]
214+
go-type = "Address"
215+
description = """
216+
Address of the PRT consensus contract. Not required, used only by the CLI and tests"""
217+
omit = true
218+
used-by = ["cli"]
219+
213220
#
214221
# Snapshot
215222
#

internal/config/generated.go

Lines changed: 16 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/ethutil/prt.go

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
// (c) Cartesi and individual authors (see AUTHORS)
2+
// SPDX-License-Identifier: Apache-2.0 (see LICENSE)
3+
package ethutil
4+
5+
import (
6+
"context"
7+
"encoding/hex"
8+
"fmt"
9+
"math/big"
10+
11+
"github.com/cartesi/rollups-node/pkg/contracts/daveconsensusfactory"
12+
"github.com/cartesi/rollups-node/pkg/contracts/iapplication"
13+
"github.com/ethereum/go-ethereum/accounts/abi/bind"
14+
"github.com/ethereum/go-ethereum/common"
15+
"github.com/ethereum/go-ethereum/core/types"
16+
"github.com/ethereum/go-ethereum/ethclient"
17+
)
18+
19+
type PRTApplicationDeployment struct {
20+
FactoryAddress common.Address
21+
TemplateHash common.Hash
22+
Salt SaltBytes
23+
24+
Application *ApplicationDeployment
25+
}
26+
27+
type PRTApplicationDeploymentResult struct {
28+
Deployment *PRTApplicationDeployment
29+
ApplicationResult *ApplicationDeploymentResult
30+
}
31+
32+
func (me *PRTApplicationDeployment) String() string {
33+
result := ""
34+
result += fmt.Sprintf("PRT application deployment:\n")
35+
result += fmt.Sprintf("\tapplication owner: %v\n", me.Application.OwnerAddress)
36+
if me.Application.Verbose {
37+
result += fmt.Sprintf("\tPRT factory address: %v\n", me.FactoryAddress)
38+
result += fmt.Sprintf("\tAPP factory address: %v\n", me.Application.FactoryAddress)
39+
result += fmt.Sprintf("\ttemplate hash: %v\n", me.Application.TemplateHash)
40+
result += fmt.Sprintf("\tdata availability: 0x%v\n", hex.EncodeToString(me.Application.DataAvailability))
41+
result += fmt.Sprintf("\tsalt: %v\n", me.Application.Salt)
42+
}
43+
return result
44+
}
45+
46+
func (me *PRTApplicationDeploymentResult) String() string {
47+
result := ""
48+
result += fmt.Sprintf("\tapplication address: %v\n", me.ApplicationResult.ApplicationAddress)
49+
result += fmt.Sprintf("\tconsensus address: %v\n", me.ApplicationResult.Deployment.Consensus)
50+
return result
51+
}
52+
53+
func (me *PRTApplicationDeployment) deployPRT(
54+
ctx context.Context,
55+
client *ethclient.Client,
56+
txOpts *bind.TransactOpts,
57+
applicationAddress common.Address,
58+
) (common.Address, error) {
59+
zero := common.Address{}
60+
61+
factory, err := daveconsensusfactory.NewDaveConsensusFactory(me.FactoryAddress, client)
62+
if err != nil {
63+
return zero, fmt.Errorf("failed to instantiate contract: %v", err)
64+
}
65+
tx, err := factory.NewDaveConsensus(txOpts, applicationAddress, me.TemplateHash, me.Salt)
66+
if err != nil {
67+
return zero, fmt.Errorf("transaction failed: %v", err)
68+
}
69+
70+
receipt, err := bind.WaitMined(ctx, client, tx)
71+
if err != nil {
72+
return zero, fmt.Errorf("failed to wait for transaction mining: %v", err)
73+
}
74+
75+
if receipt.Status != 1 {
76+
return zero, fmt.Errorf("transaction failed")
77+
}
78+
79+
// Look for the specific event in the receipt logs
80+
for _, vLog := range receipt.Logs {
81+
// Parse log for DaveConsensusCreated event
82+
event, err := factory.ParseDaveConsensusCreated(*vLog)
83+
if err != nil {
84+
continue // Skip logs that don't match
85+
}
86+
return event.DaveConsensus, nil
87+
}
88+
return zero, fmt.Errorf("failed to find DaveConsensusCreated event in receipt logs")
89+
}
90+
91+
// Do the consensus/application dance based on: https://github.com/cartesi/dave/blob/v1.0.0/cartesi-rollups/contracts/cannonfile.prod-instance.toml
92+
func (me *PRTApplicationDeployment) Deploy(
93+
ctx context.Context,
94+
client *ethclient.Client,
95+
txOpts *bind.TransactOpts,
96+
) (common.Address, IApplicationDeploymentResult, error) {
97+
zero := common.Address{}
98+
result := &PRTApplicationDeploymentResult{}
99+
result.Deployment = me
100+
101+
var err error
102+
applicationAddress, appResult, err := me.Application.Deploy(ctx, client, txOpts)
103+
if err != nil {
104+
return zero, nil, err
105+
}
106+
107+
switch appRes := appResult.(type) {
108+
case *ApplicationDeploymentResult:
109+
result.ApplicationResult = appRes
110+
default:
111+
panic("Application deployment returned an impossible type.")
112+
}
113+
114+
consensus, err := me.deployPRT(ctx, client, txOpts, applicationAddress)
115+
if err != nil {
116+
return zero, nil, fmt.Errorf("failed to deploy PRT contract: %w", err)
117+
}
118+
119+
application, err := iapplication.NewIApplication(applicationAddress, client)
120+
if err != nil {
121+
return zero, nil, fmt.Errorf("failed to instantiate application: %v", err)
122+
}
123+
124+
_, err = sendTransaction(ctx, client, txOpts, big.NewInt(0), GasLimit,
125+
func(txOpts *bind.TransactOpts) (*types.Transaction, error) {
126+
return application.MigrateToOutputsMerkleRootValidator(txOpts, consensus)
127+
},
128+
)
129+
if err != nil {
130+
return zero, nil, fmt.Errorf("failed to create a self hosted application: execution reverted")
131+
}
132+
133+
_, err = sendTransaction(ctx, client, txOpts, big.NewInt(0), GasLimit,
134+
func(txOpts *bind.TransactOpts) (*types.Transaction, error) {
135+
return application.RenounceOwnership(txOpts)
136+
},
137+
)
138+
if err != nil {
139+
return zero, nil, fmt.Errorf("failed to create a self hosted application: execution reverted")
140+
}
141+
142+
result.ApplicationResult.Deployment.Consensus = consensus
143+
return applicationAddress, result, nil
144+
}
145+
146+
func (me *PRTApplicationDeployment) GetFactoryAddress() common.Address {
147+
return me.FactoryAddress
148+
}

0 commit comments

Comments
 (0)