From ef430b1b460c8858d65271498bf36581355d3583 Mon Sep 17 00:00:00 2001 From: artpav <19916123+artemijspavlovs@users.noreply.github.com> Date: Thu, 15 Aug 2024 08:56:31 +0300 Subject: [PATCH] feat: finalize relayer flow (#833) --- cmd/config/init/genesis.go | 7 - cmd/config/init/rollapp.go | 50 +++++- cmd/da-light-client/start/start.go | 4 +- cmd/relayer/relayer.go | 8 +- cmd/relayer/run/run.go | 68 ++++++-- cmd/relayer/start/start.go | 30 ++-- cmd/rollapp/init/init.go | 75 --------- cmd/rollapp/init/utils.go | 218 +++++++++++++------------- cmd/rollapp/run/run.go | 108 +++++++++++++ cmd/root.go | 20 +-- cmd/services/load/load.go | 46 ++++++ cmd/services/start/start.go | 66 +++++--- go.sum | 1 + relayer/channels.go | 3 +- relayer/connections.go | 36 ++--- sequencer/config.go | 3 +- test/config/init/testutils/rollapp.go | 5 +- utils/bash/bash_commands.go | 2 +- utils/config/config.go | 12 -- utils/config/tomlconfig/toml.go | 126 +-------------- utils/dymint/dymint.go | 40 +++-- utils/genesis/genesis.go | 154 ++++++++++++++++++ utils/relayer/relayer.go | 59 +++++++ utils/rollapp/rollapp.go | 11 +- utils/rollapp/types.go | 30 ++++ 25 files changed, 745 insertions(+), 437 deletions(-) create mode 100644 utils/genesis/genesis.go create mode 100644 utils/relayer/relayer.go diff --git a/cmd/config/init/genesis.go b/cmd/config/init/genesis.go index baf54ba3..97967c0e 100644 --- a/cmd/config/init/genesis.go +++ b/cmd/config/init/genesis.go @@ -24,13 +24,6 @@ type PathValue struct { Value interface{} } -func GetGenesisFilePath(root string) string { - return filepath.Join( - RollappConfigDir(root), - "genesis.json", - ) -} - // TODO(#130): fix to support epochs func getDefaultGenesisParams( sequencerAddr, genesisOperatorAddress string, raCfg *config.RollappConfig, diff --git a/cmd/config/init/rollapp.go b/cmd/config/init/rollapp.go index 40da4860..23eaea79 100644 --- a/cmd/config/init/rollapp.go +++ b/cmd/config/init/rollapp.go @@ -1,16 +1,21 @@ package initconfig import ( + "encoding/json" "os/exec" "path/filepath" + comettypes "github.com/cometbft/cometbft/types" + "github.com/pterm/pterm" + "github.com/dymensionxyz/roller/cmd/consts" "github.com/dymensionxyz/roller/sequencer" "github.com/dymensionxyz/roller/utils/bash" "github.com/dymensionxyz/roller/utils/config" + genesisutils "github.com/dymensionxyz/roller/utils/genesis" ) -func InitializeRollappConfig(initConfig config.RollappConfig) error { +func InitializeRollappConfig(initConfig *config.RollappConfig, hd consts.HubData) error { home := filepath.Join(initConfig.Home, consts.ConfigDirName.Rollapp) initRollappCmd := exec.Command( @@ -28,7 +33,44 @@ func InitializeRollappConfig(initConfig config.RollappConfig) error { return err } - err = setRollappConfig(initConfig) + if initConfig.HubData.ID != "mock" { + err := genesisutils.DownloadGenesis(initConfig.Home, *initConfig) + if err != nil { + pterm.Error.Println("failed to download genesis file: ", err) + return err + } + + isChecksumValid, err := genesisutils.CompareGenesisChecksum( + initConfig.Home, + initConfig.RollappID, + hd, + ) + if !isChecksumValid { + return err + } + + genesisDoc, err := comettypes.GenesisDocFromFile( + genesisutils.GetGenesisFilePath(initConfig.Home), + ) + if err != nil { + return err + } + + // TODO: refactor + var need genesisutils.AppState + j, _ := genesisDoc.AppState.MarshalJSON() + err = json.Unmarshal(j, &need) + if err != nil { + return err + } + rollappBaseDenom := need.Bank.Supply[0].Denom + rollappDenom := rollappBaseDenom[1:] + + initConfig.BaseDenom = rollappBaseDenom + initConfig.Denom = rollappDenom + } + + err = setRollappConfig(*initConfig) if err != nil { return err } @@ -48,7 +90,3 @@ func setRollappConfig(rlpCfg config.RollappConfig) error { } return nil } - -func RollappConfigDir(root string) string { - return filepath.Join(root, consts.ConfigDirName.Rollapp, "config") -} diff --git a/cmd/da-light-client/start/start.go b/cmd/da-light-client/start/start.go index d7017322..a383dd80 100644 --- a/cmd/da-light-client/start/start.go +++ b/cmd/da-light-client/start/start.go @@ -10,7 +10,6 @@ import ( "github.com/dymensionxyz/roller/cmd/consts" "github.com/dymensionxyz/roller/cmd/utils" datalayer "github.com/dymensionxyz/roller/data_layer" - "github.com/dymensionxyz/roller/data_layer/celestia" "github.com/dymensionxyz/roller/utils/bash" "github.com/dymensionxyz/roller/utils/config/tomlconfig" "github.com/dymensionxyz/roller/utils/errorhandling" @@ -69,7 +68,6 @@ func Cmd() *cobra.Command { ctx, cancel := context.WithCancel(context.Background()) fmt.Println(startDALCCmd.String()) - defer cancel() go bash.RunCmdAsync( ctx, @@ -88,7 +86,7 @@ func Cmd() *cobra.Command { func addFlags(cmd *cobra.Command) { cmd.Flags(). - StringP(rpcEndpointFlag, "", celestia.DefaultCelestiaRPC, "The DA rpc endpoint to connect to.") + StringP(rpcEndpointFlag, "", "celestia-testnet-consensus.itrocket.net", "The DA rpc endpoint to connect to.") cmd.Flags(). StringP(metricsEndpointFlag, "", "", "The OTEL collector metrics endpoint to connect to.") } diff --git a/cmd/relayer/relayer.go b/cmd/relayer/relayer.go index 4629f73d..61c9be56 100644 --- a/cmd/relayer/relayer.go +++ b/cmd/relayer/relayer.go @@ -4,7 +4,11 @@ import ( "github.com/spf13/cobra" "github.com/dymensionxyz/roller/cmd/relayer/run" + "github.com/dymensionxyz/roller/cmd/relayer/start" "github.com/dymensionxyz/roller/cmd/relayer/status" + "github.com/dymensionxyz/roller/cmd/services" + loadservices "github.com/dymensionxyz/roller/cmd/services/load" + startservices "github.com/dymensionxyz/roller/cmd/services/start" ) func Cmd() *cobra.Command { @@ -13,7 +17,9 @@ func Cmd() *cobra.Command { Short: "Commands for running and managing the RollApp relayer.", } cmd.AddCommand(run.Cmd()) - // cmd.AddCommand(start.Cmd()) + cmd.AddCommand(start.Cmd()) cmd.AddCommand(status.Cmd()) + cmd.AddCommand(services.Cmd(loadservices.RelayerCmd(), startservices.RelayerCmd())) + return cmd } diff --git a/cmd/relayer/run/run.go b/cmd/relayer/run/run.go index dd4c7e18..e1d05abf 100644 --- a/cmd/relayer/run/run.go +++ b/cmd/relayer/run/run.go @@ -2,12 +2,14 @@ package run import ( "context" + "encoding/json" "fmt" "math/big" "os" "path/filepath" "strconv" + comettypes "github.com/cometbft/cometbft/types" "github.com/pterm/pterm" "github.com/spf13/cobra" @@ -22,6 +24,7 @@ import ( "github.com/dymensionxyz/roller/utils/config/tomlconfig" dymintutils "github.com/dymensionxyz/roller/utils/dymint" "github.com/dymensionxyz/roller/utils/errorhandling" + genesisutils "github.com/dymensionxyz/roller/utils/genesis" rollapputils "github.com/dymensionxyz/roller/utils/rollapp" ) @@ -43,15 +46,41 @@ func Cmd() *cobra.Command { Run: func(cmd *cobra.Command, args []string) { home, _ := globalutils.ExpandHomePath(cmd.Flag(utils.FlagNames.Home).Value.String()) relayerHome := filepath.Join(home, consts.ConfigDirName.Relayer) + + genesis, err := comettypes.GenesisDocFromFile(genesisutils.GetGenesisFilePath(home)) + if err != nil { + return + } + + // TODO: refactor + var need genesisutils.AppState + j, _ := genesis.AppState.MarshalJSON() + json.Unmarshal(j, &need) + rollappDenom := need.Bank.Supply[0].Denom + + rollerConfigFilePath := filepath.Join(home, consts.RollerConfigFileName) + globalutils.UpdateFieldInToml(rollerConfigFilePath, "base_denom", rollappDenom) + rollappConfig, err := tomlconfig.LoadRollerConfig(home) if err != nil { pterm.Error.Printf("failed to load rollapp config: %v\n", err) return } - rollerConfigFilePath := filepath.Join(home, "roller.toml") relayerLogFilePath := utils.GetRelayerLogPath(rollappConfig) relayerLogger := utils.GetLogger(relayerLogFilePath) + hd, err := tomlconfig.LoadHubData(home) + if err != nil { + pterm.Error.Println("failed to load hub data from roller.toml") + } + + rollappChainData, err := tomlconfig.LoadRollappMetadataFromChain( + home, + rollappConfig.RollappID, + &hd, + ) + errorhandling.PrettifyErrorIfExists(err) + /* ---------------------------- Initialize relayer --------------------------- */ outputHandler := initconfig.NewOutputHandler(false) isRelayerInitialized, err := globalutils.DirNotEmpty(relayerHome) @@ -93,7 +122,7 @@ func Cmd() *cobra.Command { return } currentHeight, err := strconv.Atoi( - strconv.FormatInt(blockInformation.Block.Header.Height, 10), + blockInformation.Block.Header.Height, ) if err != nil { pterm.Error.Printf("failed to get current block height: %v\n", err) @@ -101,29 +130,27 @@ func Cmd() *cobra.Command { } if currentHeight <= 2 { pterm.Warning.Println("current height is too low, updating dymint config") - err := dymintutils.UpdateDymintConfigForIBC(home) + err := dymintutils.UpdateDymintConfigForIBC(home, "5s") if err != nil { pterm.Error.Println("failed to update dymint config") return } } - rollappPrefix, err := globalutils.GetKeyFromTomlFile( - rollerConfigFilePath, - "bech32_prefix", - ) + rollappPrefix := rollappChainData.Bech32Prefix if err != nil { pterm.Error.Printf("failed to retrieve bech32_prefix: %v\n", err) return } + pterm.Info.Println("initializing relayer config") err = initconfig.InitializeRelayerConfig( relayer.ChainConfig{ ID: rollappConfig.RollappID, RPC: consts.DefaultRollappRPC, - Denom: rollappConfig.Denom, + Denom: rollappDenom, AddressPrefix: rollappPrefix, - GasPrices: "0", + GasPrices: "1000000000", }, relayer.ChainConfig{ ID: rollappConfig.HubData.ID, RPC: rollappConfig.HubData.RPC_URL, @@ -140,7 +167,10 @@ func Cmd() *cobra.Command { return } - err = dymintutils.UpdateDymintConfigForIBC(home) + pterm.Info.Println( + "updating dymint config to 5s block time for relayer configuration", + ) + err = dymintutils.UpdateDymintConfigForIBC(home, "5s") if err != nil { pterm.Error.Println( "failed to update dymint config for ibc creation", @@ -168,7 +198,7 @@ func Cmd() *cobra.Command { } logFileOption := utils.WithLoggerLogging(relayerLogger) - errorhandling.RequireMigrateIfNeeded(rollappConfig) + // errorhandling.RequireMigrateIfNeeded(rollappConfig) err = rollappConfig.Validate() if err != nil { @@ -236,6 +266,7 @@ func Cmd() *cobra.Command { pterm.Info.Println("establishing IBC transfer channel") seq := sequencer.GetInstance(rollappConfig) + _, err = rly.CreateIBCChannel(shouldOverwrite, logFileOption, seq) if err != nil { pterm.Error.Printf("failed to create IBC channel: %v\n", err) @@ -258,7 +289,20 @@ func Cmd() *cobra.Command { rly.DstChannel, ) - select {} + pterm.Info.Println("reverting dymint config to 1h") + err = dymintutils.UpdateDymintConfigForIBC(home, "1h0m0s") + if err != nil { + pterm.Error.Println("failed to update dymint config") + return + } + + // select {} + pterm.Info.Println("next steps:") + pterm.Info.Printf( + "run %s to start rollapp and da-light-client on your local machine\n", + pterm.DefaultBasicText.WithStyle(pterm.FgYellow.ToStyle()). + Sprintf("roller relayer services load"), + ) }, } diff --git a/cmd/relayer/start/start.go b/cmd/relayer/start/start.go index 30b5d7ab..b7944bee 100644 --- a/cmd/relayer/start/start.go +++ b/cmd/relayer/start/start.go @@ -5,12 +5,12 @@ import ( "fmt" "math/big" + "github.com/pterm/pterm" "github.com/spf13/cobra" "github.com/dymensionxyz/roller/cmd/consts" "github.com/dymensionxyz/roller/cmd/utils" "github.com/dymensionxyz/roller/relayer" - "github.com/dymensionxyz/roller/sequencer" "github.com/dymensionxyz/roller/utils/bash" "github.com/dymensionxyz/roller/utils/config" "github.com/dymensionxyz/roller/utils/config/tomlconfig" @@ -27,7 +27,7 @@ const ( flagOverride = "override" ) -func Start() *cobra.Command { +func Cmd() *cobra.Command { relayerStartCmd := &cobra.Command{ Use: "start", Short: "Starts a relayer between the Dymension hub and the rollapp.", @@ -35,7 +35,7 @@ func Start() *cobra.Command { home := cmd.Flag(utils.FlagNames.Home).Value.String() rollappConfig, err := tomlconfig.LoadRollerConfig(home) errorhandling.PrettifyErrorIfExists(err) - errorhandling.RequireMigrateIfNeeded(rollappConfig) + // errorhandling.RequireMigrateIfNeeded(rollappConfig) VerifyRelayerBalances(rollappConfig) relayerLogFilePath := utils.GetRelayerLogPath(rollappConfig) @@ -51,23 +51,28 @@ func Start() *cobra.Command { _, _, err = rly.LoadActiveChannel() errorhandling.PrettifyErrorIfExists(err) - override := cmd.Flag(flagOverride).Changed - if override { - fmt.Println("💈 Overriding the existing relayer channel") - } - if rly.ChannelReady() && !override { + // override := cmd.Flag(flagOverride).Changed + // + // if override { + // fmt.Println("💈 Overriding the existing relayer channel") + // } + + if rly.ChannelReady() { fmt.Println("💈 IBC transfer channel is already established!") status := fmt.Sprintf("Active src, %s <-> %s, dst", rly.SrcChannel, rly.DstChannel) err := rly.WriteRelayerStatus(status) errorhandling.PrettifyErrorIfExists(err) } else { - fmt.Println("💈 Establishing IBC transfer channel") - seq := sequencer.GetInstance(rollappConfig) - _, err := rly.CreateIBCChannel(override, logFileOption, seq) - errorhandling.PrettifyErrorIfExists(err) + pterm.Error.Println("💈 No channels found, ensure you've setup the relayer") + // seq := sequencer.GetInstance(rollappConfig) + // _, err := rly.CreateIBCChannel(override, logFileOption, seq) + // errorhandling.PrettifyErrorIfExists(err) + return } + ctx, cancel := context.WithCancel(context.Background()) defer cancel() + go bash.RunCmdAsync( ctx, rly.GetStartCmd(), @@ -75,6 +80,7 @@ func Start() *cobra.Command { func(errMessage string) string { return errMessage }, logFileOption, ) + fmt.Printf( "💈 The relayer is running successfully on you local machine! Channels: src, %s <-> %s, dst", rly.SrcChannel, diff --git a/cmd/rollapp/init/init.go b/cmd/rollapp/init/init.go index 10c79c84..c1bed485 100644 --- a/cmd/rollapp/init/init.go +++ b/cmd/rollapp/init/init.go @@ -1,21 +1,13 @@ package initrollapp import ( - "crypto/sha256" - "encoding/hex" - "encoding/json" "fmt" - "io" - "net/http" - "os" - "os/exec" "github.com/pterm/pterm" "github.com/spf13/cobra" initconfig "github.com/dymensionxyz/roller/cmd/config/init" "github.com/dymensionxyz/roller/cmd/consts" - "github.com/dymensionxyz/roller/utils/bash" "github.com/dymensionxyz/roller/utils/rollapp" ) @@ -88,70 +80,3 @@ func Cmd() *cobra.Command { } return cmd } - -// TODO: download the file in chunks if possible -func downloadFile(url, filepath string) error { - spinner, _ := pterm.DefaultSpinner. - Start("Downloading genesis file from ", url) - - // nolint:gosec - resp, err := http.Get(url) - if err != nil { - spinner.Fail("failed to download file: ", err) - return err - } - - // nolint:errcheck - defer resp.Body.Close() - - out, err := os.Create(filepath) - if err != nil { - spinner.Fail("failed to download file: ", err) - return err - } - // nolint:errcheck - defer out.Close() - - spinner.Success("Successfully downloaded the genesis file") - _, err = io.Copy(out, resp.Body) - if err != nil { - return err - } - return nil -} - -func calculateSHA256(filepath string) (string, error) { - file, err := os.Open(filepath) - if err != nil { - return "", fmt.Errorf("error opening file: %v", err) - } - // nolint:errcheck - defer file.Close() - - hash := sha256.New() - if _, err := io.Copy(hash, file); err != nil { - return "", fmt.Errorf("error calculating hash: %v", err) - } - - return hex.EncodeToString(hash.Sum(nil)), nil -} - -func getRollappGenesisHash(raID string, hd consts.HubData) (string, error) { - var raResponse rollapp.ShowRollappResponse - getRollappCmd := exec.Command( - consts.Executables.Dymension, - "q", "rollapp", "show", - raID, "-o", "json", "--node", hd.RPC_URL, - ) - - out, err := bash.ExecCommandWithStdout(getRollappCmd) - if err != nil { - return "", err - } - - err = json.Unmarshal(out.Bytes(), &raResponse) - if err != nil { - return "", err - } - return raResponse.Rollapp.GenesisChecksum, nil -} diff --git a/cmd/rollapp/init/utils.go b/cmd/rollapp/init/utils.go index 41265c71..9648456f 100644 --- a/cmd/rollapp/init/utils.go +++ b/cmd/rollapp/init/utils.go @@ -170,127 +170,131 @@ func runInit(cmd *cobra.Command, env string, raID string) error { } /* ------------------------ Initialize DA light node ------------------------ */ - daSpinner, _ := pterm.DefaultSpinner.Start("initializing da light client") - - damanager := datalayer.NewDAManager(initConfig.DA, initConfig.Home) - mnemonic, err := damanager.InitializeLightNodeConfig() - if err != nil { - return err - } - - sequencers, err := sequencer.GetRegisteredSequencers(raID, hd) - if err != nil { - return err - } - - height, blockIdHash, err := getLatestDABlock() - if err != nil { - return err - } - - if len(sequencers.Sequencers) == 0 { - pterm.Info.Println("no sequencers registered for the rollapp") - pterm.Info.Println("using latest height for da-light-client configuration") + if env != "mock" { + daSpinner, _ := pterm.DefaultSpinner.Start("initializing da light client") - pterm.Info.Printf( - "da light client will be initialized at height %s, block hash %s", - height, - blockIdHash, - ) - heightInt, err := strconv.Atoi(height) + damanager := datalayer.NewDAManager(initConfig.DA, initConfig.Home) + mnemonic, err := damanager.InitializeLightNodeConfig() if err != nil { return err } - celestiaConfigFilePath := filepath.Join( - home, - consts.ConfigDirName.DALightNode, - "config.toml", - ) - - err = updateCelestiaConfig(celestiaConfigFilePath, blockIdHash, heightInt) + sequencers, err := sequencer.GetRegisteredSequencers(raID, hd) if err != nil { return err } - } else { - daSpinner.UpdateText("checking for state update ") - cmd := exec.Command( - consts.Executables.Dymension, - "q", - "rollapp", - "state", - raID, - "--index", - "1", - "--node", - hd.RPC_URL, - ) - out, err := bash.ExecCommandWithStdout(cmd) + height, blockIdHash, err := GetLatestDABlock() if err != nil { - if strings.Contains(out.String(), "NotFound") { - pterm.Info.Printf("no state found for %s, da light client will be initialized with latest height", raID) - } else { + return err + } + + if len(sequencers.Sequencers) == 0 { + pterm.Info.Println("no sequencers registered for the rollapp") + pterm.Info.Println("using latest height for da-light-client configuration") + + pterm.Info.Printf( + "da light client will be initialized at height %s, block hash %s", + height, + blockIdHash, + ) + heightInt, err := strconv.Atoi(height) + if err != nil { return err } - } - daSpinner.UpdateText("state update found, extracting da height") + celestiaConfigFilePath := filepath.Join( + home, + consts.ConfigDirName.DALightNode, + "config.toml", + ) - var result Result - if err := yaml.Unmarshal(out.Bytes(), &result); err != nil { - return err - } + err = UpdateCelestiaConfig(celestiaConfigFilePath, blockIdHash, heightInt) + if err != nil { + return err + } + } else { + daSpinner.UpdateText("checking for state update ") + cmd := exec.Command( + consts.Executables.Dymension, + "q", + "rollapp", + "state", + raID, + "--index", + "1", + "--node", + hd.RPC_URL, + ) + + out, err := bash.ExecCommandWithStdout(cmd) + if err != nil { + if strings.Contains(out.String(), "NotFound") { + pterm.Info.Printf( + "no state found for %s, da light client will be initialized with latest height", + raID, + ) + } else { + return err + } + } - h, err := extractHeightfromDAPath(result.StateInfo.DAPath) - if err != nil { - return err - } + daSpinner.UpdateText("state update found, extracting da height") - height, hash, err := getDABlockByHeight(h) - if err != nil { - return err - } + var result Result + if err := yaml.Unmarshal(out.Bytes(), &result); err != nil { + return err + } - heightInt, err := strconv.Atoi(height) - if err != nil { - return err - } + h, err := ExtractHeightfromDAPath(result.StateInfo.DAPath) + if err != nil { + return err + } - celestiaConfigFilePath := filepath.Join( - home, - consts.ConfigDirName.DALightNode, - "config.toml", - ) + height, hash, err := GetDABlockByHeight(h) + if err != nil { + return err + } + + heightInt, err := strconv.Atoi(height) + if err != nil { + return err + } + + celestiaConfigFilePath := filepath.Join( + home, + consts.ConfigDirName.DALightNode, + "config.toml", + ) + + pterm.Info.Printf("the first %s state update has DA height of %s with hash %s\n", raID, height, hash) + pterm.Info.Printf("updating %s \n", celestiaConfigFilePath) + err = UpdateCelestiaConfig(celestiaConfigFilePath, hash, heightInt) + if err != nil { + return err + } + } - pterm.Info.Printf("the first %s state update has DA height of %s with hash %s\n", raID, height, hash) - err = updateCelestiaConfig(celestiaConfigFilePath, hash, heightInt) + daAddress, err := damanager.GetDAAccountAddress() if err != nil { return err } - return nil - } - - daAddress, err := damanager.GetDAAccountAddress() - if err != nil { - return err - } - - if daAddress != nil { - addresses = append( - addresses, utils.KeyInfo{ - Name: damanager.GetKeyName(), - Address: daAddress.Address, - Mnemonic: mnemonic, - }, - ) + if daAddress != nil { + addresses = append( + addresses, utils.KeyInfo{ + Name: damanager.GetKeyName(), + Address: daAddress.Address, + Mnemonic: mnemonic, + }, + ) + } + daSpinner.Success("successfully initialized da light client") } - daSpinner.Success("successfully initialized da light client") /* --------------------------- Initialize Rollapp -------------------------- */ - raSpinner, _ := pterm.DefaultSpinner.Start("initializing da light client") + raSpinner, _ := pterm.DefaultSpinner.Start("initializing rollapp client") - err = initconfig.InitializeRollappConfig(initConfig) + err = initconfig.InitializeRollappConfig(&initConfig, hd) if err != nil { return err } @@ -334,18 +338,6 @@ func runInit(cmd *cobra.Command, env string, raID string) error { // err := initLocalHub(initConfig) // utils.PrettifyErrorIfExists(err) // } - if env != "mock" { - err = tomlconfig.DownloadGenesis(home, initConfig) - if err != nil { - pterm.Error.Println("failed to download genesis file: ", err) - return err - } - - isChecksumValid, err := tomlconfig.CompareGenesisChecksum(home, raID, hd) - if !isChecksumValid { - return err - } - } raSpinner.Success("rollapp initialized successfully") /* ------------------------------ Print output ------------------------------ */ @@ -355,7 +347,7 @@ func runInit(cmd *cobra.Command, env string, raID string) error { return nil } -func updateCelestiaConfig(file, hash string, height int) error { +func UpdateCelestiaConfig(file, hash string, height int) error { // Read existing config data, err := os.ReadFile(file) if err != nil { @@ -397,11 +389,11 @@ func updateCelestiaConfig(file, hash string, height int) error { return nil } -// getLatestDABlock returns the latest DA (Data Availability) block information. +// GetLatestDABlock returns the latest DA (Data Availability) block information. // It executes the CelestiaApp command "q block --node" to retrieve the block data. // It then extracts the block height and block ID hash from the JSON response. // Returns the block height, block ID hash, and any error encountered during the process. -func getLatestDABlock() (string, string, error) { +func GetLatestDABlock() (string, string, error) { cmd := exec.Command( consts.Executables.CelestiaApp, "q", "block", "--node", celestia.DefaultCelestiaRPC, @@ -443,12 +435,12 @@ func getLatestDABlock() (string, string, error) { return height, blockIdHash, nil } -// getDABlockByHeight returns the DA (Data Availability) block information for the given height. +// GetDABlockByHeight returns the DA (Data Availability) block information for the given height. // It executes the CelestiaApp command "q block --node" to retrieve the block data, // where is the input parameter. // It then extracts the block height and block ID hash from the JSON response. // Returns the block height, block ID hash, and any error encountered during the process. -func getDABlockByHeight(h string) (string, string, error) { +func GetDABlockByHeight(h string) (string, string, error) { cmd := exec.Command( consts.Executables.CelestiaApp, "q", "block", h, "--node", celestia.DefaultCelestiaRPC, @@ -515,7 +507,7 @@ type Result struct { StateInfo StateInfo `yaml:"stateInfo"` } -func extractHeightfromDAPath(input string) (string, error) { +func ExtractHeightfromDAPath(input string) (string, error) { parts := strings.Split(input, "|") if len(parts) < 2 { return "", fmt.Errorf("input string does not have enough parts") diff --git a/cmd/rollapp/run/run.go b/cmd/rollapp/run/run.go index 92c9d7e3..8ae2f4e4 100644 --- a/cmd/rollapp/run/run.go +++ b/cmd/rollapp/run/run.go @@ -11,6 +11,7 @@ import ( "os/exec" "path/filepath" "regexp" + "strconv" "strings" cosmossdkmath "cosmossdk.io/math" @@ -19,9 +20,11 @@ import ( dymensionseqtypes "github.com/dymensionxyz/dymension/v3/x/sequencer/types" "github.com/pterm/pterm" "github.com/spf13/cobra" + yaml "gopkg.in/yaml.v2" initconfig "github.com/dymensionxyz/roller/cmd/config/init" "github.com/dymensionxyz/roller/cmd/consts" + initrollapp "github.com/dymensionxyz/roller/cmd/rollapp/init" "github.com/dymensionxyz/roller/cmd/utils" datalayer "github.com/dymensionxyz/roller/data_layer" "github.com/dymensionxyz/roller/sequencer" @@ -396,6 +399,111 @@ func Cmd() *cobra.Command { } daWalletInfo.Mnemonic = mnemonic daWalletInfo.Print(utils.WithMnemonic(), utils.WithName()) + + daSpinner, _ := pterm.DefaultSpinner.WithRemoveWhenDone(true). + Start("initializing da light client") + daSpinner.UpdateText("checking for state update ") + cmd := exec.Command( + consts.Executables.Dymension, + "q", + "rollapp", + "state", + rollappConfig.RollappID, + "--index", + "1", + "--node", + hd.RPC_URL, + ) + + out, err := bash.ExecCommandWithStdout(cmd) + if err != nil { + if strings.Contains(out.String(), "key not found") { + pterm.Info.Printf( + "no state found for %s, da light client will be initialized with latest height", + rollappConfig.RollappID, + ) + + height, blockIdHash, err := initrollapp.GetLatestDABlock() + if err != nil { + return + } + + heightInt, err := strconv.Atoi(height) + if err != nil { + pterm.Error.Println("failed to convert height to int: ", err) + return + } + + celestiaConfigFilePath := filepath.Join( + home, + consts.ConfigDirName.DALightNode, + "config.toml", + ) + + pterm.Info.Printf("updating %s \n", celestiaConfigFilePath) + err = initrollapp.UpdateCelestiaConfig( + celestiaConfigFilePath, + blockIdHash, + heightInt, + ) + if err != nil { + pterm.Error.Println("failed to update celestia config: ", err) + return + } + } else { + pterm.Error.Println("failed to retrieve rollapp state update: ", err) + return + } + // nolint:errcheck,gosec + daSpinner.Stop() + } else { + daSpinner.UpdateText("state update found, extracting da height") + // nolint:errcheck,gosec + daSpinner.Stop() + + var result initrollapp.Result + if err := yaml.Unmarshal(out.Bytes(), &result); err != nil { + pterm.Error.Println("failed to unmarshal result: ", err) + return + } + + h, err := initrollapp.ExtractHeightfromDAPath(result.StateInfo.DAPath) + if err != nil { + pterm.Error.Println("failed to extract height: ", err) + return + } + + height, hash, err := initrollapp.GetDABlockByHeight(h) + if err != nil { + pterm.Error.Println("failed to retrieve block: ", err) + return + } + + heightInt, err := strconv.Atoi(height) + if err != nil { + pterm.Error.Println("failed to convert height to int: ", err) + return + } + + celestiaConfigFilePath := filepath.Join( + home, + consts.ConfigDirName.DALightNode, + "config.toml", + ) + + pterm.Info.Printf( + "the first %s state update has DA height of %s with hash %s\n", + rollappConfig.RollappID, + height, + hash, + ) + pterm.Info.Printf("updating %s \n", celestiaConfigFilePath) + err = initrollapp.UpdateCelestiaConfig(celestiaConfigFilePath, hash, heightInt) + if err != nil { + pterm.Error.Println("failed to update celestia config: ", err) + return + } + } } var daConfig string diff --git a/cmd/root.go b/cmd/root.go index e812d3ac..f87a9d0b 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -5,17 +5,11 @@ import ( "github.com/spf13/cobra" - "github.com/dymensionxyz/roller/cmd/config" da_light_client "github.com/dymensionxyz/roller/cmd/da-light-client" "github.com/dymensionxyz/roller/cmd/eibc" - "github.com/dymensionxyz/roller/cmd/keys" - "github.com/dymensionxyz/roller/cmd/migrate" "github.com/dymensionxyz/roller/cmd/relayer" "github.com/dymensionxyz/roller/cmd/rollapp" - "github.com/dymensionxyz/roller/cmd/run" - "github.com/dymensionxyz/roller/cmd/tx" "github.com/dymensionxyz/roller/cmd/utils" - "github.com/dymensionxyz/roller/cmd/version" ) var rootCmd = &cobra.Command{ @@ -34,16 +28,16 @@ func Execute() { } func init() { - rootCmd.AddCommand(config.Cmd()) - rootCmd.AddCommand(version.Cmd()) + // rootCmd.AddCommand(config.Cmd()) + // rootCmd.AddCommand(version.Cmd()) rootCmd.AddCommand(da_light_client.DALightClientCmd()) rootCmd.AddCommand(relayer.Cmd()) - rootCmd.AddCommand(keys.Cmd()) - rootCmd.AddCommand(run.Cmd()) + // rootCmd.AddCommand(keys.Cmd()) + // rootCmd.AddCommand(run.Cmd()) // rootCmd.AddCommand(services.Cmd()) - rootCmd.AddCommand(migrate.Cmd()) - rootCmd.AddCommand(tx.Cmd()) - rootCmd.AddCommand(test()) + // rootCmd.AddCommand(migrate.Cmd()) + // rootCmd.AddCommand(tx.Cmd()) + // rootCmd.AddCommand(test()) rootCmd.AddCommand(rollapp.Cmd()) rootCmd.AddCommand(eibc.Cmd()) utils.AddGlobalFlags(rootCmd) diff --git a/cmd/services/load/load.go b/cmd/services/load/load.go index ef300935..1af7f744 100644 --- a/cmd/services/load/load.go +++ b/cmd/services/load/load.go @@ -75,6 +75,52 @@ func RollappCmd() *cobra.Command { return cmd } +func RelayerCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "load", + Short: "Loads the different rollapp services on the local machine", + Run: func(cmd *cobra.Command, args []string) { + if runtime.GOOS != "linux" { + pterm.Error.Printf( + "the %s commands are only available on linux machines\n", + pterm.DefaultBasicText.WithStyle(pterm.FgYellow.ToStyle()). + Sprintf("'services'"), + ) + + return + } + services := []string{"relayer"} + for _, service := range services { + serviceData := ServiceTemplateData{ + Name: service, + ExecPath: consts.Executables.Roller, + UserName: os.Getenv("USER"), + } + tpl, err := generateServiceTemplate(serviceData) + errorhandling.PrettifyErrorIfExists(err) + err = writeServiceFile(tpl, service) + errorhandling.PrettifyErrorIfExists(err) + } + _, err := bash.ExecCommandWithStdout( + exec.Command("sudo", "systemctl", "daemon-reload"), + ) + errorhandling.PrettifyErrorIfExists(err) + pterm.Success.Printf( + "💈 Services %s been loaded successfully.\n", + strings.Join(services, ", "), + ) + + pterm.Info.Println("next steps:") + pterm.Info.Printf( + "run %s to start rollapp and da-light-client on your local machine\n", + pterm.DefaultBasicText.WithStyle(pterm.FgYellow.ToStyle()). + Sprintf("roller rollapp services start"), + ) + }, + } + return cmd +} + func writeServiceFile(serviceTxt *bytes.Buffer, serviceName string) error { filePath := filepath.Join("/etc/systemd/system/", fmt.Sprintf("%s.service", serviceName)) cmd := exec.Command( diff --git a/cmd/services/start/start.go b/cmd/services/start/start.go index fb9f234a..b2b03828 100644 --- a/cmd/services/start/start.go +++ b/cmd/services/start/start.go @@ -16,27 +16,13 @@ func RollappCmd() *cobra.Command { Use: "start", Short: "Loads the different rollapp services on the local machine", Run: func(cmd *cobra.Command, args []string) { - if runtime.GOOS != "linux" { - pterm.Error.Printf( - "the %s commands are only available on linux machines", - pterm.DefaultBasicText.WithStyle(pterm.FgYellow.ToStyle()). - Sprintf("'services'"), - ) - - return - } services := []string{"rollapp", "da-light-client"} - for _, service := range services { - err := servicemanager.StartSystemdService(fmt.Sprintf("%s.service", service)) - if err != nil { - pterm.Error.Printf("failed to start %s systemd service: %v\n", service, err) - return - } + err := startSystemdServices(services) + if err != nil { + pterm.Error.Println("failed to start systemd services:", err) + return } - pterm.Success.Printf( - "💈 Services %s started successfully.\n", - strings.Join(services, ", "), - ) + pterm.Info.Println("next steps:") pterm.Info.Printf( "run %s to set up IBC channels and start relaying packets\n", @@ -47,3 +33,45 @@ func RollappCmd() *cobra.Command { } return cmd } + +func RelayerCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "start", + Short: "Loads the different rollapp services on the local machine", + Run: func(cmd *cobra.Command, args []string) { + services := []string{"relayer"} + err := startSystemdServices(services) + if err != nil { + pterm.Error.Println("failed to start systemd services:", err) + return + } + + pterm.Info.Println("next steps:") + pterm.Info.Printf( + "run %s to join the eibc market\n", + pterm.DefaultBasicText.WithStyle(pterm.FgYellow.ToStyle()). + Sprintf("roller eibc run"), + ) + }, + } + return cmd +} + +func startSystemdServices(services []string) error { + if runtime.GOOS != "linux" { + return fmt.Errorf( + "the services commands are only available on linux machines", + ) + } + for _, service := range services { + err := servicemanager.StartSystemdService(fmt.Sprintf("%s.service", service)) + if err != nil { + return fmt.Errorf("failed to start %s systemd service: %v", service, err) + } + } + pterm.Success.Printf( + "💈 Services %s started successfully.\n", + strings.Join(services, ", "), + ) + return nil +} diff --git a/go.sum b/go.sum index 2cfeef63..d5614b22 100644 --- a/go.sum +++ b/go.sum @@ -466,6 +466,7 @@ github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1: github.com/coinbase/kryptology v1.8.0/go.mod h1:RYXOAPdzOGUe3qlSFkMGn58i3xUA8hmxYHksuq+8ciI= github.com/coinbase/rosetta-sdk-go v0.7.9 h1:lqllBjMnazTjIqYrOGv8h8jxjg9+hJazIGZr9ZvoCcA= github.com/coinbase/rosetta-sdk-go v0.7.9/go.mod h1:0/knutI7XGVqXmmH4OQD8OckFrbQ8yMsUZTG7FXCR2M= +github.com/cometbft/cometbft v0.34.28/go.mod h1:L9shMfbkZ8B+7JlwANEr+NZbBcn+hBpwdbeYvA5rLCw= github.com/cometbft/cometbft v0.34.29 h1:Q4FqMevP9du2pOgryZJHpDV2eA6jg/kMYxBj9ZTY6VQ= github.com/cometbft/cometbft v0.34.29/go.mod h1:L9shMfbkZ8B+7JlwANEr+NZbBcn+hBpwdbeYvA5rLCw= github.com/cometbft/cometbft v0.37.5 h1:/U/TlgMh4NdnXNo+YU9T2NMCWyhXNDF34Mx582jlvq0= diff --git a/relayer/channels.go b/relayer/channels.go index 23636737..9775bd60 100644 --- a/relayer/channels.go +++ b/relayer/channels.go @@ -23,10 +23,12 @@ func (r *Relayer) LoadActiveChannel() (string, string, error) { r.logger.Printf("No active connection found. Key not found: %v", keyErr) return "", "", nil } else { + r.logger.Println("something bad happened", err) return "", "", err } } if activeConnectionID == "" { + r.logger.Println("no active connection found") return "", "", nil } @@ -85,7 +87,6 @@ func (r *Relayer) LoadActiveChannel() (string, string, error) { // Found open channel on both ends foundOpenChannel = outputStruct - fmt.Println("found", foundOpenChannel) break } diff --git a/relayer/connections.go b/relayer/connections.go index 80499147..d600421d 100644 --- a/relayer/connections.go +++ b/relayer/connections.go @@ -94,22 +94,17 @@ func (r *Relayer) GetActiveConnection() (string, error) { } // END: try to read connection information from the configuration file - var hubConnectionInfo ConnectionsQueryResult - hubConnectionOutput, err := bash.ExecCommandWithStdout(r.queryConnectionsHubCmd()) - if err != nil { - r.logger.Printf("couldn't find any open connections for %s", r.HubID) - return "", err - } - err = json.Unmarshal(hubConnectionOutput.Bytes(), &hubConnectionInfo) - if err != nil { - r.logger.Printf("couldn't unmarshal hub connection info: %v", err) - } + // var hubConnectionInfo ConnectionsQueryResult + // hubConnectionOutput, err := bash.ExecCommandWithStdout(r.queryConnectionsHubCmd()) + // if err != nil { + // r.logger.Printf("couldn't find any open connections for %s", r.HubID) + // return "", err + // } // fetch connection from the chain rollappConnectionOutput, err := bash.ExecCommandWithStdout( r.queryConnectionRollappCmd( - hubConnectionInfo. - Counterparty.ConnectionID, + "connection-0", ), ) if err != nil { @@ -132,10 +127,13 @@ func (r *Relayer) GetActiveConnection() (string, error) { if outputStruct.Connection.State != "STATE_OPEN" { return "", nil } + hubConnectionID := outputStruct.Connection.Counterparty.ConnectionID // Check if the connection is open on the hub var res ConnectionQueryResult - outputHub, err := bash.ExecCommandWithStdout(r.queryConnectionHubCmd(hubConnectionInfo.ID)) + outputHub, err := bash.ExecCommandWithStdout( + r.queryConnectionHubCmd(hubConnectionID), + ) if err != nil { return "", err } @@ -159,7 +157,7 @@ func (r *Relayer) GetActiveConnection() (string, error) { err = roller_utils.SetNestedValue( rlyCfg, []string{"paths", consts.DefaultRelayerPath, "src", "connection-id"}, - hubConnectionInfo.ID, + hubConnectionID, ) if err != nil { return "", err @@ -167,8 +165,8 @@ func (r *Relayer) GetActiveConnection() (string, error) { err = roller_utils.SetNestedValue( rlyCfg, - []string{"paths", consts.DefaultRelayerPath, "src", "connection-id"}, - hubConnectionInfo.ID, + []string{"paths", consts.DefaultRelayerPath, "dst", "connection-id"}, + "connection-0", ) if err != nil { return "", err @@ -177,7 +175,7 @@ func (r *Relayer) GetActiveConnection() (string, error) { err = roller_utils.SetNestedValue( rlyCfg, []string{"paths", consts.DefaultRelayerPath, "src", "client-id"}, - hubConnectionInfo.ID, + outputStruct.Connection.Counterparty.ClientID, ) if err != nil { return "", err @@ -186,13 +184,13 @@ func (r *Relayer) GetActiveConnection() (string, error) { err = roller_utils.SetNestedValue( rlyCfg, []string{"paths", consts.DefaultRelayerPath, "src", "client-id"}, - hubConnectionInfo.ID, + "07-tendermint-0", ) if err != nil { return "", err } - return hubConnectionInfo.Counterparty.ConnectionID, nil + return "connection-0", nil } func (r *Relayer) queryConnectionRollappCmd(connectionID string) *exec.Cmd { diff --git a/sequencer/config.go b/sequencer/config.go index 3b932bf8..d9ee8d16 100644 --- a/sequencer/config.go +++ b/sequencer/config.go @@ -98,7 +98,8 @@ func SetAppConfig(rlpCfg config.RollappConfig) error { return fmt.Errorf("failed to load %s: %v", appConfigFilePath, err) } - appCfg.Set("minimum-gas-prices", "1000000000"+rlpCfg.Denom) + appCfg.Set("minimum-gas-prices", "2000000000"+rlpCfg.BaseDenom) + appCfg.Set("gas-adjustment", 1.3) appCfg.Set("api.enable", true) appCfg.Set("api.enabled-unsafe-cors", true) diff --git a/test/config/init/testutils/rollapp.go b/test/config/init/testutils/rollapp.go index 519aa83b..98c5fd9a 100644 --- a/test/config/init/testutils/rollapp.go +++ b/test/config/init/testutils/rollapp.go @@ -5,6 +5,7 @@ import ( initconfig "github.com/dymensionxyz/roller/cmd/config/init" "github.com/dymensionxyz/roller/cmd/consts" + "github.com/dymensionxyz/roller/utils/rollapp" ) func getRollappKeysDir(root string) string { @@ -46,11 +47,11 @@ func VerifyRollappKeys(root string) error { } func getNodeKeyPath(root string) string { - return filepath.Join(initconfig.RollappConfigDir(root), "node_key.json") + return filepath.Join(rollapp.RollappConfigDir(root), "node_key.json") } func getPrivValKeyPath(root string) string { - return filepath.Join(initconfig.RollappConfigDir(root), "priv_validator_key.json") + return filepath.Join(rollapp.RollappConfigDir(root), "priv_validator_key.json") } func SanitizeGenesis(genesisPath string) error { diff --git a/utils/bash/bash_commands.go b/utils/bash/bash_commands.go index d9bf4a66..9bda25b9 100644 --- a/utils/bash/bash_commands.go +++ b/utils/bash/bash_commands.go @@ -110,7 +110,7 @@ func ExecCommandWithStdout(cmd *exec.Cmd) (bytes.Buffer, error) { cmd.Stdout = &stdout err := cmd.Run() if err != nil { - return stdout, fmt.Errorf("command execution failed: %w, stderr: %s", err, stderr.String()) + return stderr, fmt.Errorf("command execution failed: %w, stderr: %s", err, stderr.String()) } return stdout, nil } diff --git a/utils/config/config.go b/utils/config/config.go index 1c70cd90..643ee13a 100644 --- a/utils/config/config.go +++ b/utils/config/config.go @@ -45,22 +45,10 @@ func (c RollappConfig) Validate() error { // return err // } - err = IsValidDenom(c.BaseDenom) - if err != nil { - return err - } - if err := ValidateDecimals(c.Decimals); err != nil { - return err - } - if !IsValidDAType(string(c.DA)) { return fmt.Errorf("invalid DA type: %s. supported types %s", c.DA, SupportedDas) } - if !IsValidVMType(string(c.VMType)) { - return fmt.Errorf("invalid VM type: %s", c.VMType) - } - return nil } diff --git a/utils/config/tomlconfig/toml.go b/utils/config/tomlconfig/toml.go index 86966824..c866229c 100644 --- a/utils/config/tomlconfig/toml.go +++ b/utils/config/tomlconfig/toml.go @@ -1,21 +1,12 @@ package tomlconfig import ( - "crypto/sha256" - "encoding/hex" "encoding/json" - "fmt" - "io" - "net/http" "os" - "os/exec" "path/filepath" - comettypes "github.com/cometbft/cometbft/types" naoinatoml "github.com/naoina/toml" - "github.com/pterm/pterm" - initconfig "github.com/dymensionxyz/roller/cmd/config/init" "github.com/dymensionxyz/roller/cmd/consts" "github.com/dymensionxyz/roller/utils/bash" "github.com/dymensionxyz/roller/utils/config" @@ -118,7 +109,7 @@ func LoadRollappMetadataFromChain( RollappID: raResponse.Rollapp.RollappId, RollappBinary: consts.Executables.RollappEVM, VMType: consts.EVM_ROLLAPP, - Denom: "mock", + Denom: "", Decimals: 18, HubData: *hd, DA: consts.Celestia, @@ -126,7 +117,7 @@ func LoadRollappMetadataFromChain( Environment: hd.ID, ExecutionVersion: version.BuildVersion, Bech32Prefix: raResponse.Rollapp.Bech32Prefix, - BaseDenom: "amock", + BaseDenom: "", MinGasPrices: "0", } @@ -134,116 +125,3 @@ func LoadRollappMetadataFromChain( return &cfg, nil } - -func DownloadGenesis(home string, rollappConfig config.RollappConfig) error { - genesisPath := initconfig.GetGenesisFilePath(home) - genesisUrl := rollappConfig.GenesisUrl - err := downloadFile(genesisUrl, genesisPath) - if err != nil { - return err - } - - // move to helper function with a spinner? - genesis, err := comettypes.GenesisDocFromFile(genesisPath) - if err != nil { - return err - } - - if genesis.ChainID != rollappConfig.RollappID { - err = fmt.Errorf( - "the genesis file ChainID (%s) does not match the rollapp ID you're trying to initialize ("+ - "%s)", - genesis.ChainID, - rollappConfig.RollappID, - ) - return err - } - - return nil -} - -func CompareGenesisChecksum(root, raID string, hd consts.HubData) (bool, error) { - genesisPath := initconfig.GetGenesisFilePath(root) - downloadedGenesisHash, err := calculateSHA256(genesisPath) - if err != nil { - pterm.Error.Println("failed to calculate hash of genesis file: ", err) - return false, err - } - raGenesisHash, _ := getRollappGenesisHash(raID, hd) - if downloadedGenesisHash != raGenesisHash { - err = fmt.Errorf( - "the hash of the downloaded file (%s) does not match the one registered with the rollapp (%s)", - downloadedGenesisHash, - raGenesisHash, - ) - return false, err - } - - return true, nil -} - -// TODO: download the file in chunks if possible -func downloadFile(url, filepath string) error { - spinner, _ := pterm.DefaultSpinner. - Start("Downloading genesis file from ", url) - - // nolint:gosec - resp, err := http.Get(url) - if err != nil { - spinner.Fail("failed to download file: ", err) - return err - } - // nolint:errcheck - defer resp.Body.Close() - - out, err := os.Create(filepath) - if err != nil { - spinner.Fail("failed to download file: ", err) - return err - } - // nolint:errcheck - defer out.Close() - - spinner.Success("Successfully downloaded the genesis file") - _, err = io.Copy(out, resp.Body) - if err != nil { - return err - } - return nil -} - -func calculateSHA256(filepath string) (string, error) { - file, err := os.Open(filepath) - if err != nil { - return "", fmt.Errorf("error opening file: %v", err) - } - // nolint:errcheck - defer file.Close() - - hash := sha256.New() - if _, err := io.Copy(hash, file); err != nil { - return "", fmt.Errorf("error calculating hash: %v", err) - } - - return hex.EncodeToString(hash.Sum(nil)), nil -} - -func getRollappGenesisHash(raID string, hd consts.HubData) (string, error) { - var raResponse rollapp.ShowRollappResponse - getRollappCmd := exec.Command( - consts.Executables.Dymension, - "q", "rollapp", "show", - raID, "-o", "json", "--node", hd.RPC_URL, - ) - - out, err := bash.ExecCommandWithStdout(getRollappCmd) - if err != nil { - return "", err - } - - err = json.Unmarshal(out.Bytes(), &raResponse) - if err != nil { - return "", err - } - return raResponse.Rollapp.GenesisChecksum, nil -} diff --git a/utils/dymint/dymint.go b/utils/dymint/dymint.go index 057d25f9..eb387a8d 100644 --- a/utils/dymint/dymint.go +++ b/utils/dymint/dymint.go @@ -1,7 +1,7 @@ package dymint import ( - "fmt" + "os/exec" "time" "github.com/BurntSushi/toml" @@ -9,7 +9,8 @@ import ( "github.com/dymensionxyz/roller/sequencer" "github.com/dymensionxyz/roller/utils" - tomlconfig "github.com/dymensionxyz/roller/utils/config/tomlconfig" + "github.com/dymensionxyz/roller/utils/bash" + "github.com/dymensionxyz/roller/utils/config/tomlconfig" ) // TODO: use dymint instead @@ -60,10 +61,9 @@ type dymintInstrumentationConfig struct { PrometheusListenAddr string `toml:"prometheus_listen_addr"` } -func UpdateDymintConfigForIBC(home string) error { +func UpdateDymintConfigForIBC(home string, t string) error { pterm.Info.Println("checking dymint block time settings") dymintPath := sequencer.GetDymintFilePath(home) - fmt.Println(dymintPath) dymintCfg, err := tomlconfig.Load(dymintPath) if err != nil { return err @@ -76,7 +76,11 @@ func UpdateDymintConfigForIBC(home string) error { return err } - want := time.Second * 5 + want, err := time.ParseDuration(t) + if err != nil { + return err + } + have, err := time.ParseDuration(cfg.MaxIdleTime) if err != nil { return err @@ -97,15 +101,31 @@ func UpdateDymintConfigForIBC(home string) error { if err != nil { return err } - err = utils.UpdateFieldInToml(dymintPath, "max_proof_time", want.String()) + + if want < time.Minute*1 { + err = utils.UpdateFieldInToml(dymintPath, "max_proof_time", want.String()) + if err != nil { + return err + } + } else { + err = utils.UpdateFieldInToml(dymintPath, "max_proof_time", "1m40s") + if err != nil { + return err + } + } + cmd := exec.Command( + "sudo", "systemctl", "restart", "rollapp", + ) + + // TODO: check for the systemd service status and /health endpoint instead + time.Sleep(time.Second * 2) + _, err = bash.ExecCommandWithStdout(cmd) if err != nil { return err } + } else { + pterm.Info.Println("block time settings already up to date") } - pterm.DefaultInteractiveConfirm.WithDefaultText( - "would you like roller to restart your rollapp process?", - ) - return nil } diff --git a/utils/genesis/genesis.go b/utils/genesis/genesis.go new file mode 100644 index 00000000..169d1257 --- /dev/null +++ b/utils/genesis/genesis.go @@ -0,0 +1,154 @@ +package genesis + +import ( + "crypto/sha256" + "encoding/hex" + "encoding/json" + "fmt" + "io" + "net/http" + "os" + "os/exec" + "path/filepath" + + "github.com/cometbft/cometbft/types" + "github.com/pterm/pterm" + + "github.com/dymensionxyz/roller/cmd/consts" + "github.com/dymensionxyz/roller/utils/bash" + "github.com/dymensionxyz/roller/utils/config" + "github.com/dymensionxyz/roller/utils/rollapp" +) + +type AppState struct { + Bank Bank `json:"bank"` +} + +type Bank struct { + Supply []Denom `json:"supply"` +} + +type Denom struct { + Denom string `json:"denom"` +} + +func DownloadGenesis(home string, rollappConfig config.RollappConfig) error { + pterm.Info.Println("downloading genesis file") + genesisPath := GetGenesisFilePath(home) + genesisUrl := rollappConfig.GenesisUrl + err := downloadFile(genesisUrl, genesisPath) + if err != nil { + return err + } + + // move to helper function with a spinner? + genesis, err := types.GenesisDocFromFile(genesisPath) + if err != nil { + return err + } + + if genesis.ChainID != rollappConfig.RollappID { + err = fmt.Errorf( + "the genesis file ChainID (%s) does not match the rollapp ID you're trying to initialize ("+ + "%s)", + genesis.ChainID, + rollappConfig.RollappID, + ) + return err + } + + return nil +} + +// TODO: download the file in chunks if possible +func downloadFile(url, filepath string) error { + spinner, _ := pterm.DefaultSpinner. + Start("Downloading genesis file from ", url) + + // nolint:gosec + resp, err := http.Get(url) + if err != nil { + spinner.Fail("failed to download file: ", err) + return err + } + // nolint:errcheck + defer resp.Body.Close() + + out, err := os.Create(filepath) + if err != nil { + spinner.Fail("failed to download file: ", err) + return err + } + // nolint:errcheck + defer out.Close() + + spinner.Success("Successfully downloaded the genesis file") + _, err = io.Copy(out, resp.Body) + if err != nil { + return err + } + return nil +} + +func calculateSHA256(filepath string) (string, error) { + file, err := os.Open(filepath) + if err != nil { + return "", fmt.Errorf("error opening file: %v", err) + } + // nolint:errcheck + defer file.Close() + + hash := sha256.New() + if _, err := io.Copy(hash, file); err != nil { + return "", fmt.Errorf("error calculating hash: %v", err) + } + + return hex.EncodeToString(hash.Sum(nil)), nil +} + +func getRollappGenesisHash(raID string, hd consts.HubData) (string, error) { + var raResponse rollapp.ShowRollappResponse + getRollappCmd := exec.Command( + consts.Executables.Dymension, + "q", "rollapp", "show", + raID, "-o", "json", "--node", hd.RPC_URL, + ) + + out, err := bash.ExecCommandWithStdout(getRollappCmd) + if err != nil { + return "", err + } + + err = json.Unmarshal(out.Bytes(), &raResponse) + if err != nil { + return "", err + } + return raResponse.Rollapp.GenesisChecksum, nil +} + +func CompareGenesisChecksum(root, raID string, hd consts.HubData) (bool, error) { + genesisPath := GetGenesisFilePath(root) + downloadedGenesisHash, err := calculateSHA256(genesisPath) + if err != nil { + pterm.Error.Println("failed to calculate hash of genesis file: ", err) + return false, err + } + raGenesisHash, _ := getRollappGenesisHash(raID, hd) + if downloadedGenesisHash != raGenesisHash { + err = fmt.Errorf( + "the hash of the downloaded file (%s) does not match the one registered with the rollapp (%s)", + downloadedGenesisHash, + raGenesisHash, + ) + return false, err + } + + return true, nil +} + +func GetGenesisFilePath(root string) string { + return filepath.Join( + rollapp.RollappConfigDir(root), + "genesis.json", + ) +} diff --git a/utils/relayer/relayer.go b/utils/relayer/relayer.go new file mode 100644 index 00000000..3e819a72 --- /dev/null +++ b/utils/relayer/relayer.go @@ -0,0 +1,59 @@ +package relayer + +import ( + "encoding/json" + "os/exec" + + "github.com/dymensionxyz/roller/cmd/consts" + "github.com/dymensionxyz/roller/utils/bash" +) + +type Channels struct { + Channels []struct { + State string `json:"state"` + Ordering string `json:"ordering"` + Counterparty struct { + PortId string `json:"port_id"` + ChannelId string `json:"channel_id"` + } `json:"counterparty"` + ConnectionHops []string `json:"connection_hops"` + Version string `json:"version"` + PortId string `json:"port_id"` + ChannelId string `json:"channel_id"` + } `json:"channels"` + Pagination struct { + NextKey interface{} `json:"next_key"` + Total string `json:"total"` + } `json:"pagination"` + Height struct { + RevisionNumber string `json:"revision_number"` + RevisionHeight string `json:"revision_height"` + } `json:"height"` +} + +func GetRegisteredSequencers( + raID string, hd consts.HubData, +) (*Channels, error) { + var ibcChannels Channels + cmd := GetQueryRollappIBCChannels() + + out, err := bash.ExecCommandWithStdout(cmd) + if err != nil { + return nil, err + } + + err = json.Unmarshal(out.Bytes(), &ibcChannels) + if err != nil { + return nil, err + } + + return &ibcChannels, nil +} + +func GetQueryRollappIBCChannels() *exec.Cmd { + return exec.Command( + consts.Executables.RollappEVM, + "q", "ibc", "channels", + "-o", "json", + ) +} diff --git a/utils/rollapp/rollapp.go b/utils/rollapp/rollapp.go index 492a053f..6db6af35 100644 --- a/utils/rollapp/rollapp.go +++ b/utils/rollapp/rollapp.go @@ -4,10 +4,10 @@ import ( "encoding/json" "fmt" "os/exec" + "path/filepath" "strings" dymensiontypes "github.com/dymensionxyz/dymension/v3/x/rollapp/types" - tmtypes "github.com/tendermint/tendermint/types" "github.com/dymensionxyz/roller/cmd/consts" globalutils "github.com/dymensionxyz/roller/utils/bash" @@ -78,11 +78,6 @@ func IsRollappRegistered(raID string, hd consts.HubData) (bool, error) { return true, nil } -type BlockInformation struct { - BlockId tmtypes.BlockID `json:"block_id"` - Block tmtypes.Block `json:"block"` -} - func GetShowRollappCmd(raID string, hd consts.HubData) *exec.Cmd { cmd := exec.Command( consts.Executables.Dymension, @@ -106,3 +101,7 @@ func GetRollappCmd(raID string, hd consts.HubData) *exec.Cmd { return cmd } + +func RollappConfigDir(root string) string { + return filepath.Join(root, consts.ConfigDirName.Rollapp, "config") +} diff --git a/utils/rollapp/types.go b/utils/rollapp/types.go index f8406539..8f56f9d4 100644 --- a/utils/rollapp/types.go +++ b/utils/rollapp/types.go @@ -1,5 +1,11 @@ package rollapp +import ( + "time" + + tmtypes "github.com/tendermint/tendermint/types" +) + type ShowRollappResponse struct { Rollapp Rollapp `json:"rollapp"` LatestStateIndex *StateInfoIndex `json:"latestStateIndex"` @@ -48,3 +54,27 @@ type StateInfoIndex struct { // state update used for indexing to a specific state info, the first index is 1 Index string `protobuf:"varint,2,opt,name=index,proto3" json:"index,omitempty"` } + +type BlockInformation struct { + BlockId tmtypes.BlockID `json:"block_id"` + Block Block `json:"block"` +} + +type Block struct { + Header `json:"header"` + tmtypes.Data `json:"data"` + Evidence tmtypes.EvidenceData `json:"evidence"` +} + +type Header struct { + // basic block info + Version Consensus `json:"version"` + ChainID string `json:"chain_id"` + Height string `json:"height"` + Time time.Time `json:"time"` +} + +type Consensus struct { + Block string `protobuf:"varint,1,opt,name=block,proto3" json:"block,omitempty"` + App string `protobuf:"varint,2,opt,name=app,proto3" json:"app,omitempty"` +}