From 86193333d1fb78d1af22841b3ecbc0e1af36d0c4 Mon Sep 17 00:00:00 2001 From: Itay Date: Thu, 22 Jun 2023 13:23:12 +0200 Subject: [PATCH] feat: Add IBC channel creation capability from `roller relayer start` command (#74) --- cmd/config/init/DALightClient.go | 3 +- cmd/config/init/consts.go | 13 +-- cmd/config/init/flags.go | 4 +- cmd/config/init/genesis.go | 5 +- cmd/config/init/init.go | 26 ++--- cmd/config/init/keys.go | 101 +++++++++++++++--- cmd/config/init/output.go | 5 +- cmd/config/init/relayer.go | 10 +- cmd/config/init/rollapp.go | 5 +- cmd/config/init/unique_rollapp_id.go | 5 +- cmd/consts/consts.go | 5 +- cmd/da-light-client/start/start.go | 5 +- cmd/register/bash_commands.go | 10 +- cmd/register/register.go | 12 +-- cmd/relayer/relayer.go | 15 +++ cmd/relayer/start/start.go | 37 +++++++ cmd/root.go | 2 + cmd/run/run.go | 89 +++++++++++++++ cmd/sequencer/start/start.go | 5 +- cmd/utils/bash_commands.go | 26 +++++ .../persistence_config.go => utils/config.go} | 28 +++-- cmd/utils/error_handling.go | 1 + cmd/utils/keys.go | 40 ++++--- .../relayer/config/config.yaml | 4 +- .../relayer/config/config.yaml | 4 +- test/config/init/init_test.go | 2 +- test/config/init/testutils/keys.go | 8 +- test/config/init/testutils/rollapp.go | 5 +- 28 files changed, 368 insertions(+), 107 deletions(-) create mode 100644 cmd/relayer/relayer.go create mode 100644 cmd/relayer/start/start.go create mode 100644 cmd/run/run.go rename cmd/{config/init/persistence_config.go => utils/config.go} (54%) diff --git a/cmd/config/init/DALightClient.go b/cmd/config/init/DALightClient.go index ea75f86b..cc5cff7a 100644 --- a/cmd/config/init/DALightClient.go +++ b/cmd/config/init/DALightClient.go @@ -1,13 +1,14 @@ package initconfig import ( + "github.com/dymensionxyz/roller/cmd/utils" "os/exec" "path/filepath" "github.com/dymensionxyz/roller/cmd/consts" ) -func initializeLightNodeConfig(initConfig InitConfig) error { +func initializeLightNodeConfig(initConfig utils.RollappConfig) error { initLightNodeCmd := exec.Command(consts.Executables.Celestia, "light", "init", "--p2p.network", "arabica", "--node.store", filepath.Join(initConfig.Home, consts.ConfigDirName.DALightNode)) err := initLightNodeCmd.Run() if err != nil { diff --git a/cmd/config/init/consts.go b/cmd/config/init/consts.go index d59f9e82..fb705922 100644 --- a/cmd/config/init/consts.go +++ b/cmd/config/init/consts.go @@ -1,5 +1,7 @@ package initconfig +import "github.com/dymensionxyz/roller/cmd/utils" + var FlagNames = struct { Home string Decimals string @@ -16,7 +18,7 @@ const TestnetHubID = "35-C" const StagingHubID = "internal-devnet" const LocalHubID = "local" -var Hubs = map[string]HubData{ +var Hubs = map[string]utils.HubData{ TestnetHubID: { API_URL: "https://rest-hub-35c.dymension.xyz", ID: "35-C", @@ -34,13 +36,4 @@ var Hubs = map[string]HubData{ }, } -type HubData = struct { - API_URL string - ID string - RPC_URL string -} - const defaultRollappRPC = "http://localhost:26657" - -const KeysDirName = "keys" -const RollerConfigFileName = "config.toml" diff --git a/cmd/config/init/flags.go b/cmd/config/init/flags.go index 31d1a8ea..384ec3f2 100644 --- a/cmd/config/init/flags.go +++ b/cmd/config/init/flags.go @@ -52,14 +52,14 @@ func getRollappBinaryPath(cmd *cobra.Command) string { return rollappBinaryPath } -func GetInitConfig(initCmd *cobra.Command, args []string) InitConfig { +func GetInitConfig(initCmd *cobra.Command, args []string) utils.RollappConfig { rollappId := args[0] denom := args[1] home := initCmd.Flag(utils.FlagNames.Home).Value.String() rollappBinaryPath := getRollappBinaryPath(initCmd) decimals := getDecimals(initCmd) hubID := initCmd.Flag(FlagNames.HubID).Value.String() - return InitConfig{ + return utils.RollappConfig{ Home: home, RollappID: rollappId, RollappBinary: rollappBinaryPath, diff --git a/cmd/config/init/genesis.go b/cmd/config/init/genesis.go index ce07fc35..301a7be6 100644 --- a/cmd/config/init/genesis.go +++ b/cmd/config/init/genesis.go @@ -1,17 +1,18 @@ package initconfig import ( + "github.com/dymensionxyz/roller/cmd/utils" "io/ioutil" "fmt" "os/exec" "path/filepath" - "github.com/tidwall/sjson" "github.com/dymensionxyz/roller/cmd/consts" + "github.com/tidwall/sjson" ) -func initializeRollappGenesis(initConfig InitConfig) error { +func initializeRollappGenesis(initConfig utils.RollappConfig) error { zeros := initConfig.Decimals + 9 tokenAmount := "1" + fmt.Sprintf("%0*d", zeros, 0) + initConfig.Denom rollappConfigDirPath := filepath.Join(initConfig.Home, consts.ConfigDirName.Rollapp) diff --git a/cmd/config/init/init.go b/cmd/config/init/init.go index d41f5aa5..a169732d 100644 --- a/cmd/config/init/init.go +++ b/cmd/config/init/init.go @@ -9,15 +9,6 @@ import ( "github.com/spf13/cobra" ) -type InitConfig struct { - Home string - RollappID string - RollappBinary string - Denom string - Decimals uint64 - HubData HubData -} - func InitCmd() *cobra.Command { initCmd := &cobra.Command{ Use: "init ", @@ -36,16 +27,13 @@ func InitCmd() *cobra.Command { utils.PrettifyErrorIfExists(err) if shouldOverwrite { utils.PrettifyErrorIfExists(os.RemoveAll(initConfig.Home)) + utils.PrettifyErrorIfExists(os.MkdirAll(initConfig.Home, 0755)) } else { os.Exit(0) } + } else { + utils.PrettifyErrorIfExists(os.MkdirAll(initConfig.Home, 0755)) } - - addresses, err := generateKeys(initConfig) - utils.PrettifyErrorIfExists(err) - utils.PrettifyErrorIfExists(initializeLightNodeConfig(initConfig)) - initializeRollappConfig(initConfig) - utils.PrettifyErrorIfExists(initializeRollappGenesis(initConfig)) utils.PrettifyErrorIfExists(initializeRelayerConfig(ChainConfig{ ID: initConfig.RollappID, RPC: defaultRollappRPC, @@ -57,7 +45,13 @@ func InitCmd() *cobra.Command { Denom: "udym", AddressPrefix: consts.AddressPrefixes.Hub, }, initConfig)) - utils.PrettifyErrorIfExists(WriteConfigToTOML(initConfig)) + addresses, err := generateKeys(initConfig) + utils.PrettifyErrorIfExists(err) + utils.PrettifyErrorIfExists(initializeLightNodeConfig(initConfig)) + initializeRollappConfig(initConfig) + utils.PrettifyErrorIfExists(initializeRollappGenesis(initConfig)) + + utils.PrettifyErrorIfExists(utils.WriteConfigToTOML(initConfig)) printInitOutput(addresses, initConfig.RollappID) }, Args: cobra.ExactArgs(2), diff --git a/cmd/config/init/keys.go b/cmd/config/init/keys.go index a6e657c5..57cee5c4 100644 --- a/cmd/config/init/keys.go +++ b/cmd/config/init/keys.go @@ -1,8 +1,10 @@ package initconfig import ( + "os/exec" "path" "path/filepath" + "strconv" "github.com/cosmos/cosmos-sdk/crypto/hd" "github.com/cosmos/cosmos-sdk/crypto/keyring" @@ -10,15 +12,29 @@ import ( "github.com/dymensionxyz/roller/cmd/utils" ) -func generateKeys(initConfig InitConfig, excludeKeys ...string) (map[string]string, error) { - keys := getDefaultKeysConfig(initConfig) - excludeKeysMap := make(map[string]struct{}) - for _, key := range excludeKeys { - excludeKeysMap[key] = struct{}{} +func generateKeys(rollappConfig utils.RollappConfig) (map[string]string, error) { + sequencerAddresses, err := generateSequencersKeys(rollappConfig) + if err != nil { + return nil, err + } + relayerAddresses, err := generateRelayerKeys(rollappConfig) + if err != nil { + return nil, err } + return utils.MergeMaps(sequencerAddresses, relayerAddresses), nil +} + +func generateSequencersKeys(initConfig utils.RollappConfig) (map[string]string, error) { + keys := getSequencerKeysConfig() addresses := make(map[string]string) for _, key := range keys { - if _, exists := excludeKeysMap[key.ID]; !exists { + if key.Prefix == consts.AddressPrefixes.Rollapp { + address, err := createAddressBinary(key, consts.Executables.RollappEVM, initConfig.Home) + if err != nil { + return nil, err + } + addresses[key.ID] = address + } else { keyInfo, err := createKey(key, initConfig.Home) if err != nil { return nil, err @@ -51,7 +67,7 @@ func createKey(keyConfig utils.KeyConfig, home string) (keyring.Info, error) { return info, nil } -func getDefaultKeysConfig(initConfig InitConfig) []utils.KeyConfig { +func getSequencerKeysConfig() []utils.KeyConfig { return []utils.KeyConfig{ { Dir: consts.ConfigDirName.Rollapp, @@ -65,17 +81,72 @@ func getDefaultKeysConfig(initConfig InitConfig) []utils.KeyConfig { CoinType: consts.CoinTypes.EVM, Prefix: consts.AddressPrefixes.Rollapp, }, - { - Dir: path.Join(consts.ConfigDirName.Relayer, KeysDirName, initConfig.HubData.ID), - ID: consts.KeyNames.HubRelayer, - CoinType: consts.CoinTypes.Cosmos, - Prefix: consts.AddressPrefixes.Hub, - }, - { - Dir: path.Join(consts.ConfigDirName.Relayer, KeysDirName, initConfig.RollappID), + } +} + +func getRelayerKeysConfig(rollappConfig utils.RollappConfig) map[string]utils.KeyConfig { + return map[string]utils.KeyConfig{ + consts.KeyNames.RollappRelayer: { + Dir: path.Join(rollappConfig.Home, consts.ConfigDirName.Relayer), ID: consts.KeyNames.RollappRelayer, CoinType: consts.CoinTypes.EVM, Prefix: consts.AddressPrefixes.Rollapp, }, + consts.KeyNames.HubRelayer: { + Dir: path.Join(rollappConfig.Home, consts.ConfigDirName.Relayer), + ID: consts.KeyNames.HubRelayer, + CoinType: consts.CoinTypes.Cosmos, + Prefix: consts.AddressPrefixes.Hub, + }, + } +} + +func createAddressBinary(keyConfig utils.KeyConfig, binaryPath string, home string) (string, error) { + createKeyCommand := exec.Command(binaryPath, "keys", "add", keyConfig.ID, "--keyring-backend", "test", + "--keyring-dir", filepath.Join(home, keyConfig.Dir), "--output", "json") + out, err := utils.ExecBashCommand(createKeyCommand) + if err != nil { + return "", err + } + return utils.ParseAddressFromOutput(out) +} + +func generateRelayerKeys(rollappConfig utils.RollappConfig) (map[string]string, error) { + relayerAddresses := make(map[string]string) + keys := getRelayerKeysConfig(rollappConfig) + createRollappKeyCmd := getAddRlyKeyCmd(keys[consts.KeyNames.RollappRelayer], rollappConfig.RollappID) + createHubKeyCmd := getAddRlyKeyCmd(keys[consts.KeyNames.HubRelayer], rollappConfig.HubData.ID) + out, err := utils.ExecBashCommand(createRollappKeyCmd) + if err != nil { + return nil, err + } + relayerRollappAddress, err := utils.ParseAddressFromOutput(out) + if err != nil { + return nil, err + } + relayerAddresses[consts.KeyNames.RollappRelayer] = relayerRollappAddress + out, err = utils.ExecBashCommand(createHubKeyCmd) + if err != nil { + return nil, err } + relayerHubAddress, err := utils.ParseAddressFromOutput(out) + if err != nil { + return nil, err + } + relayerAddresses[consts.KeyNames.HubRelayer] = relayerHubAddress + return relayerAddresses, err +} + +func getAddRlyKeyCmd(keyConfig utils.KeyConfig, chainID string) *exec.Cmd { + return exec.Command( + consts.Executables.Relayer, + consts.KeysDirName, + "add", + chainID, + keyConfig.ID, + "--home", + keyConfig.Dir, + "--coin-type", + strconv.Itoa(int(keyConfig.CoinType)), + ) } diff --git a/cmd/config/init/output.go b/cmd/config/init/output.go index 41a6ef8f..bb87d86e 100644 --- a/cmd/config/init/output.go +++ b/cmd/config/init/output.go @@ -4,8 +4,8 @@ import ( "fmt" "os" - "github.com/olekukonko/tablewriter" "github.com/dymensionxyz/roller/cmd/consts" + "github.com/olekukonko/tablewriter" ) func printInitOutput(addresses map[string]string, rollappId string) { @@ -16,7 +16,8 @@ func printInitOutput(addresses map[string]string, rollappId string) { data := [][]string{ {"Celestia", addresses[consts.KeyNames.DALightNode]}, {"Sequencer", addresses[consts.KeyNames.HubSequencer]}, - {"Relayer", addresses[consts.KeyNames.HubRelayer]}, + {"Relayer, Hub", addresses[consts.KeyNames.HubRelayer]}, + {"Relayer, RollApp", addresses[consts.KeyNames.RollappRelayer]}, } table := tablewriter.NewWriter(os.Stdout) diff --git a/cmd/config/init/relayer.go b/cmd/config/init/relayer.go index b738d6c7..3ec7c765 100644 --- a/cmd/config/init/relayer.go +++ b/cmd/config/init/relayer.go @@ -2,6 +2,7 @@ package initconfig import ( "encoding/json" + "github.com/dymensionxyz/roller/cmd/utils" "io/ioutil" "os" "os/exec" @@ -102,7 +103,7 @@ func addChainsConfig(rollappConfig ChainConfig, hubConfig ChainConfig, relayerHo relayerHubConfig := getRelayerFileChainConfig(RelayerChainConfig{ ChainConfig: hubConfig, - GasPrices: "0.25" + hubConfig.Denom, + GasPrices: "0.0" + hubConfig.Denom, ClientType: "07-tendermint", KeyName: consts.KeyNames.HubRelayer, }) @@ -121,15 +122,16 @@ func setupPath(rollappConfig ChainConfig, hubConfig ChainConfig, relayerHome str if err := setSettlementCmd.Run(); err != nil { return err } - relayerPath := "hub-rollapp" - newPathCmd := exec.Command(consts.Executables.Relayer, "paths", "new", rollappConfig.ID, hubConfig.ID, relayerPath, "--src-port", "transfer", "--dst-port", "transfer", "--version", "ics20-1", "--home", relayerHome) + args := []string{"paths", "new", rollappConfig.ID, hubConfig.ID, consts.DefaultRelayerPath} + args = append(args, utils.GetRelayerDefaultFlags(relayerHome)...) + newPathCmd := exec.Command(consts.Executables.Relayer, args...) if err := newPathCmd.Run(); err != nil { return err } return nil } -func initializeRelayerConfig(rollappConfig ChainConfig, hubConfig ChainConfig, initConfig InitConfig) error { +func initializeRelayerConfig(rollappConfig ChainConfig, hubConfig ChainConfig, initConfig utils.RollappConfig) error { relayerHome := filepath.Join(initConfig.Home, consts.ConfigDirName.Relayer) if err := initRelayer(relayerHome); err != nil { return err diff --git a/cmd/config/init/rollapp.go b/cmd/config/init/rollapp.go index 44052187..10f1c3b3 100644 --- a/cmd/config/init/rollapp.go +++ b/cmd/config/init/rollapp.go @@ -1,15 +1,16 @@ package initconfig import ( + "github.com/dymensionxyz/roller/cmd/utils" "os" "os/exec" "path/filepath" - toml "github.com/pelletier/go-toml" "github.com/dymensionxyz/roller/cmd/consts" + toml "github.com/pelletier/go-toml" ) -func initializeRollappConfig(initConfig InitConfig) { +func initializeRollappConfig(initConfig utils.RollappConfig) { initRollappCmd := exec.Command(initConfig.RollappBinary, "init", consts.KeyNames.HubSequencer, "--chain-id", initConfig.RollappID, "--home", filepath.Join(initConfig.Home, consts.ConfigDirName.Rollapp)) err := initRollappCmd.Run() if err != nil { diff --git a/cmd/config/init/unique_rollapp_id.go b/cmd/config/init/unique_rollapp_id.go index 13e33188..ee8a2f18 100644 --- a/cmd/config/init/unique_rollapp_id.go +++ b/cmd/config/init/unique_rollapp_id.go @@ -2,10 +2,11 @@ package initconfig import ( "fmt" + "github.com/dymensionxyz/roller/cmd/utils" "net/http" ) -func IsRollappIDUnique(rollappID string, initConfig InitConfig) (bool, error) { +func IsRollappIDUnique(rollappID string, initConfig utils.RollappConfig) (bool, error) { url := initConfig.HubData.API_URL + "/dymensionxyz/dymension/rollapp/rollapp/" + rollappID req, err := http.NewRequest("GET", url, nil) @@ -31,7 +32,7 @@ func IsRollappIDUnique(rollappID string, initConfig InitConfig) (bool, error) { } } -func VerifyUniqueRollappID(rollappID string, initConfig InitConfig) error { +func VerifyUniqueRollappID(rollappID string, initConfig utils.RollappConfig) error { isUniqueRollapp, err := IsRollappIDUnique(rollappID, initConfig) if err != nil { return err diff --git a/cmd/consts/consts.go b/cmd/consts/consts.go index bde59811..57d5ae59 100644 --- a/cmd/consts/consts.go +++ b/cmd/consts/consts.go @@ -39,7 +39,7 @@ var AddressPrefixes = struct { Rollapp string DA string }{ - Rollapp: "rol", + Rollapp: "ethm", Hub: "dym", DA: "celestia", } @@ -61,3 +61,6 @@ var CoinTypes = struct { Cosmos: 118, EVM: 60, } + +const KeysDirName = "keys" +const DefaultRelayerPath = "hub-rollapp" diff --git a/cmd/da-light-client/start/start.go b/cmd/da-light-client/start/start.go index 20ed3392..e4d79a97 100644 --- a/cmd/da-light-client/start/start.go +++ b/cmd/da-light-client/start/start.go @@ -5,7 +5,6 @@ import ( "os/exec" "path/filepath" - initconfig "github.com/dymensionxyz/roller/cmd/config/init" "github.com/dymensionxyz/roller/cmd/consts" "github.com/dymensionxyz/roller/cmd/utils" "github.com/spf13/cobra" @@ -19,7 +18,7 @@ func Cmd() *cobra.Command { Short: "Runs the rollapp sequencer.", Run: func(cmd *cobra.Command, args []string) { home := cmd.Flag(utils.FlagNames.Home).Value.String() - rollappConfig, err := initconfig.LoadConfigFromTOML(home) + rollappConfig, err := utils.LoadConfigFromTOML(home) utils.PrettifyErrorIfExists(err) rpcEndpoint := cmd.Flag(rpcEndpointFlag).Value.String() startRollappCmd := getStartCelestiaLCCmd(rollappConfig, rpcEndpoint) @@ -45,7 +44,7 @@ func parseError(errMsg string) string { return errMsg } -func getStartCelestiaLCCmd(rollappConfig initconfig.InitConfig, rpcEndpoint string) *exec.Cmd { +func getStartCelestiaLCCmd(rollappConfig utils.RollappConfig, rpcEndpoint string) *exec.Cmd { return exec.Command( consts.Executables.Celestia, "light", "start", "--core.ip", rpcEndpoint, diff --git a/cmd/register/bash_commands.go b/cmd/register/bash_commands.go index e6ee856a..310a0684 100644 --- a/cmd/register/bash_commands.go +++ b/cmd/register/bash_commands.go @@ -1,6 +1,7 @@ package register import ( + "github.com/dymensionxyz/roller/cmd/utils" "os/exec" "path/filepath" @@ -8,11 +9,10 @@ import ( "strings" - initconfig "github.com/dymensionxyz/roller/cmd/config/init" "github.com/dymensionxyz/roller/cmd/consts" ) -func getRegisterRollappCmd(rollappConfig initconfig.InitConfig) *exec.Cmd { +func getRegisterRollappCmd(rollappConfig utils.RollappConfig) *exec.Cmd { cmdArgs := []string{ "tx", "rollapp", "create-rollapp", rollappConfig.RollappID, "stamp1", "genesis-path/1", "3", "3", `{"Addresses":[]}`, } @@ -22,7 +22,7 @@ func getRegisterRollappCmd(rollappConfig initconfig.InitConfig) *exec.Cmd { ) } -func showSequencerPubKey(rollappConfig initconfig.InitConfig) (string, error) { +func showSequencerPubKey(rollappConfig utils.RollappConfig) (string, error) { cmd := exec.Command( consts.Executables.RollappEVM, "dymint", @@ -37,7 +37,7 @@ func showSequencerPubKey(rollappConfig initconfig.InitConfig) (string, error) { return strings.ReplaceAll(strings.ReplaceAll(string(out), "\n", ""), "\\", ""), nil } -func getRegisterSequencerCmd(rollappConfig initconfig.InitConfig) (*exec.Cmd, error) { +func getRegisterSequencerCmd(rollappConfig utils.RollappConfig) (*exec.Cmd, error) { seqPubKey, err := showSequencerPubKey(rollappConfig) if err != nil { return nil, err @@ -54,7 +54,7 @@ func getRegisterSequencerCmd(rollappConfig initconfig.InitConfig) (*exec.Cmd, er return exec.Command(consts.Executables.Dymension, cmdArgs...), nil } -func getCommonFlags(rollappConfig initconfig.InitConfig) []string { +func getCommonFlags(rollappConfig utils.RollappConfig) []string { return []string{ "--from", consts.KeyNames.HubSequencer, "--keyring-backend", "test", diff --git a/cmd/register/register.go b/cmd/register/register.go index 9f654988..a6c97d7b 100644 --- a/cmd/register/register.go +++ b/cmd/register/register.go @@ -22,8 +22,8 @@ func RegisterCmd() *cobra.Command { Use: "register", Short: "Registers the rollapp and the sequencer to the Dymension hub.", Run: func(cmd *cobra.Command, args []string) { - home := cmd.Flag(initconfig.FlagNames.Home).Value.String() - rollappConfig, err := initconfig.LoadConfigFromTOML(home) + home := cmd.Flag(utils.FlagNames.Home).Value.String() + rollappConfig, err := utils.LoadConfigFromTOML(home) utils.PrettifyErrorIfExists(err) utils.PrettifyErrorIfExists(initconfig.VerifyUniqueRollappID(rollappConfig.RollappID, rollappConfig)) utils.PrettifyErrorIfExists(registerRollapp(rollappConfig)) @@ -38,7 +38,7 @@ func RegisterCmd() *cobra.Command { return registerCmd } -func registerRollapp(rollappConfig initconfig.InitConfig) error { +func registerRollapp(rollappConfig utils.RollappConfig) error { cmd := getRegisterRollappCmd(rollappConfig) var stdout bytes.Buffer var stderr bytes.Buffer @@ -57,7 +57,7 @@ func registerRollapp(rollappConfig initconfig.InitConfig) error { return nil } -func handleStdErr(stderr bytes.Buffer, rollappConfig initconfig.InitConfig) error { +func handleStdErr(stderr bytes.Buffer, rollappConfig utils.RollappConfig) error { stderrStr := stderr.String() if len(stderrStr) > 0 { if strings.Contains(stderrStr, "key not found") { @@ -83,7 +83,7 @@ type Response struct { RawLog string `json:"raw_log"` } -func handleStdOut(stdout bytes.Buffer, rollappConfig initconfig.InitConfig) error { +func handleStdOut(stdout bytes.Buffer, rollappConfig utils.RollappConfig) error { var response Response err := json.NewDecoder(&stdout).Decode(&response) @@ -98,6 +98,6 @@ func handleStdOut(stdout bytes.Buffer, rollappConfig initconfig.InitConfig) erro return nil } -func printRegisterOutput(rollappConfig initconfig.InitConfig) { +func printRegisterOutput(rollappConfig utils.RollappConfig) { fmt.Printf("💈 Rollapp '%s' has been successfully registered on the hub.\n", rollappConfig.RollappID) } diff --git a/cmd/relayer/relayer.go b/cmd/relayer/relayer.go new file mode 100644 index 00000000..5db4c7fe --- /dev/null +++ b/cmd/relayer/relayer.go @@ -0,0 +1,15 @@ +package relayer + +import ( + start "github.com/dymensionxyz/roller/cmd/relayer/start" + "github.com/spf13/cobra" +) + +func Cmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "relayer", + Short: "Commands for running and managing the RollApp relayer.", + } + cmd.AddCommand(start.Start()) + return cmd +} diff --git a/cmd/relayer/start/start.go b/cmd/relayer/start/start.go new file mode 100644 index 00000000..db32a174 --- /dev/null +++ b/cmd/relayer/start/start.go @@ -0,0 +1,37 @@ +package start + +import ( + "fmt" + "github.com/dymensionxyz/roller/cmd/consts" + "github.com/dymensionxyz/roller/cmd/utils" + "github.com/spf13/cobra" + "os/exec" + "path/filepath" +) + +func Start() *cobra.Command { + registerCmd := &cobra.Command{ + Use: "start", + Short: "Starts a relayer between the Dymension hub and the rollapp.", + Run: func(cmd *cobra.Command, args []string) { + home := cmd.Flag(utils.FlagNames.Home).Value.String() + rollappConfig, err := utils.LoadConfigFromTOML(home) + utils.PrettifyErrorIfExists(err) + fmt.Println(rollappConfig) + createChannelCmd := getCreateChannelCmd(rollappConfig) + err = utils.ExecBashCommandWithOSOutput(createChannelCmd) + utils.PrettifyErrorIfExists(err) + }, + } + utils.AddGlobalFlags(registerCmd) + return registerCmd +} + +func getCreateChannelCmd(rollappConfig utils.RollappConfig) *exec.Cmd { + fmt.Println("Creating IBC channel...") + relayerHome := filepath.Join(rollappConfig.Home, consts.ConfigDirName.Relayer) + defaultRlyArgs := utils.GetRelayerDefaultFlags(relayerHome) + args := []string{"transact", "link", "-t300s", consts.DefaultRelayerPath} + args = append(args, defaultRlyArgs...) + return exec.Command(consts.Executables.Relayer, args...) +} diff --git a/cmd/root.go b/cmd/root.go index 1a246d6d..2857ed6a 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -6,6 +6,7 @@ import ( "github.com/dymensionxyz/roller/cmd/config" da_light_client "github.com/dymensionxyz/roller/cmd/da-light-client" "github.com/dymensionxyz/roller/cmd/register" + "github.com/dymensionxyz/roller/cmd/relayer" "github.com/dymensionxyz/roller/cmd/sequencer" "github.com/dymensionxyz/roller/cmd/version" "github.com/spf13/cobra" @@ -32,4 +33,5 @@ func init() { rootCmd.AddCommand(register.RegisterCmd()) rootCmd.AddCommand(da_light_client.DALightClientCmd()) rootCmd.AddCommand(sequencer.SequencerCmd()) + rootCmd.AddCommand(relayer.Cmd()) } diff --git a/cmd/run/run.go b/cmd/run/run.go new file mode 100644 index 00000000..1d787a8a --- /dev/null +++ b/cmd/run/run.go @@ -0,0 +1,89 @@ +package run + +import ( + "fmt" + "github.com/dymensionxyz/roller/cmd/consts" + "os/exec" + "path/filepath" + + "errors" + + "bytes" + + "strings" + + "github.com/dymensionxyz/roller/cmd/utils" + "github.com/spf13/cobra" +) + +const daLightClientEndpointFlag = "da-light-client-endpoint" + +func RunCmd() *cobra.Command { + runCmd := &cobra.Command{ + Use: "run", + Short: "Runs the rollapp sequencer.", + Run: func(cmd *cobra.Command, args []string) { + home := cmd.Flag(utils.FlagNames.Home).Value.String() + rollappConfig, err := utils.LoadConfigFromTOML(home) + utils.PrettifyErrorIfExists(err) + startRollappCmd := getStartRollapCmd(rollappConfig, cmd.Flag(daLightClientEndpointFlag).Value.String()) + var stderr bytes.Buffer + startRollappCmd.Stderr = &stderr + startRollappErr := startRollappCmd.Start() + if startRollappErr != nil { + errMsg := parseError(stderr.String()) + utils.PrettifyErrorIfExists(errors.New(errMsg)) + } + utils.PrettifyErrorIfExists(startRollappErr) + fmt.Println("💈 The Rollapp sequencer is running on your local machine!") + fmt.Println("💈 EVM RPC: http://0.0.0.0:8545") + fmt.Println("💈 Node RPC: http://0.0.0.0:26657") + fmt.Println("💈 Rest API: http://0.0.0.0:1317") + err = startRollappCmd.Wait() + if err != nil { + errMsg := parseError(stderr.String()) + utils.PrettifyErrorIfExists(errors.New(errMsg)) + } + }, + } + utils.AddGlobalFlags(runCmd) + addFlags(runCmd) + return runCmd +} + +func addFlags(cmd *cobra.Command) { + cmd.Flags().StringP(daLightClientEndpointFlag, "", "http://localhost:26659", "The DA light client endpoint.") +} +func parseError(errMsg string) string { + lines := strings.Split(errMsg, "\n") + if len(lines) > 0 && lines[0] == "Error: failed to initialize database: resource temporarily unavailable" { + return "The Rollapp sequencer is already running. Only one sequencer can run on the machine at any given time." + } + return errMsg +} + +func getStartRollapCmd(rollappConfig utils.RollappConfig, daEndpoint string) *exec.Cmd { + daConfig := fmt.Sprintf(`{"base_url": "%s", "timeout": 60000000000, "fee":20000, "gas_limit": 20000000, "namespace_id":[0,0,0,0,0,0,255,255]}`, daEndpoint) + rollappConfigDir := filepath.Join(rollappConfig.Home, consts.ConfigDirName.Rollapp) + settlementConfig := fmt.Sprintf(`{"node_address": "%s", "rollapp_id": "%s", "dym_account_name": "%s", "keyring_home_dir": "%s", "keyring_backend":"test", "gas_fees": "2000000udym"}`, rollappConfig.HubData.RPC_URL, rollappConfig.RollappID, + consts.KeyNames.HubSequencer, rollappConfigDir) + + return exec.Command( + rollappConfig.RollappBinary, "start", + "--dymint.aggregator", + "--json-rpc.enable", + "--json-rpc.api", "eth,txpool,personal,net,debug,web3,miner", + "--dymint.da_layer", "celestia", + "--dymint.da_config", daConfig, + "--dymint.settlement_layer", "dymension", + "--dymint.settlement_config", settlementConfig, + "--dymint.block_batch_size", "1200", + "--dymint.namespace_id", "000000000000ffff", + "--dymint.block_time", "0.2s", + "--home", rollappConfigDir, + "--log_level", "debug", + "--log-file", filepath.Join(rollappConfigDir, "rollapp.log"), + "--max-log-size", "2000", + "--module-log-level-override", "", + ) +} diff --git a/cmd/sequencer/start/start.go b/cmd/sequencer/start/start.go index b85a9bc2..55363ab2 100644 --- a/cmd/sequencer/start/start.go +++ b/cmd/sequencer/start/start.go @@ -7,7 +7,6 @@ import ( "strings" - initconfig "github.com/dymensionxyz/roller/cmd/config/init" "github.com/dymensionxyz/roller/cmd/consts" "github.com/dymensionxyz/roller/cmd/utils" "github.com/spf13/cobra" @@ -19,7 +18,7 @@ func StartCmd() *cobra.Command { Short: "Runs the rollapp sequencer.", Run: func(cmd *cobra.Command, args []string) { home := cmd.Flag(utils.FlagNames.Home).Value.String() - rollappConfig, err := initconfig.LoadConfigFromTOML(home) + rollappConfig, err := utils.LoadConfigFromTOML(home) utils.PrettifyErrorIfExists(err) LightNodeEndpoint := cmd.Flag(FlagNames.DAEndpoint).Value.String() startRollappCmd := getStartRollapCmd(rollappConfig, LightNodeEndpoint) @@ -52,7 +51,7 @@ func parseError(errMsg string) string { return errMsg } -func getStartRollapCmd(rollappConfig initconfig.InitConfig, lightNodeEndpoint string) *exec.Cmd { +func getStartRollapCmd(rollappConfig utils.RollappConfig, lightNodeEndpoint string) *exec.Cmd { daConfig := fmt.Sprintf(`{"base_url": "%s", "timeout": 60000000000, "fee":20000, "gas_limit": 20000000, "namespace_id":[0,0,0,0,0,0,255,255]}`, lightNodeEndpoint) rollappConfigDir := filepath.Join(rollappConfig.Home, consts.ConfigDirName.Rollapp) diff --git a/cmd/utils/bash_commands.go b/cmd/utils/bash_commands.go index 3d7f1880..4e4d45ca 100644 --- a/cmd/utils/bash_commands.go +++ b/cmd/utils/bash_commands.go @@ -3,6 +3,8 @@ package utils import ( "bytes" "errors" + "fmt" + "os" "os/exec" ) @@ -21,3 +23,27 @@ func RunBashCmdAsync(cmd *exec.Cmd, printOutput func(), parseError func(errMsg s PrettifyErrorIfExists(errors.New(errMsg)) } } + +func GetRelayerDefaultFlags(root string) []string { + return []string{ + "--src-port", "transfer", "--dst-port", "transfer", "--version", "ics20-1", "--home", root, + } +} + +func ExecBashCommand(cmd *exec.Cmd) (bytes.Buffer, error) { + var stderr bytes.Buffer + var stdout bytes.Buffer + cmd.Stderr = &stderr + cmd.Stdout = &stdout + err := cmd.Run() + if err != nil { + return stdout, fmt.Errorf("command execution failed: %w, stderr: %s", err, stderr.String()) + } + return stdout, nil +} + +func ExecBashCommandWithOSOutput(cmd *exec.Cmd) error { + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + return cmd.Run() +} diff --git a/cmd/config/init/persistence_config.go b/cmd/utils/config.go similarity index 54% rename from cmd/config/init/persistence_config.go rename to cmd/utils/config.go index 63083039..a19b2566 100644 --- a/cmd/config/init/persistence_config.go +++ b/cmd/utils/config.go @@ -1,13 +1,12 @@ -package initconfig +package utils import ( + "github.com/pelletier/go-toml" "io/ioutil" "path/filepath" - - "github.com/pelletier/go-toml" ) -func WriteConfigToTOML(InitConfig InitConfig) error { +func WriteConfigToTOML(InitConfig RollappConfig) error { tomlBytes, err := toml.Marshal(InitConfig) if err != nil { return err @@ -20,8 +19,8 @@ func WriteConfigToTOML(InitConfig InitConfig) error { return nil } -func LoadConfigFromTOML(root string) (InitConfig, error) { - var config InitConfig +func LoadConfigFromTOML(root string) (RollappConfig, error) { + var config RollappConfig tomlBytes, err := ioutil.ReadFile(filepath.Join(root, RollerConfigFileName)) if err != nil { return config, err @@ -33,3 +32,20 @@ func LoadConfigFromTOML(root string) (InitConfig, error) { return config, nil } + +type RollappConfig struct { + Home string + RollappID string + RollappBinary string + Denom string + Decimals uint64 + HubData HubData +} + +const RollerConfigFileName = "config.toml" + +type HubData = struct { + API_URL string + ID string + RPC_URL string +} diff --git a/cmd/utils/error_handling.go b/cmd/utils/error_handling.go index b84c305c..9bddc232 100644 --- a/cmd/utils/error_handling.go +++ b/cmd/utils/error_handling.go @@ -1,6 +1,7 @@ package utils import ( + "github.com/fatih/color" "os" ) diff --git a/cmd/utils/keys.go b/cmd/utils/keys.go index 596464f4..4943a4d2 100644 --- a/cmd/utils/keys.go +++ b/cmd/utils/keys.go @@ -3,7 +3,6 @@ package utils import ( "bytes" "encoding/json" - "errors" "os/exec" "github.com/cosmos/cosmos-sdk/crypto/keyring" @@ -16,29 +15,26 @@ type KeyInfo struct { Address string `json:"address"` } +func ParseAddressFromOutput(output bytes.Buffer) (string, error) { + var key = &KeyInfo{} + err := json.Unmarshal(output.Bytes(), key) + if err != nil { + return "", err + } + return key.Address, nil +} + func GetCelestiaAddress(keyringDir string) (string, error) { cmd := exec.Command( consts.Executables.CelKey, "show", consts.KeyNames.DALightNode, "--node.type", "light", "--keyring-dir", keyringDir, "--keyring-backend", "test", "--output", "json", ) - - var out bytes.Buffer - var stderr bytes.Buffer - cmd.Stdout = &out - cmd.Stderr = &stderr - - err := cmd.Run() - if err != nil { - return "", errors.New(stderr.String()) - } - - var key = &KeyInfo{} - err = json.Unmarshal(out.Bytes(), key) + output, err := ExecBashCommand(cmd) if err != nil { return "", err } - - return key.Address, nil + address, err := ParseAddressFromOutput(output) + return address, err } type KeyConfig struct { @@ -78,3 +74,15 @@ func GetAddress(keyConfig KeyConfig) (string, error) { } return formattedAddress, nil } + +func MergeMaps(map1, map2 map[string]string) map[string]string { + result := make(map[string]string) + for key, value := range map1 { + result[key] = value + } + for key, value := range map2 { + result[key] = value + } + + return result +} diff --git a/test/config/init/goldens/init_with_flags/relayer/config/config.yaml b/test/config/init/goldens/init_with_flags/relayer/config/config.yaml index d5717557..2118e654 100644 --- a/test/config/init/goldens/init_with_flags/relayer/config/config.yaml +++ b/test/config/init/goldens/init_with_flags/relayer/config/config.yaml @@ -13,7 +13,7 @@ chains: account-prefix: dym keyring-backend: test gas-adjustment: 1.2 - gas-prices: 0.25udym + gas-prices: 0.0udym debug: true timeout: 10s output-format: json @@ -25,7 +25,7 @@ chains: key: relayer-rollapp-key chain-id: mars_1_1 rpc-addr: http://localhost:26657 - account-prefix: rol + account-prefix: ethm keyring-backend: test gas-adjustment: 1.2 gas-prices: 0.0udym diff --git a/test/config/init/goldens/init_without_flags/relayer/config/config.yaml b/test/config/init/goldens/init_without_flags/relayer/config/config.yaml index d5717557..2118e654 100644 --- a/test/config/init/goldens/init_without_flags/relayer/config/config.yaml +++ b/test/config/init/goldens/init_without_flags/relayer/config/config.yaml @@ -13,7 +13,7 @@ chains: account-prefix: dym keyring-backend: test gas-adjustment: 1.2 - gas-prices: 0.25udym + gas-prices: 0.0udym debug: true timeout: 10s output-format: json @@ -25,7 +25,7 @@ chains: key: relayer-rollapp-key chain-id: mars_1_1 rpc-addr: http://localhost:26657 - account-prefix: rol + account-prefix: ethm keyring-backend: test gas-adjustment: 1.2 gas-prices: 0.0udym diff --git a/test/config/init/init_test.go b/test/config/init/init_test.go index 36e8dc62..9b2e3a49 100644 --- a/test/config/init/init_test.go +++ b/test/config/init/init_test.go @@ -54,7 +54,7 @@ func TestInitCmd(t *testing.T) { assert.NoError(initCmd.Execute()) initConfig := initconfig.GetInitConfig(initCmd, []string{rollappID, denom}) assert.NoError(testutils.VerifyRollerConfig(initConfig)) - assert.NoError(os.Remove(filepath.Join(tempDir, initconfig.RollerConfigFileName))) + assert.NoError(os.Remove(filepath.Join(tempDir, utils.RollerConfigFileName))) assert.NoError(testutils.VerifyRollappKeys(tempDir)) assert.NoError(testutils.VerifyRelayerKeys(tempDir, rollappID, initConfig.HubData.ID)) assert.NoError(testutils.VerifyLightNodeKeys(tempDir)) diff --git a/test/config/init/testutils/keys.go b/test/config/init/testutils/keys.go index 0f5db9c7..fab6431d 100644 --- a/test/config/init/testutils/keys.go +++ b/test/config/init/testutils/keys.go @@ -6,10 +6,10 @@ import ( "os" + "github.com/dymensionxyz/roller/cmd/consts" "path/filepath" "regexp" - "github.com/dymensionxyz/roller/cmd/consts" - + initconfig "github.com/dymensionxyz/roller/cmd/config/init" ) @@ -81,7 +81,7 @@ func verifyAndRemoveFilePattern(pattern string, dir string) error { } func getLightNodeKeysDir(root string) string { - return filepath.Join(root, consts.ConfigDirName.DALightNode, initconfig.KeysDirName) + return filepath.Join(root, consts.ConfigDirName.DALightNode, consts.KeysDirName) } func VerifyLightNodeKeys(root string) error { @@ -95,7 +95,7 @@ func VerifyLightNodeKeys(root string) error { } func getRelayerKeysDir(root string) string { - return filepath.Join(root, consts.ConfigDirName.Relayer, initconfig.KeysDirName) + return filepath.Join(root, consts.ConfigDirName.Relayer, consts.KeysDirName) } func VerifyRelayerKeys(root string, rollappID string, hubID string) error { diff --git a/test/config/init/testutils/rollapp.go b/test/config/init/testutils/rollapp.go index e7e01151..035db6b2 100644 --- a/test/config/init/testutils/rollapp.go +++ b/test/config/init/testutils/rollapp.go @@ -1,6 +1,7 @@ package testutils import ( + "github.com/dymensionxyz/roller/cmd/utils" "path/filepath" "errors" @@ -71,8 +72,8 @@ func SanitizeGenesis(genesisPath string) error { return nil } -func VerifyRollerConfig(rollappConfig initconfig.InitConfig) error { - existingConfig, err := initconfig.LoadConfigFromTOML(rollappConfig.Home) +func VerifyRollerConfig(rollappConfig utils.RollappConfig) error { + existingConfig, err := utils.LoadConfigFromTOML(rollappConfig.Home) if err != nil { return err }