Skip to content
Draft
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
20 changes: 11 additions & 9 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,14 @@ TARGET_OS?=$(shell uname)
export TARGET_OS

ROLLUPS_NODE_VERSION := 2.0.0-alpha.11
ROLLUPS_CONTRACTS_VERSION := 2.2.0
ROLLUPS_CONTRACTS_VERSION := 3.0.0-alpha.6
ROLLUPS_CONTRACTS_URL:=https://github.com/cartesi/rollups-contracts/releases/download/
ROLLUPS_CONTRACTS_ARTIFACT:=rollups-contracts-$(ROLLUPS_CONTRACTS_VERSION)-artifacts.tar.gz
ROLLUPS_CONTRACTS_SHA256:=31c20a8c50f794185957ebd6e554fc99c8e01f0fdf9a80628d031fb0edc7091d
ROLLUPS_PRT_CONTRACTS_VERSION := 2.1.1
ROLLUPS_CONTRACTS_SHA256:=ad1e0880766d25419fc6da1858ea4e7b9074b400e9d9ef68da88b12f4a8bba45
ROLLUPS_PRT_CONTRACTS_VERSION := 3.0.0-alpha.3
ROLLUPS_PRT_CONTRACTS_URL:=https://github.com/cartesi/dave/releases/download/
ROLLUPS_PRT_CONTRACTS_ARTIFACT:=cartesi-rollups-prt-$(ROLLUPS_PRT_CONTRACTS_VERSION)-contract-artifacts.tar.gz
ROLLUPS_PRT_CONTRACTS_SHA256:=830815bcd858a67b73738c6747030960d88ed1e2e0b123086f2112b1ff47f7c9
ROLLUPS_PRT_CONTRACTS_SHA256:=240f4934df7a313dc05a4ae6cc3eee97b5c146952c4218502fec0db83f36a5a5

IMAGE_TAG ?= devel

Expand Down Expand Up @@ -123,11 +123,13 @@ env:
@echo export CARTESI_BLOCKCHAIN_HTTP_ENDPOINT="http://localhost:8545"
@echo export CARTESI_BLOCKCHAIN_WS_ENDPOINT="ws://localhost:8545"
@echo export CARTESI_BLOCKCHAIN_ID="31337"
@echo export CARTESI_CONTRACTS_INPUT_BOX_ADDRESS="0x1b51e2992A2755Ba4D6F7094032DF91991a0Cfac"
@echo export CARTESI_CONTRACTS_AUTHORITY_FACTORY_ADDRESS="0x5E96408CFE423b01dADeD3bc867E6013135990cc"
@echo export CARTESI_CONTRACTS_APPLICATION_FACTORY_ADDRESS="0x26E758238CB6eC5aB70ce0dd52aF2d7b82e1972E"
@echo export CARTESI_CONTRACTS_SELF_HOSTED_APPLICATION_FACTORY_ADDRESS="0x010D3CbB4223F5bCc7b7B03cEE59f3aAea8eDb8A"
@echo export CARTESI_CONTRACTS_DAVE_APP_FACTORY_ADDRESS="0xfC2DBC639b5FB9AfE66A8696eC14EaD9FbFBC404"
@echo export CARTESI_CONTRACTS_INPUT_BOX_ADDRESS="0x346B3df038FE9f8380071eC6514D5a83aD143939"
@echo export CARTESI_CONTRACTS_AUTHORITY_FACTORY_ADDRESS="0x3C1FE01c542a88A523FF6847eD1E26176c8C4ED0"
@echo export CARTESI_CONTRACTS_QUORUM_FACTORY_ADDRESS="0x1f94009389F408B8D0ADfFcF8BBDCe5552BaCa5F"
@echo export CARTESI_CONTRACTS_APPLICATION_FACTORY_ADDRESS="0xC549F89cF1ca43eDDECC64Ac2208F4b283B1c483"
@echo export CARTESI_CONTRACTS_SELF_HOSTED_APPLICATION_FACTORY_ADDRESS="0x6145C5996a71a379E030aEb0440df79D60833418"
@echo export CARTESI_CONTRACTS_DAVE_APP_FACTORY_ADDRESS="0x33FFf0b681c90664dD048a60400AE2D827a4c5bb"
@echo export CARTESI_DEVNET_WITHDRAWAL_OUTPUT_BUILDER_ADDRESS="0x0745787835A019cd4dae8EDB541Fbc0647793d63"
@echo export CARTESI_AUTH_MNEMONIC=\"test test test test test test test test test test test junk\"
@echo export CARTESI_DATABASE_CONNECTION="postgres://postgres:password@localhost:5432/rollupsdb?sslmode=disable"
@echo export CARTESI_SNAPSHOTS_DIR="snapshots"
Expand Down
143 changes: 125 additions & 18 deletions cmd/cartesi-rollups-cli/root/app/register/register.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@ import (
"github.com/cartesi/rollups-node/internal/model"
"github.com/cartesi/rollups-node/internal/repository/factory"
"github.com/cartesi/rollups-node/pkg/contracts/dataavailability"
"github.com/cartesi/rollups-node/pkg/contracts/iquorum"
"github.com/cartesi/rollups-node/pkg/ethutil"

"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/spf13/cobra"
Expand Down Expand Up @@ -48,6 +50,7 @@ var (
templatePath string
templateHash string
epochLength uint64
claimStagingPeriod uint64
inputBoxBlockNumber uint64
inputBoxAddressFromEnv bool
dataAvailability string
Expand Down Expand Up @@ -80,6 +83,11 @@ func init() {
"Consensus Epoch length. (DO NOT USE IN PRODUCTION)\nThis value is retrieved from the consensus contract",
)

Cmd.Flags().Uint64Var(&claimStagingPeriod, "claim-staging-period", 0,
"Consensus claim staging period in blocks (Authority/Quorum only). "+
"(DO NOT USE IN PRODUCTION)\nThis value is retrieved from the consensus contract",
)

Cmd.Flags().StringVarP(&dataAvailability, "data-availability", "D", "",
"Application ABI encoded Data Availability. If not provided, it will be read from the InputBox Address",
)
Expand Down Expand Up @@ -175,6 +183,20 @@ func run(cmd *cobra.Command, args []string) {
}
}

if !cmd.Flags().Changed("claim-staging-period") && !applicationTypePRT {
claimStagingPeriod, err = getClaimStagingPeriod(ctx, consensus)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to get claim staging period from consensus: %v\n", err)
os.Exit(1)
}
}

withdrawalConfig, err := readApplicationWithdrawalConfig(ctx, address)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to read withdrawal config from application: %v\n", err)
os.Exit(1)
}

inputBoxAddress, encodedDA, err := processDataAvailability(
ctx,
address,
Expand Down Expand Up @@ -203,27 +225,33 @@ func run(cmd *cobra.Command, args []string) {
os.Exit(1)
}

consensusType := model.Consensus_Authority
if applicationTypePRT {
consensusType = model.Consensus_PRT
consensusType, err := getConsensusType(ctx, consensus, applicationTypePRT)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to detect consensus type: %v\n", err)
os.Exit(1)
}

application := model.Application{
Name: validName,
IApplicationAddress: address,
IConsensusAddress: consensus,
IInputBoxAddress: *inputBoxAddress,
TemplateURI: templatePath,
TemplateHash: parsedTemplateHash,
EpochLength: epochLength,
DataAvailability: encodedDA,
ConsensusType: consensusType,
State: applicationState,
IInputBoxBlock: inputBoxBlockNumber,
LastEpochCheckBlock: 0,
LastInputCheckBlock: 0,
LastOutputCheckBlock: 0,
LastTournamentCheckBlock: 0,
Name: validName,
IApplicationAddress: address,
IConsensusAddress: consensus,
IInputBoxAddress: *inputBoxAddress,
TemplateURI: templatePath,
TemplateHash: parsedTemplateHash,
EpochLength: epochLength,
ClaimStagingPeriod: claimStagingPeriod,
WithdrawalConfig: withdrawalConfig,
DataAvailability: encodedDA,
ConsensusType: consensusType,
State: applicationState,
IInputBoxBlock: inputBoxBlockNumber,
LastEpochCheckBlock: 0,
LastInputCheckBlock: 0,
LastOutputCheckBlock: 0,
LastTournamentCheckBlock: 0,
LastForecloseCheckBlock: 0,
LastAccountsDriveProvedCheckBlock: 0,
LastWithdrawalCheckBlock: 0,
}

// load execution parameters from a file?
Expand Down Expand Up @@ -320,6 +348,85 @@ func getEpochLength(
return ethutil.GetEpochLength(ctx, client, consensusAddr)
}

func getClaimStagingPeriod(
ctx context.Context,
consensusAddr common.Address,
) (uint64, error) {
ethEndpoint, err := config.GetBlockchainHttpEndpoint()
if err != nil {
return 0, fmt.Errorf("failed to get blockchain http endpoint address: %w", err)
}
client, err := ethclient.Dial(ethEndpoint.Raw())
if err != nil {
return 0, fmt.Errorf("failed to connect to the blockchain http endpoint: %s", ethEndpoint)
}
return ethutil.GetClaimStagingPeriod(ctx, client, consensusAddr)
}

type quorumConsensusProbe interface {
NumOfValidators(opts *bind.CallOpts) (*big.Int, error)
}

func getConsensusType(
ctx context.Context,
consensusAddr common.Address,
applicationTypePRT bool,
) (model.Consensus, error) {
if applicationTypePRT {
return model.Consensus_PRT, nil
}

ethEndpoint, err := config.GetBlockchainHttpEndpoint()
if err != nil {
return "", fmt.Errorf("failed to get blockchain http endpoint address: %w", err)
}
client, err := ethclient.DialContext(ctx, ethEndpoint.Raw())
if err != nil {
return "", fmt.Errorf("failed to connect to the blockchain http endpoint: %s", ethEndpoint)
}
quorum, err := iquorum.NewIQuorum(consensusAddr, client)
if err != nil {
return "", err
}
return consensusTypeFromQuorumProbe(applicationTypePRT, quorum)
}

func consensusTypeFromQuorumProbe(
applicationTypePRT bool,
probe quorumConsensusProbe,
) (model.Consensus, error) {
if applicationTypePRT {
return model.Consensus_PRT, nil
}
numOfValidators, err := probe.NumOfValidators(nil)
if err != nil {
return model.Consensus_Authority, nil
}
if numOfValidators == nil || numOfValidators.Sign() == 0 {
return "", fmt.Errorf("quorum consensus reports zero validators")
}
return model.Consensus_Quorum, nil
}

func readApplicationWithdrawalConfig(
ctx context.Context,
appAddr common.Address,
) (model.WithdrawalConfig, error) {
ethEndpoint, err := config.GetBlockchainHttpEndpoint()
if err != nil {
return model.WithdrawalConfig{}, fmt.Errorf("failed to get blockchain http endpoint address: %w", err)
}
client, err := ethclient.Dial(ethEndpoint.Raw())
if err != nil {
return model.WithdrawalConfig{}, fmt.Errorf("failed to connect to the blockchain http endpoint: %s", ethEndpoint)
}
wc, err := ethutil.GetApplicationWithdrawalConfig(ctx, client, appAddr)
if err != nil {
return model.WithdrawalConfig{}, err
}
return model.WithdrawalConfig(wc), nil
}

func getInputBoxDeploymentBlock(
ctx context.Context,
inputBoxAddress common.Address,
Expand Down
72 changes: 72 additions & 0 deletions cmd/cartesi-rollups-cli/root/app/register/register_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// (c) Cartesi and individual authors (see AUTHORS)
// SPDX-License-Identifier: Apache-2.0 (see LICENSE)

package register

import (
"errors"
"math/big"
"testing"

"github.com/cartesi/rollups-node/internal/model"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/stretchr/testify/require"
)

type quorumConsensusProbeStub struct {
numOfValidators *big.Int
err error
called bool
}

func (p *quorumConsensusProbeStub) NumOfValidators(_ *bind.CallOpts) (*big.Int, error) {
p.called = true
return p.numOfValidators, p.err
}

func TestConsensusTypeFromQuorumProbe_PRTSkipsProbe(t *testing.T) {
probe := &quorumConsensusProbeStub{
numOfValidators: big.NewInt(3),
}

consensusType, err := consensusTypeFromQuorumProbe(true, probe)

require.NoError(t, err)
require.Equal(t, model.Consensus_PRT, consensusType)
require.False(t, probe.called)
}

func TestConsensusTypeFromQuorumProbe_AuthorityWhenProbeFails(t *testing.T) {
probe := &quorumConsensusProbeStub{
err: errors.New("execution reverted"),
}

consensusType, err := consensusTypeFromQuorumProbe(false, probe)

require.NoError(t, err)
require.Equal(t, model.Consensus_Authority, consensusType)
require.True(t, probe.called)
}

func TestConsensusTypeFromQuorumProbe_QuorumWhenValidatorsExist(t *testing.T) {
probe := &quorumConsensusProbeStub{
numOfValidators: big.NewInt(3),
}

consensusType, err := consensusTypeFromQuorumProbe(false, probe)

require.NoError(t, err)
require.Equal(t, model.Consensus_Quorum, consensusType)
require.True(t, probe.called)
}

func TestConsensusTypeFromQuorumProbe_RejectsZeroValidatorQuorum(t *testing.T) {
probe := &quorumConsensusProbeStub{
numOfValidators: big.NewInt(0),
}

_, err := consensusTypeFromQuorumProbe(false, probe)

require.ErrorContains(t, err, "zero validators")
require.True(t, probe.called)
}
19 changes: 18 additions & 1 deletion cmd/cartesi-rollups-cli/root/app/status/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,12 +70,29 @@ func run(cmd *cobra.Command, args []string) {
os.Exit(1)
}

// If no new status is provided, display the current status and reason
// If no new status is provided, display the current status and reason.
// Foreclose / drive-prove markers (zero == not observed) are surfaced
// so operators and integration tests can detect post-foreclosure
// progress without going through the JSON-RPC API. Foreclosure does
// not transition the app state, so these fields are the only signal
// that the chain has moved past the app's active lifecycle.
if len(args) == 1 {
fmt.Println(app.State)
if app.Reason != nil && *app.Reason != "" {
fmt.Printf("Reason: %s\n", *app.Reason)
}
if app.ForecloseBlock != 0 {
fmt.Printf("Foreclose block: 0x%x\n", app.ForecloseBlock)
if app.ForecloseTransaction != nil {
fmt.Printf("Foreclose transaction: %s\n", app.ForecloseTransaction.Hex())
}
}
if app.AccountsDriveProvedBlock != 0 {
fmt.Printf("Accounts drive proved block: 0x%x\n", app.AccountsDriveProvedBlock)
if app.AccountsDriveMerkleRoot != nil {
fmt.Printf("Accounts drive merkle root: %s\n", app.AccountsDriveMerkleRoot.Hex())
}
}
os.Exit(0)
}

Expand Down
Loading
Loading