Skip to content

Commit 18dce93

Browse files
committed
feat(cli): add PRT consensus to deploy application
1 parent 94ec587 commit 18dce93

5 files changed

Lines changed: 246 additions & 11 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: 74 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ var (
2929
applicationRegisterParam bool
3030
applicationTemplateHashParam string
3131
factoryAddressParam string
32+
prtFactoryAddressParam string
33+
deploymentTypePRT bool
3234
)
3335

3436
var applicationCmd = &cobra.Command{
@@ -49,7 +51,8 @@ Supported Environment Variables:
4951
CARTESI_BLOCKCHAIN_HTTP_ENDPOINT Blockchain HTTP endpoint
5052
CARTESI_CONTRACTS_INPUT_BOX_ADDRESS Input Box contract address
5153
CARTESI_CONTRACTS_APPLICATION_FACTORY_ADDRESS Application Factory address
52-
CARTESI_CONTRACTS_SELF_HOSTED_APPLICATION_FACTORY_ADDRESS Self Hosted Application Factory address`,
54+
CARTESI_CONTRACTS_SELF_HOSTED_APPLICATION_FACTORY_ADDRESS Self Hosted Application Factory address
55+
CARTESI_CONTRACTS_PRT_FACTORY_ADDRESS PRT Factory address`,
5356
}
5457

5558
const applicationExamples = `
@@ -59,6 +62,9 @@ const applicationExamples = `
5962
# deploy an application contract using an existing consensus, then register the application
6063
- cli deploy application echo-dapp applications/echo-dapp/ --consensus=0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
6164
65+
# deploy an application contract with a PRT consensus, then register the application
66+
- cli deploy application echo-dapp applications/echo-dapp/ --prt
67+
6268
# deploy but don't register into the database
6369
- cli deploy application echo-dapp applications/echo-dapp/ --register=false
6470
@@ -73,6 +79,8 @@ func init() {
7379
"Consensus address. A new authority consensus will be created if this field is left empty.")
7480
applicationCmd.Flags().StringVarP(&factoryAddressParam, "factory", "f", "",
7581
"Application factory address. Default value is retrieved from configuration.")
82+
applicationCmd.Flags().StringVarP(&prtFactoryAddressParam, "prt-factory", "", "",
83+
"PRT Application factory address. Default value is retrieved from configuration.")
7684
applicationCmd.Flags().StringVarP(&applicationOwnerAddressParam, "application-owner", "o", "",
7785
"Application owner address. If not defined, it will be derived from the auth method.")
7886
applicationCmd.Flags().StringVarP(&applicationDataAvailabilityParam, "data-availability", "d", "",
@@ -85,6 +93,8 @@ func init() {
8593
"Start processing the application, requires 'register=true'.")
8694
applicationCmd.Flags().StringVarP(&authorityOwnerAddressParam, "authority-owner", "O", "",
8795
"Authority Owner address. If not defined, it will be derived from the auth method.")
96+
applicationCmd.Flags().BoolVarP(&deploymentTypePRT, "prt", "", false,
97+
"Deploy a PRT application.")
8898

8999
origHelpFunc := applicationCmd.HelpFunc()
90100
applicationCmd.SetHelpFunc(func(command *cobra.Command, strings []string) {
@@ -141,7 +151,9 @@ func runDeployApplication(cmd *cobra.Command, args []string) {
141151
}
142152

143153
var deployment ethutil.IApplicationDeployment
144-
if deploySelfhosted := !cmd.Flags().Changed("consensus"); deploySelfhosted {
154+
if deploymentTypePRT {
155+
deployment, err = buildPrtApplicationDeployment(cmd, args, client, txOpts)
156+
} else if deploySelfhosted := !cmd.Flags().Changed("consensus"); deploySelfhosted {
145157
deployment, err = buildSelfhostedApplicationDeployment(cmd, args, client, txOpts)
146158
} else {
147159
deployment, err = buildApplicationOnlyDeployment(cmd, args, client, txOpts)
@@ -210,6 +222,15 @@ func runDeployApplication(cmd *cobra.Command, args []string) {
210222
application.EpochLength = res.Deployment.EpochLength
211223
application.DataAvailability = res.Deployment.DataAvailability
212224
application.IInputBoxBlock = res.Deployment.IInputBoxBlock
225+
226+
case *ethutil.PRTApplicationDeploymentResult:
227+
application.IApplicationAddress = res.ApplicationResult.ApplicationAddress
228+
application.IConsensusAddress = res.ApplicationResult.Deployment.Consensus
229+
application.IInputBoxAddress = res.ApplicationResult.Deployment.InputBoxAddress
230+
application.TemplateHash = res.ApplicationResult.Deployment.TemplateHash
231+
application.EpochLength = res.ApplicationResult.Deployment.EpochLength
232+
application.DataAvailability = res.ApplicationResult.Deployment.DataAvailability
233+
application.IInputBoxBlock = res.ApplicationResult.Deployment.IInputBoxBlock
213234
default:
214235
panic("unimplemented deployment type\n")
215236
}
@@ -339,7 +360,7 @@ func buildSelfhostedApplicationDeployment(
339360
return request, nil
340361
}
341362

342-
func buildApplicationOnlyDeployment(
363+
func buildApplicationOnlyDeploymentWithoutConsensus(
343364
cmd *cobra.Command,
344365
args []string,
345366
client *ethclient.Client,
@@ -360,11 +381,6 @@ func buildApplicationOnlyDeployment(
360381
return nil, fmt.Errorf("error on parameter factory: %w", err)
361382
}
362383

363-
request.Consensus, err = parseHexAddress(applicationConsensusAddressParam)
364-
if err != nil {
365-
return nil, fmt.Errorf("error on parameter consensus: %w", err)
366-
}
367-
368384
if !cmd.Flags().Changed("template-hash") {
369385
if len(args) >= 2 { // args[1] is mandatory if `template-hash` was absent
370386
request.TemplateHash, err = readHash(args[1])
@@ -402,17 +418,64 @@ func buildApplicationOnlyDeployment(
402418
return nil, fmt.Errorf("error on parameter data-availability: %w", err)
403419
}
404420

421+
request.Salt, err = ethutil.ParseSalt(saltParam)
422+
if err != nil {
423+
return nil, fmt.Errorf("error on parameter salt: %w", err)
424+
}
425+
426+
request.Verbose = verboseParam
427+
return request, nil
428+
}
429+
430+
func buildApplicationOnlyDeployment(
431+
cmd *cobra.Command,
432+
args []string,
433+
client *ethclient.Client,
434+
txOpts *bind.TransactOpts,
435+
) (
436+
*ethutil.ApplicationDeployment,
437+
error,
438+
) {
439+
request, err := buildApplicationOnlyDeploymentWithoutConsensus(cmd, args, client, txOpts)
440+
441+
request.Consensus, err = parseHexAddress(applicationConsensusAddressParam)
442+
if err != nil {
443+
return nil, fmt.Errorf("error on parameter consensus: %w", err)
444+
}
445+
405446
request.Consensus, request.EpochLength, err = customConsensus(client, applicationConsensusAddressParam)
406447
if err != nil {
407448
return nil, fmt.Errorf("error on parameter consensus: %w", err)
408449
}
409450

410-
request.Salt, err = ethutil.ParseSalt(saltParam)
451+
return request, nil
452+
}
453+
454+
func buildPrtApplicationDeployment(
455+
cmd *cobra.Command,
456+
args []string,
457+
client *ethclient.Client,
458+
txOpts *bind.TransactOpts,
459+
) (
460+
*ethutil.PRTApplicationDeployment,
461+
error,
462+
) {
463+
var err error
464+
request := &ethutil.PRTApplicationDeployment{}
465+
if !cmd.Flags().Changed("prt-factory") {
466+
request.FactoryAddress, err = config.GetContractsPrtFactoryAddress()
467+
} else {
468+
request.FactoryAddress, err = parseHexAddress(factoryAddressParam)
469+
}
411470
if err != nil {
412-
return nil, fmt.Errorf("error on parameter salt: %w", err)
471+
return nil, fmt.Errorf("error on parameter factory: %w", err)
472+
}
473+
474+
request.Application, err = buildApplicationOnlyDeploymentWithoutConsensus(cmd, args, client, txOpts)
475+
if err != nil {
476+
return nil, fmt.Errorf("error on application: %w", err)
413477
}
414478

415-
request.Verbose = verboseParam
416479
return request, nil
417480
}
418481

internal/config/generate/Config.toml

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

197+
[contracts.CARTESI_CONTRACTS_PRT_CONSENSUS_FACTORY_ADDRESS]
198+
go-type = "Address"
199+
description = """
200+
Address of the PRT consensus contract. Not required, used only by the CLI and tests"""
201+
omit = true
202+
used-by = ["cli"]
203+
197204
#
198205
# Snapshot
199206
#

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)