From a9340a8065d8d5bf7fa35ca99ae930f3ff03f00c Mon Sep 17 00:00:00 2001 From: artpav <19916123+artemijspavlovs@users.noreply.github.com> Date: Mon, 28 Oct 2024 11:01:49 +0200 Subject: [PATCH] fix: improve relayer flow stability (#1091) --- cmd/consts/da.go | 7 +- cmd/consts/dymension.go | 6 + cmd/consts/types.go | 1 + cmd/relayer/setup/setup.go | 848 ++++++++------------------------- cmd/relayer/start/start.go | 35 +- cmd/rollapp/init/init.go | 4 +- cmd/rollapp/init/utils.go | 2 +- relayer/connections.go | 8 +- relayer/create_ibc_channel.go | 17 +- relayer/query.go | 117 ----- utils/config/propmts.go | 25 +- utils/dependencies/dymd.go | 16 +- utils/filesystem/filesystem.go | 17 + utils/keys/relayer.go | 90 +++- utils/relayer/config.go | 90 ++++ utils/relayer/connection.go | 81 ++++ utils/relayer/newibc.go | 85 ++++ utils/relayer/relayer.go | 236 ++++++++- utils/relayer/types.go | 45 ++ utils/rollapp/rollapp.go | 4 +- utils/roller/config.go | 13 +- utils/roller/roller.go | 37 +- 22 files changed, 881 insertions(+), 903 deletions(-) delete mode 100644 relayer/query.go create mode 100644 utils/relayer/config.go create mode 100644 utils/relayer/connection.go create mode 100644 utils/relayer/newibc.go create mode 100644 utils/relayer/types.go diff --git a/cmd/consts/da.go b/cmd/consts/da.go index 678a525c..95df5b99 100644 --- a/cmd/consts/da.go +++ b/cmd/consts/da.go @@ -27,12 +27,13 @@ const ( type DaNetwork string const ( + MockDA DaNetwork = "mock" CelestiaTestnet DaNetwork = "mocha-4" CelestiaMainnet DaNetwork = "celestia" ) var DaNetworks = map[string]DaData{ - "mock": { + string(MockDA): { Backend: Local, ApiUrl: "", ID: "mock", @@ -44,7 +45,7 @@ var DaNetworks = map[string]DaData{ }, GasPrice: "", }, - "mocha-4": { + string(CelestiaTestnet): { Backend: Celestia, ApiUrl: DefaultCelestiaRestApiEndpoint, ID: CelestiaTestnet, @@ -60,7 +61,7 @@ var DaNetworks = map[string]DaData{ }, GasPrice: "0.02", }, - "celestia": { + string(CelestiaMainnet): { Backend: Celestia, ApiUrl: "api-celestia.mzonder.com", ID: CelestiaMainnet, diff --git a/cmd/consts/dymension.go b/cmd/consts/dymension.go index 78d3c292..3eb1df1f 100644 --- a/cmd/consts/dymension.go +++ b/cmd/consts/dymension.go @@ -6,6 +6,7 @@ var MainnetHubData = HubData{ RPC_URL: "https://dymension-mainnet-tendermint.public.blastapi.io", ARCHIVE_RPC_URL: "https://dymension-mainnet-tendermint.public.blastapi.io", GAS_PRICE: "20000000000", + DA_NETWORK: string(CelestiaMainnet), } var TestnetHubData = HubData{ @@ -14,6 +15,7 @@ var TestnetHubData = HubData{ RPC_URL: "https://rpc-blumbus.mzonder.com", ARCHIVE_RPC_URL: "https://rpc-blumbus-archive.mzonder.com", GAS_PRICE: "20000000000", + DA_NETWORK: string(CelestiaTestnet), } var DevnetHubData = HubData{ @@ -22,6 +24,7 @@ var DevnetHubData = HubData{ RPC_URL: "http://52.58.111.62:36657", ARCHIVE_RPC_URL: "http://52.58.111.62:36657", GAS_PRICE: "100000000", + DA_NETWORK: string(CelestiaTestnet), } var LocalHubData = HubData{ @@ -30,6 +33,7 @@ var LocalHubData = HubData{ RPC_URL: "http://localhost:36657", ARCHIVE_RPC_URL: "http://localhost:36657", GAS_PRICE: "100000000", + DA_NETWORK: string(MockDA), } var MockHubData = HubData{ @@ -38,6 +42,7 @@ var MockHubData = HubData{ RPC_URL: "", ARCHIVE_RPC_URL: "", GAS_PRICE: "", + DA_NETWORK: string(MockDA), } var PlaygroundHubData = HubData{ @@ -46,6 +51,7 @@ var PlaygroundHubData = HubData{ RPC_URL: "https://rpc-dymension-playground-2.mzonder.com:443", ARCHIVE_RPC_URL: "https://rpc-dymension-playground-2.mzonder.com:443", GAS_PRICE: "2000000000", + DA_NETWORK: string(CelestiaTestnet), } // TODO(#112): The available hub networks should be read from YAML file diff --git a/cmd/consts/types.go b/cmd/consts/types.go index a104d9c4..9ea180d6 100644 --- a/cmd/consts/types.go +++ b/cmd/consts/types.go @@ -6,6 +6,7 @@ type HubData = struct { RPC_URL string `toml:"rpc_url"` ARCHIVE_RPC_URL string `toml:"archive_rpc_url"` GAS_PRICE string `toml:"gas_price"` + DA_NETWORK string `toml:"da_network"` } type RollappData = struct { diff --git a/cmd/relayer/setup/setup.go b/cmd/relayer/setup/setup.go index 968c0e06..2ce0dd03 100644 --- a/cmd/relayer/setup/setup.go +++ b/cmd/relayer/setup/setup.go @@ -1,12 +1,8 @@ package setup import ( - "errors" "fmt" - "io/fs" "os" - "path/filepath" - "strconv" "github.com/pterm/pterm" "github.com/spf13/cobra" @@ -15,18 +11,14 @@ import ( "github.com/dymensionxyz/roller/cmd/consts" "github.com/dymensionxyz/roller/relayer" "github.com/dymensionxyz/roller/sequencer" - "github.com/dymensionxyz/roller/utils/config" - "github.com/dymensionxyz/roller/utils/config/tomlconfig" "github.com/dymensionxyz/roller/utils/config/yamlconfig" dymintutils "github.com/dymensionxyz/roller/utils/dymint" "github.com/dymensionxyz/roller/utils/errorhandling" "github.com/dymensionxyz/roller/utils/filesystem" - genesisutils "github.com/dymensionxyz/roller/utils/genesis" - "github.com/dymensionxyz/roller/utils/keys" "github.com/dymensionxyz/roller/utils/logging" + relayerutils "github.com/dymensionxyz/roller/utils/relayer" "github.com/dymensionxyz/roller/utils/rollapp" rollapputils "github.com/dymensionxyz/roller/utils/rollapp" - "github.com/dymensionxyz/roller/utils/roller" sequencerutils "github.com/dymensionxyz/roller/utils/sequencer" ) @@ -45,58 +37,20 @@ func Cmd() *cobra.Command { home, _ := filesystem.ExpandHomePath( cmd.Flag(initconfig.GlobalFlagNames.Home).Value.String(), ) - relayerHome := filepath.Join(home, consts.ConfigDirName.Relayer) - // check for roller config, if it's present - fetch the rollapp ID from there - var raID string - var env string - var hd consts.HubData - var runForExisting bool - var rollerData roller.RollappConfig - var existingRollerConfig bool + relayerHome := relayerutils.GetHomeDir(home) + relayerConfigPath := relayerutils.GetConfigFilePath(relayerHome) - rollerConfigFilePath := filepath.Join(home, consts.RollerConfigFileName) - - // fetch rollapp metadata from chain - // retrieve rpc endpoint - _, err := os.Stat(rollerConfigFilePath) + raID, hd, err := relayerutils.GetRollappToRunFor(home) if err != nil { - if errors.Is(err, fs.ErrNotExist) { - pterm.Info.Println("existing roller configuration not found") - existingRollerConfig = false - runForExisting = false - } else { - pterm.Error.Println("failed to check existing roller config") - return - } - } else { - pterm.Info.Println("existing roller configuration found, retrieving RollApp ID from it") - rollerData, err = roller.LoadConfig(home) - if err != nil { - pterm.Error.Printf("failed to load rollapp config: %v\n", err) - return - } - rollerRaID := rollerData.RollappID - rollerHubData := rollerData.HubData - msg := fmt.Sprintf( - "the retrieved rollapp ID is: %s, would you like to initialize the relayer for this rollapp?", - rollerRaID, - ) - rlyFromRoller, _ := pterm.DefaultInteractiveConfirm.WithDefaultText(msg).Show() - if rlyFromRoller { - raID = rollerRaID - hd = rollerHubData - runForExisting = true - } - - if !rlyFromRoller { - runForExisting = false - } + pterm.Error.Println("failed to determine what RollApp to run for:", err) + return } - if !runForExisting { - raID, _ = pterm.DefaultInteractiveTextInput.WithDefaultText("Please enter the RollApp ID"). - Show() + _, err = rollapputils.ValidateChainID(hd.ID) + if err != nil { + pterm.Error.Printf("'%s' is not a valid Hub ID: %v", raID, err) + return } _, err = rollapputils.ValidateChainID(raID) @@ -105,676 +59,278 @@ func Cmd() *cobra.Command { return } - if !runForExisting { - envs := []string{"playground", "custom"} - env, _ = pterm.DefaultInteractiveSelect. - WithDefaultText( - "select the environment you want to initialize relayer for", - ). - WithOptions(envs). - Show() - - if env == "playground" { - hd = consts.Hubs[env] - } else { - hd = config.GenerateCustomHubData() - // err = dependencies.InstallCustomDymdVersion() - // if err != nil { - // pterm.Error.Println("failed to install custom dymd version: ", err) - // return - // } - } - - if !existingRollerConfig { - pterm.Info.Println("creating a new roller config") - err := os.MkdirAll(home, 0o755) - if err != nil { - pterm.Error.Printf( - "failed to create %s: %v", home, err, - ) - return - } - - _, err = os.Create(rollerConfigFilePath) - if err != nil { - pterm.Error.Printf( - "failed to create %s: %v", rollerConfigFilePath, err, - ) - return - } - } - - rollerTomlData := map[string]any{ - "rollapp_id": raID, - "home": home, - - "HubData.id": hd.ID, - "HubData.api_url": hd.API_URL, - "HubData.rpc_url": hd.RPC_URL, - "HubData.archive_rpc_url": hd.ARCHIVE_RPC_URL, - "HubData.gas_price": hd.GAS_PRICE, - } + ok, err := rollapp.IsRollappRegistered(raID, *hd) + if err != nil { + pterm.Error.Printf("'%s' is not a valid RollApp ID: %v", raID, err) + return + } - for key, value := range rollerTomlData { - err = tomlconfig.UpdateFieldInFile( - rollerConfigFilePath, - key, - value, - ) - if err != nil { - fmt.Printf("failed to add %s to roller.toml: %v", key, err) - return - } - } + if !ok { + pterm.Error.Printf("%s rollapp not registered on %s", raID, hd.ID) } - // retrieve rollapp rpc endpoints - raRpc, err := sequencerutils.GetRpcEndpointFromChain(raID, hd) + raRpc, err := sequencerutils.GetRpcEndpointFromChain(raID, *hd) if err != nil { + pterm.Error.Println("failed to retrieve rollapp rpc endpoint: ", err) return } - // check if there are active channels created for the rollapp - relayerLogFilePath := logging.GetRelayerLogPath(home) - relayerLogger := logging.GetLogger(relayerLogFilePath) - raData := consts.RollappData{ ID: raID, RpcUrl: fmt.Sprintf("%s:%d", raRpc, 443), } - - rly := relayer.NewRelayer( - home, - raData.ID, - hd.ID, - ) - rly.SetLogger(relayerLogger) - logFileOption := logging.WithLoggerLogging(relayerLogger) + relayerLogFilePath := logging.GetRelayerLogPath(home) + relayerLogger := logging.GetLogger(relayerLogFilePath) rollappChainData, err := rollapp.PopulateRollerConfigWithRaMetadataFromChain( home, raData.ID, - hd, + *hd, ) errorhandling.PrettifyErrorIfExists(err) - isRelayerInitialized, err := filesystem.DirNotEmpty(relayerHome) + err = rollappChainData.ValidateConfig() if err != nil { - pterm.Error.Printf("failed to check %s: %v\n", relayerHome, err) + pterm.Error.Println("rollapp data validation error: ", err) return } - var shouldOverwrite bool - if isRelayerInitialized { - pterm.Info.Println("relayer already initialized") - } else { - err = os.MkdirAll(relayerHome, 0o755) - if err != nil { - pterm.Error.Printf("failed to create %s: %v\n", relayerHome, err) - return - } - } - - // if shouldOverwrite { - // pterm.Info.Println("overriding the existing relayer configuration") - // err = os.RemoveAll(relayerHome) - // if err != nil { - // pterm.Error.Printf( - // "failed to recuresively remove %s: %v\n", - // relayerHome, - // err, - // ) - // return - // } - // - // err := filesystem.RemoveServiceFiles(consts.RelayerSystemdServices) - // if err != nil { - // pterm.Error.Printf("failed to remove relayer systemd services: %v\n", err) - // return - // } - // - // err = os.MkdirAll(relayerHome, 0o755) - // if err != nil { - // pterm.Error.Printf("failed to create %s: %v\n", relayerHome, err) - // return - // } - // } - - srcIbcChannel, dstIbcChannel, err := rly.LoadActiveChannel(raData, hd) + // things to check: + // 1. relayer folder exists + isRelayerDirPresent, err := filesystem.DirNotEmpty(relayerHome) if err != nil { - pterm.Error.Printf("failed to load active channel, %v", err) + pterm.Error.Printf("failed to check %s: %v\n", relayerHome, err) return } - if srcIbcChannel == "" || dstIbcChannel == "" { - defer func() { - pterm.Info.Println("reverting dymint config to 1h") - err := dymintutils.UpdateDymintConfigForIBC(home, "1h0m0s", true) - if err != nil { - pterm.Error.Println("failed to update dymint config: ", err) - return - } - }() - - if !runForExisting { - pterm.Error.Println( - "existing channels not found, initial IBC setup must be run on a sequencer node", - ) - return - } + var isRelayerIbcPathValid bool - if runForExisting && rollerData.NodeType != consts.NodeType.Sequencer { - pterm.Error.Println( - "existing channels not found, initial IBC setup must be run on a sequencer node", + if isRelayerDirPresent { + isRelayerIbcPathValid, err = relayerutils.ValidateIbcPathChains( + relayerHome, + raID, + *hd, + ) + if err != nil { + pterm.Error.Printf( + "validate relayer config IBC path %s: %v\n", + relayerHome, + err, ) return } - - // at this point it is safe to assume that - // relayer is being initialized on a sequencer node - // there is an existing roller config that can be used as the data source - - pterm.Info.Println("let's create that IBC connection, shall we?") - /* ---------------------------- Initialize relayer --------------------------- */ - as, err := genesisutils.GetGenesisAppState(home) + } else { + err = os.MkdirAll(relayerHome, 0o755) if err != nil { - pterm.Error.Printf("failed to get genesis app state: %v\n", err) + pterm.Error.Printf("failed to create %s: %v\n", relayerHome, err) return } - rollappDenom := as.Bank.Supply[0].Denom + } - err = tomlconfig.UpdateFieldInFile( - rollerConfigFilePath, - "base_denom", - rollappDenom, - ) + if !isRelayerIbcPathValid { + pterm.Warning.Println("relayer config verification failed...") + pterm.Info.Println("populating relayer config with correct values...") + err = relayerutils.InitializeRelayer(home, *rollappChainData) if err != nil { - pterm.Error.Println("failed to set base denom in roller.toml") + pterm.Error.Printf("failed to initialize relayer config: %v\n", err) return } - seq := sequencer.GetInstance(rollerData) - - dymintutils.WaitForHealthyRollApp("http://localhost:26657/health") - err = relayer.WaitForValidRollappHeight(seq) - if err != nil { - pterm.Error.Printf("rollapp did not reach valid height: %v\n", err) + if err := relayer.CreatePath(*rollappChainData); err != nil { + pterm.Error.Printf("failed to create relayer IBC path: %v\n", err) return } + } - if !isRelayerInitialized || shouldOverwrite { - // preflight checks - blockInformation, err := rollapputils.GetCurrentHeight() - if err != nil { - pterm.Error.Printf("failed to get current block height: %v\n", err) - return - } - currentHeight, err := strconv.Atoi( - blockInformation.Block.Header.Height, - ) - if err != nil { - pterm.Error.Printf("failed to get current block height: %v\n", err) - return - } - - if currentHeight <= 2 { - pterm.Warning.Println("current height is too low, updating dymint config") - err = dymintutils.UpdateDymintConfigForIBC(home, "5s", false) - if err != nil { - pterm.Error.Println("failed to update dymint config: ", err) - return - } - } - - 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: rollerData.RollappID, - RPC: consts.DefaultRollappRPC, - Denom: rollappDenom, - AddressPrefix: rollappPrefix, - GasPrices: "2000000000", - }, relayer.ChainConfig{ - ID: rollerData.HubData.ID, - RPC: rollerData.HubData.RPC_URL, - Denom: consts.Denoms.Hub, - AddressPrefix: consts.AddressPrefixes.Hub, - GasPrices: rollerData.HubData.GAS_PRICE, - }, home, - ) - if err != nil { - pterm.Error.Printf( - "failed to initialize relayer config: %v\n", - err, - ) - return - } - - relayerKeys, err := keys.GenerateRelayerKeys(rollerData) - if err != nil { - pterm.Error.Printf("failed to create relayer keys: %v\n", err) - return - } - - for _, key := range relayerKeys { - key.Print(keys.WithMnemonic(), keys.WithName()) - } - - keysToFund, err := keys.GetRelayerKeys(rollerData) - pterm.Info.Println( - "please fund the hub relayer key with at least 20 dym tokens: ", - ) - for _, k := range keysToFund { - k.Print(keys.WithName()) - } - proceed, _ := pterm.DefaultInteractiveConfirm.WithDefaultValue(false). - WithDefaultText( - "press 'y' when the wallets are funded", - ).Show() - if !proceed { - return - } - - if err != nil { - pterm.Error.Printf("failed to create relayer keys: %v\n", err) - return - } - - if err := relayer.CreatePath(rollerData); err != nil { - pterm.Error.Printf("failed to create relayer IBC path: %v\n", err) - return - } - - pterm.Info.Println("updating application relayer config") - relayerConfigPath := filepath.Join(relayerHome, "config", "config.yaml") - updates := map[string]interface{}{ - fmt.Sprintf("chains.%s.value.gas-adjustment", rollerData.HubData.ID): 1.5, - fmt.Sprintf("chains.%s.value.gas-adjustment", rollerData.RollappID): 1.3, - fmt.Sprintf("chains.%s.value.is-dym-hub", rollerData.HubData.ID): true, - fmt.Sprintf( - "chains.%s.value.http-addr", - rollerData.HubData.ID, - ): rollerData.HubData.API_URL, - fmt.Sprintf("chains.%s.value.is-dym-rollapp", rollerData.RollappID): true, - "extra-codecs": []string{ - "ethermint", - }, - } - err = yamlconfig.UpdateNestedYAML(relayerConfigPath, updates) - if err != nil { - pterm.Error.Printf("Error updating YAML: %v\n", err) - return - } - - err = dymintutils.UpdateDymintConfigForIBC(home, "5s", false) - if err != nil { - pterm.Error.Printf("Error updating YAML: %v\n", err) - return - } - } + if err := relayerutils.UpdateConfigWithDefaultValues(relayerHome, *rollappChainData); err != nil { + pterm.Error.Printf("failed to update relayer config file: %v\n", err) + return + } - if isRelayerInitialized && !shouldOverwrite { - pterm.Info.Println("ensuring relayer keys are present") - kc := keys.GetRelayerKeysConfig(rollerData) - - for k, v := range kc { - pterm.Info.Printf("checking %s\n", k) - - switch v.ID { - case consts.KeysIds.RollappRelayer: - chainId := rollerData.RollappID - isPresent, err := keys.IsRlyAddressWithNameInKeyring(v, chainId) - if err != nil { - pterm.Error.Printf("failed to check address: %v\n", err) - return - } - - if !isPresent { - key, err := keys.AddRlyKey(v, rollerData.RollappID) - if err != nil { - pterm.Error.Printf("failed to add key: %v\n", err) - } - - key.Print(keys.WithMnemonic(), keys.WithName()) - } - case consts.KeysIds.HubRelayer: - chainId := rollerData.HubData.ID - isPresent, err := keys.IsRlyAddressWithNameInKeyring(v, chainId) - if err != nil { - pterm.Error.Printf("failed to check address: %v\n", err) - return - } - if !isPresent { - key, err := keys.AddRlyKey(v, rollerData.HubData.ID) - if err != nil { - pterm.Error.Printf("failed to add key: %v\n", err) - } - - key.Print(keys.WithMnemonic(), keys.WithName()) - } - default: - pterm.Error.Println("invalid key name", err) - return - } - } - } + err = relayerutils.EnsureKeysArePresentAndFunded(*rollappChainData) + if err != nil { + pterm.Error.Println( + "failed to ensure relayer keys are created/funded:", + err, + ) + return + } - err = VerifyRelayerBalances(raData, hd) - if err != nil { - return - } + // 5. Are there existing channels ( from chain ) + rly := relayer.NewRelayer( + home, + raData.ID, + hd.ID, + ) + rly.SetLogger(relayerLogger) + logFileOption := logging.WithLoggerLogging(relayerLogger) - // errorhandling.RequireMigrateIfNeeded(rollappConfig) + srcIbcChannel, dstIbcChannel, err := rly.LoadActiveChannel(raData, *hd) + if err != nil { + pterm.Error.Printf("failed to load active channel, %v", err) + return + } - err = rollerData.ValidateConfig() + if srcIbcChannel != "" && dstIbcChannel != "" { + pterm.Info.Println("updating application relayer config") + + rollappIbcConnection, hubIbcConnection, err := rly.GetActiveConnections( + raData, + *hd, + ) if err != nil { - pterm.Error.Printf("failed to validate rollapp config: %v\n", err) + pterm.Error.Printf("failed to retrieve active connections: %v\n", err) return } - var createIbcChannels bool + updates := map[string]interface{}{ + // hub + fmt.Sprintf("paths.%s.src.client-id", consts.DefaultRelayerPath): hubIbcConnection.ClientID, + fmt.Sprintf("paths.%s.src.connection-id", consts.DefaultRelayerPath): hubIbcConnection.ID, - if rly.ChannelReady() && !shouldOverwrite { - pterm.DefaultSection.WithIndentCharacter("💈"). - Println("IBC transfer channel is already established!") - - status := fmt.Sprintf( - "Active\nrollapp: %s\n<->\nhub: %s", - rly.SrcChannel, - rly.DstChannel, - ) - err := rly.WriteRelayerStatus(status) - if err != nil { - fmt.Println(err) - return - } - - pterm.Info.Println(status) - return - } - - if !rly.ChannelReady() { - createIbcChannels, _ = pterm.DefaultInteractiveConfirm.WithDefaultText( - fmt.Sprintf( - "no channel found. would you like to create a new IBC channel for %s?", - rollerData.RollappID, - ), - ).Show() - - if !createIbcChannels { - pterm.Warning.Println("you can't run a relayer without an ibc channel") - return - } + // ra + fmt.Sprintf("paths.%s.dst.client-id", consts.DefaultRelayerPath): rollappIbcConnection.ClientID, + fmt.Sprintf("paths.%s.dst.connection-id", consts.DefaultRelayerPath): rollappIbcConnection.ID, } - - // TODO: look up relayer keys - if createIbcChannels || shouldOverwrite { - err = VerifyRelayerBalances(raData, hd) - if err != nil { - pterm.Error.Printf("failed to verify relayer balances: %v\n", err) - return - } - - pterm.Info.Println("establishing IBC transfer channel") - seq := sequencer.GetInstance(rollerData) - if seq == nil { - pterm.Error.Println("failed to get sequencer sequencer instance") - return - } - - channels, err := rly.CreateIBCChannel( - shouldOverwrite, - logFileOption, - raData, - hd, - ) - if err != nil { - pterm.Error.Printf("failed to create IBC channel: %v\n", err) - return - } - - srcIbcChannel = channels.Src - dstIbcChannel = channels.Dst + err = yamlconfig.UpdateNestedYAML(relayerConfigPath, updates) + if err != nil { + pterm.Error.Printf("Error updating YAML: %v\n", err) + return } - defer func() { - pterm.Info.Println("next steps:") - pterm.Info.Printf( - "run %s load the necessary systemd services\n", - pterm.DefaultBasicText.WithStyle(pterm.FgYellow.ToStyle()). - Sprintf("roller relayer services load"), - ) - }() - return - } - - if srcIbcChannel != "" && dstIbcChannel != "" { - if !isRelayerInitialized || shouldOverwrite { - raResponse, err := rollapp.Show(raID, hd) - if err != nil { - pterm.Error.Println("failed to retrieve rollapp information: ", err) - return - } - - raRpc, err := sequencerutils.GetRpcEndpointFromChain(raID, hd) - if err != nil { - pterm.Error.Println("failed to retrieve rollapp rpc endpoint: ", err) - return - } - - pterm.Info.Println("initializing relayer config") - err = initconfig.InitializeRelayerConfig( - relayer.ChainConfig{ - ID: raResponse.Rollapp.RollappId, - RPC: raRpc, - Denom: raResponse.Rollapp.GenesisInfo.NativeDenom.Base, - AddressPrefix: raResponse.Rollapp.GenesisInfo.Bech32Prefix, - GasPrices: "2000000000", - }, relayer.ChainConfig{ - ID: hd.ID, - RPC: hd.RPC_URL, - Denom: consts.Denoms.Hub, - AddressPrefix: consts.AddressPrefixes.Hub, - GasPrices: hd.GAS_PRICE, - }, home, - ) - if err != nil { - pterm.Error.Printf( - "failed to initialize relayer config: %v\n", - err, - ) - return - } - - relayerKeys, err := keys.GenerateRelayerKeys(rollerData) - if err != nil { - pterm.Error.Printf("failed to create relayer keys: %v\n", err) - return - } - - for _, key := range relayerKeys { - key.Print(keys.WithMnemonic(), keys.WithName()) - } - - keysToFund, err := keys.GetRelayerKeys(rollerData) - pterm.Info.Println( - "please fund the hub relayer key with at least 20 dym tokens: ", - ) - for _, k := range keysToFund { - k.Print(keys.WithName()) - } - proceed, _ := pterm.DefaultInteractiveConfirm.WithDefaultValue(false). - WithDefaultText( - "press 'y' when the wallets are funded", - ).Show() - if !proceed { - return - } - - if err != nil { - pterm.Error.Printf("failed to create relayer keys: %v\n", err) - return - } - - if err := relayer.CreatePath(rollerData); err != nil { - pterm.Error.Printf("failed to create relayer IBC path: %v\n", err) - return - } - - pterm.Info.Println("updating application relayer config") - relayerConfigPath := filepath.Join(relayerHome, "config", "config.yaml") - - rollappIbcConnection, hubIbcConnection, err := rly.GetActiveConnections( - raData, - hd, - ) - if err != nil { - pterm.Error.Printf("failed to retrieve active connections: %v\n", err) - return - } - - updates := map[string]interface{}{ - // hub - fmt.Sprintf("chains.%s.value.gas-adjustment", rollerData.HubData.ID): 1.5, - fmt.Sprintf("chains.%s.value.is-dym-hub", rollerData.HubData.ID): true, - fmt.Sprintf( - "chains.%s.value.http-addr", - rollerData.HubData.ID, - ): rollerData.HubData.API_URL, - fmt.Sprintf("paths.%s.src.client-id", consts.DefaultRelayerPath): hubIbcConnection.ClientID, - fmt.Sprintf("paths.%s.src.connection-id", consts.DefaultRelayerPath): hubIbcConnection.ID, - - // ra - fmt.Sprintf("chains.%s.value.gas-adjustment", raResponse.Rollapp.RollappId): 1.3, - fmt.Sprintf("chains.%s.value.is-dym-rollapp", raResponse.Rollapp.RollappId): true, - fmt.Sprintf( - "paths.%s.dst.client-id", - consts.DefaultRelayerPath, - ): rollappIbcConnection.ClientID, - fmt.Sprintf("paths.%s.dst.connection-id", consts.DefaultRelayerPath): rollappIbcConnection.ID, - - // misc - "extra-codecs": []string{ - "ethermint", - }, - } - err = yamlconfig.UpdateNestedYAML(relayerConfigPath, updates) - if err != nil { - pterm.Error.Printf("Error updating YAML: %v\n", err) - return - } - } pterm.Info.Println("existing IBC channels found ") pterm.Info.Println("Hub: ", srcIbcChannel) pterm.Info.Println("RollApp: ", dstIbcChannel) return } - // TODO: remove code duplication - _, err = os.Stat(relayerHome) - if err != nil { + defer func() { + pterm.Info.Println("reverting dymint config to 1h") + err := dymintutils.UpdateDymintConfigForIBC(home, "1h0m0s", true) if err != nil { - pterm.Error.Printf("failed to create %s: %v\n", relayerHome, err) + pterm.Error.Println("failed to update dymint config: ", err) return } - } + }() - pterm.Info.Println("initializing relayer config") - err = initconfig.InitializeRelayerConfig( - relayer.ChainConfig{ - ID: raData.ID, - RPC: raData.RpcUrl, - Denom: rollappChainData.Denom, - AddressPrefix: rollappChainData.Bech32Prefix, - GasPrices: "2000000000", - }, relayer.ChainConfig{ - ID: rollappChainData.HubData.ID, - RPC: rollappChainData.HubData.RPC_URL, - Denom: consts.Denoms.Hub, - AddressPrefix: consts.AddressPrefixes.Hub, - GasPrices: rollappChainData.HubData.GAS_PRICE, - }, home, + canCreateIbcConnectionOnCurrentNode, err := relayerutils.NewIbcConnenctionCanBeCreatedOnCurrentNode( + home, + raID, ) if err != nil { - pterm.Error.Printf( - "failed to initialize relayer config: %v\n", + pterm.Error.Println( + "failed to determine whether connection can be created from this node:", err, ) return } - rlyKeys, err := keys.GenerateRelayerKeys(*rollappChainData) - if err != nil { - pterm.Error.Printf("failed to create relayer keys: %v\n", err) + if !canCreateIbcConnectionOnCurrentNode { + pterm.Error.Println(err) return } - for _, key := range rlyKeys { - key.Print(keys.WithMnemonic(), keys.WithName()) - } - keysToFund, err := keys.GetRelayerKeys(*rollappChainData) + err = relayerutils.InitializeRelayer(home, *rollappChainData) if err != nil { - pterm.Error.Println("failed to retrieve relayer keys: ", err) + pterm.Error.Println("failed to initialize relayer:", err) return } - pterm.Info.Println( - "please fund the hub relayer key with at least 20 dym tokens: ", - ) - for _, k := range keysToFund { - k.Print(keys.WithName()) - } - proceed, _ := pterm.DefaultInteractiveConfirm.WithDefaultValue(false). - WithDefaultText( - "press 'y' when the wallets are funded", - ).Show() - if !proceed { + + pterm.Info.Println("let's create that IBC connection, shall we?") + seq := sequencer.GetInstance(*rollappChainData) + + dymintutils.WaitForHealthyRollApp("http://localhost:26657/health") + err = relayer.WaitForValidRollappHeight(seq) + if err != nil { + pterm.Error.Printf("rollapp did not reach valid height: %v\n", err) return } - if err := relayer.CreatePath(*rollappChainData); err != nil { - pterm.Error.Printf("failed to create relayer IBC path: %v\n", err) + pterm.Info.Println("setting block time to 5s for esstablishing IBC connection") + err = dymintutils.UpdateDymintConfigForIBC(home, "5s", true) + if err != nil { + pterm.Error.Println("failed to update dymint config: ", err) return } - rollappIbcConnection, hubIbcConnection, err := rly.GetActiveConnections(raData, hd) - if err != nil { - pterm.Error.Printf("failed to retrieve active connections: %v\n", err) + if rly.ChannelReady() { + pterm.DefaultSection.WithIndentCharacter("💈"). + Println("IBC transfer channel is already established!") + + status := fmt.Sprintf( + "Active\nrollapp: %s\n<->\nhub: %s", + rly.SrcChannel, + rly.DstChannel, + ) + err := rly.WriteRelayerStatus(status) + if err != nil { + fmt.Println(err) + return + } + + pterm.Info.Println(status) return } - pterm.Info.Println("updating application relayer config") - relayerConfigPath := filepath.Join(relayerHome, "config", "config.yaml") - updates := map[string]interface{}{ - fmt.Sprintf("chains.%s.value.gas-adjustment", rollappChainData.HubData.ID): 1.5, - fmt.Sprintf("chains.%s.value.gas-adjustment", rollappChainData.RollappID): 1.3, - fmt.Sprintf("chains.%s.value.is-dym-hub", rollappChainData.HubData.ID): true, - fmt.Sprintf( - "chains.%s.value.http-addr", - rollappChainData.HubData.ID, - ): rollappChainData.HubData.API_URL, - fmt.Sprintf("chains.%s.value.is-dym-rollapp", rollappChainData.RollappID): true, - "extra-codecs": []string{ - "ethermint", - }, - fmt.Sprintf("paths.%s.dst.client-id", consts.DefaultRelayerPath): rollappIbcConnection.ClientID, - fmt.Sprintf("paths.%s.dst.connection-id", consts.DefaultRelayerPath): rollappIbcConnection.ID, - fmt.Sprintf("paths.%s.src.client-id", consts.DefaultRelayerPath): hubIbcConnection.ClientID, - fmt.Sprintf("paths.%s.src.connection-id", consts.DefaultRelayerPath): hubIbcConnection.ID, + var createIbcChannels bool + if !rly.ChannelReady() { + createIbcChannels, _ = pterm.DefaultInteractiveConfirm.WithDefaultText( + fmt.Sprintf( + "no channel found. would you like to create a new IBC channel for %s?", + pterm.DefaultBasicText.WithStyle(pterm.FgYellow.ToStyle()). + Sprint(rollappChainData.RollappID), + ), + ).Show() + + if !createIbcChannels { + pterm.Warning.Println("you can't run a relayer without an ibc channel") + return + } } - err = yamlconfig.UpdateNestedYAML(relayerConfigPath, updates) - if err != nil { - pterm.Error.Printf("Error updating YAML: %v\n", err) - return + + if createIbcChannels { + err = relayerutils.VerifyRelayerBalances(*hd) + if err != nil { + pterm.Error.Printf("failed to verify relayer balances: %v\n", err) + return + } + + pterm.Info.Println("establishing IBC transfer channel") + channels, err := rly.CreateIBCChannel( + logFileOption, + raData, + *hd, + ) + if err != nil { + pterm.Error.Printf("failed to create IBC channel: %v\n", err) + return + } + + srcIbcChannel = channels.Src + dstIbcChannel = channels.Dst + + status := fmt.Sprintf( + "Active\nrollapp: %s\n<->\nhub: %s", + srcIbcChannel, + dstIbcChannel, + ) + + pterm.Info.Println(status) + err = rly.WriteRelayerStatus(status) + if err != nil { + fmt.Println(err) + return + } } - fmt.Println("hub channel: ", srcIbcChannel) - fmt.Println("ra channel: ", dstIbcChannel) + defer func() { + pterm.Info.Println("next steps:") + pterm.Info.Printf( + "run %s load the necessary systemd services\n", + pterm.DefaultBasicText.WithStyle(pterm.FgYellow.ToStyle()). + Sprintf("roller relayer services load"), + ) + }() }, } @@ -782,19 +338,3 @@ func Cmd() *cobra.Command { BoolP(flagOverride, "", false, "override the existing relayer clients and channels") return relayerStartCmd } - -func VerifyRelayerBalances(raData consts.RollappData, hd consts.HubData) error { - insufficientBalances, err := relayer.GetRelayerInsufficientBalances(raData, hd) - if err != nil { - return err - } - - if len(insufficientBalances) != 0 { - err = keys.PrintInsufficientBalancesIfAny(insufficientBalances) - if err != nil { - return err - } - } - - return nil -} diff --git a/cmd/relayer/start/start.go b/cmd/relayer/start/start.go index 6711f8fa..c7f96a1b 100644 --- a/cmd/relayer/start/start.go +++ b/cmd/relayer/start/start.go @@ -16,8 +16,8 @@ import ( "github.com/dymensionxyz/roller/utils/bash" "github.com/dymensionxyz/roller/utils/config" "github.com/dymensionxyz/roller/utils/errorhandling" - "github.com/dymensionxyz/roller/utils/keys" "github.com/dymensionxyz/roller/utils/logging" + relayerutils "github.com/dymensionxyz/roller/utils/relayer" "github.com/dymensionxyz/roller/utils/rollapp" "github.com/dymensionxyz/roller/utils/roller" sequencerutils "github.com/dymensionxyz/roller/utils/sequencer" @@ -29,19 +29,6 @@ const ( flagOverride = "override" ) -type Config struct { - Paths struct { - HubRollapp struct { - Dst struct { - ChainID string `yaml:"chain-id"` - } `yaml:"dst"` - Src struct { - ChainID string `yaml:"chain-id"` - } `yaml:"src"` - } `yaml:"hub-rollapp"` - } `yaml:"paths"` -} - func Cmd() *cobra.Command { relayerStartCmd := &cobra.Command{ Use: "start", @@ -65,7 +52,7 @@ Consider using 'services' if you want to run a 'systemd' service instead. return } - var rlyConfig Config + var rlyConfig relayerutils.Config err = yaml.Unmarshal(data, &rlyConfig) if err != nil { fmt.Printf("Error unmarshaling YAML: %v\n", err) @@ -111,7 +98,7 @@ Consider using 'services' if you want to run a 'systemd' service instead. Denom: raResponse.Rollapp.GenesisInfo.NativeDenom.Base, } - err = VerifyRelayerBalances(raData, hd) + err = relayerutils.VerifyRelayerBalances(hd) if err != nil { pterm.Error.Println("failed to check balances", err) return @@ -176,19 +163,3 @@ Consider using 'services' if you want to run a 'systemd' service instead. BoolP(flagOverride, "", false, "override the existing relayer clients and channels") return relayerStartCmd } - -func VerifyRelayerBalances(raData consts.RollappData, hd consts.HubData) error { - insufficientBalances, err := relayer.GetRelayerInsufficientBalances(raData, hd) - if err != nil { - return err - } - - if len(insufficientBalances) != 0 { - err = keys.PrintInsufficientBalancesIfAny(insufficientBalances) - if err != nil { - return err - } - } - - return nil -} diff --git a/cmd/rollapp/init/init.go b/cmd/rollapp/init/init.go index efdd45f5..b7fbdb33 100644 --- a/cmd/rollapp/init/init.go +++ b/cmd/rollapp/init/init.go @@ -53,7 +53,7 @@ func Cmd() *cobra.Command { pterm.Error.Println("failed to create roller home directory: ", err) return } - isFirstInitialization, err := roller.CreateConfigFile(home) + isFirstInitialization, err := roller.CreateConfigFileIfNotPresent(home) if err != nil { pterm.Error.Println("failed to initialize rollapp: ", err) return @@ -157,7 +157,7 @@ func Cmd() *cobra.Command { // default flow isRollappRegistered, _ := rollapp.IsRollappRegistered(raID, hd) if !isRollappRegistered { - pterm.Error.Printf("%s was not found as a registered rollapp: %v", raID, err) + pterm.Error.Printf("%s was not found as a registered rollapp: %v\n", raID, err) return } diff --git a/cmd/rollapp/init/utils.go b/cmd/rollapp/init/utils.go index 13a0b0be..6ef58680 100644 --- a/cmd/rollapp/init/utils.go +++ b/cmd/rollapp/init/utils.go @@ -110,7 +110,7 @@ func runInit( return err } - err = roller.PopulateConfig(home, raID, hd, *daData, initConfig) + err = roller.PopulateConfig(home, raID, hd, *daData, string(initConfig.RollappVMType)) if err != nil { return err } diff --git a/relayer/connections.go b/relayer/connections.go index e0b3e191..4edc8a25 100644 --- a/relayer/connections.go +++ b/relayer/connections.go @@ -69,11 +69,9 @@ func (r *Relayer) GetActiveConnectionIDs( raData consts.RollappData, hd consts.HubData, ) (string, string, error) { - rollappConnectionOutput, err := bash.ExecCommandWithStdout( - r.queryConnectionRollappCmd( - raData, - ), - ) + cmd := r.queryConnectionRollappCmd(raData) + + rollappConnectionOutput, err := bash.ExecCommandWithStdout(cmd) if err != nil { r.logger.Printf( "failed to find connection on the rollapp side for %s: %v", diff --git a/relayer/create_ibc_channel.go b/relayer/create_ibc_channel.go index 03dd0f7e..11178330 100644 --- a/relayer/create_ibc_channel.go +++ b/relayer/create_ibc_channel.go @@ -18,7 +18,6 @@ import ( // CreateIBCChannel Creates an IBC channel between the hub and the client, // and return the source channel ID. func (r *Relayer) CreateIBCChannel( - override bool, logFileOption bash.CommandOption, raData consts.RollappData, hd consts.HubData, @@ -37,20 +36,18 @@ func (r *Relayer) CreateIBCChannel( return ConnectionChannels{}, err } - if connectionID == "" || override { + if connectionID == "" { pterm.Info.Println("💈 Creating connection...") if err := r.WriteRelayerStatus(status); err != nil { return ConnectionChannels{}, err } - createConnectionCmd := r.getCreateConnectionCmd(override) + createConnectionCmd := r.getCreateConnectionCmd() if err := bash.ExecCmd(createConnectionCmd, logFileOption); err != nil { return ConnectionChannels{}, err } } - var src, dst string - // Sleep for a few seconds to make sure the connection is created time.Sleep(15 * time.Second) // we ran create channel with override, as it not recovarable anyway @@ -85,9 +82,10 @@ func (r *Relayer) CreateIBCChannel( if err := r.WriteRelayerStatus(status); err != nil { return ConnectionChannels{}, err } + return ConnectionChannels{ - Src: src, - Dst: dst, + Src: r.SrcChannel, + Dst: r.DstChannel, }, nil } @@ -136,11 +134,8 @@ func (r *Relayer) getCreateClientsCmd(override bool) *exec.Cmd { return cmd } -func (r *Relayer) getCreateConnectionCmd(override bool) *exec.Cmd { +func (r *Relayer) getCreateConnectionCmd() *exec.Cmd { args := []string{"tx", "connection", "--max-clock-drift", "70m"} - if override { - args = append(args, "--override") - } args = append(args, r.getRelayerDefaultArgs()...) return exec.Command(consts.Executables.Relayer, args...) } diff --git a/relayer/query.go b/relayer/query.go deleted file mode 100644 index 79770a35..00000000 --- a/relayer/query.go +++ /dev/null @@ -1,117 +0,0 @@ -package relayer - -import ( - cosmossdkmath "cosmossdk.io/math" - - "github.com/dymensionxyz/roller/cmd/consts" - "github.com/dymensionxyz/roller/sequencer" - "github.com/dymensionxyz/roller/utils/keys" - "github.com/dymensionxyz/roller/utils/roller" -) - -var oneDayRelayPrice, _ = cosmossdkmath.NewIntFromString( - "2000000000000000000", -) // 2000000000000000000 = 2dym - -// TODO: refactor to use consts.RollappData -// nolint: unused -func getRolRlyAccData(home string, raData roller.RollappConfig) (*keys.AccountData, error) { - RollappRlyAddr, err := keys.GetRelayerAddress(home, raData.RollappID) - seq := sequencer.GetInstance(raData) - if err != nil { - return nil, err - } - - RollappRlyBalance, err := keys.QueryBalance( - keys.ChainQueryConfig{ - RPC: seq.GetRPCEndpoint(), - Denom: raData.Denom, - Binary: consts.Executables.RollappEVM, - }, RollappRlyAddr, - ) - if err != nil { - return nil, err - } - - return &keys.AccountData{ - Address: RollappRlyAddr, - Balance: RollappRlyBalance, - }, nil -} - -func getHubRlyAccData(home string, hd consts.HubData) (*keys.AccountData, error) { - HubRlyAddr, err := keys.GetRelayerAddress(home, hd.ID) - if err != nil { - return nil, err - } - - HubRlyBalance, err := keys.QueryBalance( - keys.ChainQueryConfig{ - RPC: hd.RPC_URL, - Denom: consts.Denoms.Hub, - Binary: consts.Executables.Dymension, - }, HubRlyAddr, - ) - if err != nil { - return nil, err - } - - return &keys.AccountData{ - Address: HubRlyAddr, - Balance: HubRlyBalance, - }, nil -} - -func GetRelayerAccountsData( - home string, - raData consts.RollappData, - hd consts.HubData, -) ([]keys.AccountData, error) { - var data []keys.AccountData - - // rollappRlyAcc, err := getRolRlyAccData(cfg) - // if err != nil { - // return nil, err - // } - // data = append(data, *rollappRlyAcc) - - hubRlyAcc, err := getHubRlyAccData(home, hd) - if err != nil { - return nil, err - } - - data = append(data, *hubRlyAcc) - return data, nil -} - -func GetRelayerInsufficientBalances( - raData consts.RollappData, - hd consts.HubData, -) ([]keys.NotFundedAddressData, error) { - var insufficientBalances []keys.NotFundedAddressData - home := roller.GetRootDir() - - accData, err := GetRelayerAccountsData(home, raData, hd) - if err != nil { - return nil, err - } - - // consts.Denoms.Hub is used here because as of @202409 we no longer require rollapp - // relayer account funding to establish IBC connection. - for _, acc := range accData { - if acc.Balance.Amount.Cmp(oneDayRelayPrice.BigInt()) < 0 { - insufficientBalances = append( - insufficientBalances, keys.NotFundedAddressData{ - KeyName: consts.KeysIds.HubRelayer, - Address: acc.Address, - CurrentBalance: acc.Balance.Amount, - RequiredBalance: oneDayRelayPrice.BigInt(), - Denom: consts.Denoms.Hub, - Network: hd.ID, - }, - ) - } - } - - return insufficientBalances, nil -} diff --git a/utils/config/propmts.go b/utils/config/propmts.go index 3f7108c1..c1f67014 100644 --- a/utils/config/propmts.go +++ b/utils/config/propmts.go @@ -1,6 +1,10 @@ package config -import "github.com/pterm/pterm" +import ( + "strings" + + "github.com/pterm/pterm" +) func PromptVmType() string { vmtypes := []string{"evm", "wasm"} @@ -11,3 +15,22 @@ func PromptVmType() string { return vmtype } + +func PromptRaID() string { + raID, _ := pterm.DefaultInteractiveTextInput.WithDefaultText("Please enter the RollApp ID"). + Show() + + return strings.TrimSpace(raID) +} + +func PromptEnvironment() string { + envs := []string{"playground", "custom"} + env, _ := pterm.DefaultInteractiveSelect. + WithDefaultText( + "select the environment you want to initialize relayer for", + ). + WithOptions(envs). + Show() + + return strings.TrimSpace(env) +} diff --git a/utils/dependencies/dymd.go b/utils/dependencies/dymd.go index f87d052b..19df176b 100644 --- a/utils/dependencies/dymd.go +++ b/utils/dependencies/dymd.go @@ -4,9 +4,10 @@ import ( "os/exec" "strings" + "github.com/pterm/pterm" + "github.com/dymensionxyz/roller/cmd/consts" "github.com/dymensionxyz/roller/utils/dependencies/types" - "github.com/pterm/pterm" ) func CustomDymdDependency() types.Dependency { @@ -35,13 +36,24 @@ func CustomDymdDependency() types.Dependency { } } +func InstallCustomDymdVersion() error { + dep := CustomDymdDependency() + + err := InstallBinaryFromRepo(dep, dep.DependencyName) + if err != nil { + return err + } + + return nil +} + func DefaultDymdDependency() types.Dependency { return types.Dependency{ DependencyName: "dymension", RepositoryOwner: "dymensionxyz", RepositoryName: "dymension", RepositoryUrl: "https://github.com/artemijspavlovs/dymension", - Release: "v3.1.0-pg07", + Release: "v3.1.0-pg10", Binaries: []types.BinaryPathPair{ { Binary: "dymd", diff --git a/utils/filesystem/filesystem.go b/utils/filesystem/filesystem.go index b11da267..e70a984f 100644 --- a/utils/filesystem/filesystem.go +++ b/utils/filesystem/filesystem.go @@ -1,8 +1,10 @@ package filesystem import ( + "errors" "fmt" "io" + "io/fs" "net/http" "os" "os/exec" @@ -201,3 +203,18 @@ func TailFile(fp, svcName string, lineNumber int) error { return nil } + +func DoesFileExist(path string) (bool, error) { + _, err := os.Stat(path) + + if errors.Is(err, fs.ErrNotExist) { + pterm.Info.Println("existing roller configuration not found") + return false, nil + } + + if err != nil { + return false, err + } + + return true, nil +} diff --git a/utils/keys/relayer.go b/utils/keys/relayer.go index 74ffb9f8..5dc8e7c8 100644 --- a/utils/keys/relayer.go +++ b/utils/keys/relayer.go @@ -50,8 +50,14 @@ func IsRlyAddressWithNameInKeyring( if err != nil { return false, err } + + fmt.Println("out", out.String()) lookFor := fmt.Sprintf("no keys found for chain %s", chainId) + if out.String() == "" { + return false, nil + } + return !strings.Contains(out.String(), lookFor), nil } @@ -78,7 +84,7 @@ func GetRelayerKeysConfig(rollappConfig roller.RollappConfig) map[string]KeyConf } } -func GetRelayerKeys(rollappConfig roller.RollappConfig) ([]KeyInfo, error) { +func GetRelayerKeysToFund(rollappConfig roller.RollappConfig) error { relayerAddresses := make([]KeyInfo, 0) relayerKeys := GetRelayerKeysConfig(rollappConfig) @@ -87,14 +93,21 @@ func GetRelayerKeys(rollappConfig roller.RollappConfig) ([]KeyInfo, error) { rollappConfig.HubData.ID, ) if err != nil { - return nil, err + return err } relayerAddresses = append( relayerAddresses, *relayerHubAddress, ) - return relayerAddresses, nil + pterm.Info.Println( + "please fund the hub relayer key with at least 20 dym tokens: ", + ) + for _, k := range relayerAddresses { + k.Print(WithName()) + } + + return nil } func AddRlyKey(kc KeyConfig, chainID string) (*KeyInfo, error) { @@ -117,34 +130,59 @@ func AddRlyKey(kc KeyConfig, chainID string) (*KeyInfo, error) { return ki, nil } -func GenerateRelayerKeys(rollappConfig roller.RollappConfig) ([]KeyInfo, error) { +func GenerateRelayerKeys(rollerData roller.RollappConfig) error { pterm.Info.Println("creating relayer keys") - var relayerAddresses []KeyInfo - keys := GetRelayerKeysConfig(rollappConfig) - - pterm.Info.Println("creating relayer rollapp key") - relayerRollappAddress, err := AddRlyKey( - keys[consts.KeysIds.RollappRelayer], - rollappConfig.RollappID, - ) - if err != nil { - return nil, err + var createdRlyKeys []KeyInfo + keys := GetRelayerKeysConfig(rollerData) + + for k, v := range keys { + pterm.Info.Printf("checking %s in %s\n", k, v.Dir) + + switch v.ID { + case consts.KeysIds.RollappRelayer: + chainId := rollerData.RollappID + isPresent, err := IsRlyAddressWithNameInKeyring(v, chainId) + if err != nil { + pterm.Error.Printf("failed to check address: %v\n", err) + return err + } + + if !isPresent { + pterm.Info.Printf("creating %s in %s\n", k, v.Dir) + key, err := AddRlyKey(v, rollerData.RollappID) + if err != nil { + pterm.Error.Printf("failed to add key: %v\n", err) + } + createdRlyKeys = append(createdRlyKeys, *key) + } + case consts.KeysIds.HubRelayer: + chainId := rollerData.HubData.ID + isPresent, err := IsRlyAddressWithNameInKeyring(v, chainId) + if err != nil { + pterm.Error.Printf("failed to check address: %v\n", err) + return err + } + + if !isPresent { + pterm.Info.Printf("creating %s in %s\n", k, v.Dir) + key, err := AddRlyKey(v, rollerData.HubData.ID) + if err != nil { + pterm.Error.Printf("failed to add key: %v\n", err) + } + createdRlyKeys = append(createdRlyKeys, *key) + } + default: + return fmt.Errorf("invalid key name: %s", v.ID) + } } - relayerAddresses = append( - relayerAddresses, *relayerRollappAddress, - ) - - pterm.Info.Println("creating relayer hub key") - relayerHubAddress, err := AddRlyKey(keys[consts.KeysIds.HubRelayer], rollappConfig.HubData.ID) - if err != nil { - return nil, err + if len(createdRlyKeys) != 0 { + for _, key := range createdRlyKeys { + key.Print(WithMnemonic(), WithName()) + } } - relayerAddresses = append( - relayerAddresses, *relayerHubAddress, - ) - return relayerAddresses, nil + return nil } func getAddRlyKeyCmd(keyConfig KeyConfig, chainID string) *exec.Cmd { diff --git a/utils/relayer/config.go b/utils/relayer/config.go new file mode 100644 index 00000000..1a91abe7 --- /dev/null +++ b/utils/relayer/config.go @@ -0,0 +1,90 @@ +package relayer + +import ( + "fmt" + "path/filepath" + + "github.com/pterm/pterm" + + "github.com/dymensionxyz/roller/cmd/consts" + "github.com/dymensionxyz/roller/utils/config/yamlconfig" + "github.com/dymensionxyz/roller/utils/filesystem" + "github.com/dymensionxyz/roller/utils/roller" +) + +func UpdateConfigWithDefaultValues(relayerHome string, rollerData roller.RollappConfig) error { + pterm.Info.Println("updating application relayer config") + relayerConfigPath := filepath.Join(relayerHome, "config", "config.yaml") + updates := map[string]interface{}{ + fmt.Sprintf("chains.%s.value.gas-adjustment", rollerData.HubData.ID): 1.5, + fmt.Sprintf("chains.%s.value.gas-adjustment", rollerData.RollappID): 1.3, + fmt.Sprintf("chains.%s.value.is-dym-hub", rollerData.HubData.ID): true, + fmt.Sprintf( + "chains.%s.value.http-addr", + rollerData.HubData.ID, + ): rollerData.HubData.API_URL, + fmt.Sprintf("chains.%s.value.is-dym-rollapp", rollerData.RollappID): true, + "extra-codecs": []string{ + "ethermint", + }, + } + err := yamlconfig.UpdateNestedYAML(relayerConfigPath, updates) + if err != nil { + pterm.Error.Printf("Error updating YAML: %v\n", err) + return err + } + + return nil +} + +func ValidateIbcPathChains(relayerHome, raID string, hd consts.HubData) (bool, error) { + var srcChainOk bool + var dstChainOk bool + var defaultPathOk bool + var relayerConfigExists bool + var err error + + relayerConfigPath := GetConfigFilePath(relayerHome) + + pterm.Info.Println("checking configuration") + // 2. config file exists + relayerConfigExists, err = filesystem.DoesFileExist(relayerConfigPath) + if err != nil { + return false, err + } + + if relayerConfigExists { + // 2.1. path exist + defaultPathOk, err = VerifyDefaultPath(relayerHome) + if err != nil { + pterm.Error.Printf( + "failed to verify relayer path %s: %v\n", + consts.DefaultRelayerPath, + err, + ) + } + + if defaultPathOk { + // 2.2. isHubChainPresent + srcChainOk, err = VerifyPathSrcChain(relayerHome, hd) + if err != nil { + pterm.Error.Printf( + "failed to verify source chain in relayer path: %v\n", + err, + ) + } + + // 2.3. isRollappChainPresent + dstChainOk, err = VerifyPathDstChain(relayerHome, raID) + if err != nil { + return false, err + } + } + } + + if !relayerConfigExists || !srcChainOk || !dstChainOk { + return false, nil + } + + return true, nil +} diff --git a/utils/relayer/connection.go b/utils/relayer/connection.go new file mode 100644 index 00000000..d62e6739 --- /dev/null +++ b/utils/relayer/connection.go @@ -0,0 +1,81 @@ +package relayer + +import ( + "fmt" + "os" + + "gopkg.in/yaml.v3" + + "github.com/dymensionxyz/roller/cmd/consts" +) + +func VerifyDefaultPath(relayerHome string) (bool, error) { + cfp := GetConfigFilePath(relayerHome) + + data, err := os.ReadFile(cfp) + if err != nil { + return false, err + } + + var config map[string]interface{} + err = yaml.Unmarshal(data, &config) + if err != nil { + return false, err + } + + // Navigate to paths and check for hub-rollapp + if paths, ok := config["paths"].(map[interface{}]interface{}); ok { + if _, exists := paths[consts.DefaultRelayerPath]; exists { + fmt.Println("hub-rollapp exists in the YAML configuration.") + return true, nil + } + } + + return false, nil +} + +func VerifyPathSrcChain(relayerHome string, hd consts.HubData) (bool, error) { + cfp := GetConfigFilePath(relayerHome) + + data, err := os.ReadFile(cfp) + if err != nil { + return false, err + } + + // Unmarshal the YAML into the Config struct + var config Config + err = yaml.Unmarshal(data, &config) + if err != nil { + return false, err + } + + // Check if src.chain-id has a specific value + if config.Paths.HubRollapp.Src.ChainID == hd.ID { + return true, nil + } + + return false, nil +} + +func VerifyPathDstChain(relayerHome, raID string) (bool, error) { + cfp := GetConfigFilePath(relayerHome) + + data, err := os.ReadFile(cfp) + if err != nil { + return false, err + } + + // Unmarshal the YAML into the Config struct + var config Config + err = yaml.Unmarshal(data, &config) + if err != nil { + return false, err + } + + // Check if src.chain-id has a specific value + if config.Paths.HubRollapp.Dst.ChainID == raID { + return true, nil + } + + return false, nil +} diff --git a/utils/relayer/newibc.go b/utils/relayer/newibc.go new file mode 100644 index 00000000..14782e9f --- /dev/null +++ b/utils/relayer/newibc.go @@ -0,0 +1,85 @@ +package relayer + +import ( + "fmt" + "path/filepath" + + "github.com/pterm/pterm" + + initconfig "github.com/dymensionxyz/roller/cmd/config/init" + "github.com/dymensionxyz/roller/cmd/consts" + "github.com/dymensionxyz/roller/relayer" + "github.com/dymensionxyz/roller/utils/filesystem" + "github.com/dymensionxyz/roller/utils/keys" + "github.com/dymensionxyz/roller/utils/roller" +) + +// TODO: this should be a method on Relayer.Relayer in `relayer_manager` +func InitializeRelayer(home string, rollerData roller.RollappConfig) error { + // at this point it is safe to assume that + // relayer is being initialized on a sequencer node + // there is an existing roller config that can be used as the data source + relayerHome := filepath.Join(home, consts.ConfigDirName.Relayer) + isRelayerInitialized, err := filesystem.DirNotEmpty(relayerHome) + if err != nil { + pterm.Error.Printf("failed to check %s: %v\n", relayerHome, err) + return err + } + + if !isRelayerInitialized { + pterm.Info.Println("initializing relayer config") + err = initconfig.InitializeRelayerConfig( + relayer.ChainConfig{ + ID: rollerData.RollappID, + RPC: consts.DefaultRollappRPC, + Denom: rollerData.BaseDenom, + AddressPrefix: rollerData.Bech32Prefix, + GasPrices: "2000000000", + }, relayer.ChainConfig{ + ID: rollerData.HubData.ID, + RPC: rollerData.HubData.RPC_URL, + Denom: consts.Denoms.Hub, + AddressPrefix: consts.AddressPrefixes.Hub, + GasPrices: rollerData.HubData.GAS_PRICE, + }, home, + ) + if err != nil { + pterm.Error.Printf( + "failed to initialize relayer config: %v\n", + err, + ) + return err + } + } + + return nil +} + +func EnsureKeysArePresentAndFunded(rollerData roller.RollappConfig) error { + err := keys.GenerateRelayerKeys(rollerData) + if err != nil { + pterm.Error.Printf("failed to create relayer keys: %v\n", err) + return err + } + + err = keys.GetRelayerKeysToFund(rollerData) + if err != nil { + pterm.Error.Printf("failed to retrieve relayer keys to fund: %v\n", err) + return err + } + + proceed, _ := pterm.DefaultInteractiveConfirm.WithDefaultValue(false). + WithDefaultText( + "press 'y' when the wallets are funded", + ).Show() + if !proceed { + return fmt.Errorf("cancelled by user") + } + + err = VerifyRelayerBalances(rollerData.HubData) + if err != nil { + return err + } + + return nil +} diff --git a/utils/relayer/relayer.go b/utils/relayer/relayer.go index 4a26383b..efb3955b 100644 --- a/utils/relayer/relayer.go +++ b/utils/relayer/relayer.go @@ -1,24 +1,218 @@ package relayer -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"` +import ( + "fmt" + "path/filepath" + + "github.com/pterm/pterm" + + "github.com/dymensionxyz/roller/cmd/consts" + "github.com/dymensionxyz/roller/sequencer" + "github.com/dymensionxyz/roller/utils/config" + "github.com/dymensionxyz/roller/utils/dependencies" + "github.com/dymensionxyz/roller/utils/filesystem" + "github.com/dymensionxyz/roller/utils/keys" + "github.com/dymensionxyz/roller/utils/roller" +) + +func GetRollappToRunFor(home string) (string, *consts.HubData, error) { + rollerConfigFilePath := roller.GetConfigPath(home) + rollerConfigExists, err := filesystem.DoesFileExist(rollerConfigFilePath) + if err != nil { + return "", nil, err + } + + if rollerConfigExists { + pterm.Info.Println( + "existing roller configuration found, retrieving RollApp ID from it", + ) + rollerData, err := roller.LoadConfig(home) + if err != nil { + pterm.Error.Printf("failed to load rollapp config: %v\n", err) + return "", nil, err + } + + msg := fmt.Sprintf( + "the retrieved rollapp ID is: %s, would you like to initialize the relayer for this rollapp?", + pterm.DefaultBasicText.WithStyle(pterm.FgYellow.ToStyle()). + Sprint(rollerData.RollappID), + ) + runForRollappFromRollerConfig, _ := pterm.DefaultInteractiveConfirm.WithDefaultText(msg). + Show() + + if runForRollappFromRollerConfig { + raID := rollerData.RollappID + hd := rollerData.HubData + + return raID, &hd, nil + } + } + + return promptForRaAndHd() +} + +func NewIbcConnenctionCanBeCreatedOnCurrentNode(home, raID string) (bool, error) { + rollerData, err := roller.LoadConfig(home) + if err != nil { + pterm.Error.Printf("failed to load rollapp config: %v\n", err) + return false, err + } + + err = fmt.Errorf( + "new channels can only be initialized on a sequencer node which is running for a rollapp you're trying to create the IBC connection for", + ) + + runForRollappFromRollerConfig := raID == rollerData.RollappID + if !runForRollappFromRollerConfig { + return false, err + } + + if runForRollappFromRollerConfig && rollerData.NodeType != consts.NodeType.Sequencer { + return false, err + } + + return true, nil +} + +func promptForRaAndHd() (string, *consts.HubData, error) { + var hd consts.HubData + raID := config.PromptRaID() + env := config.PromptEnvironment() + + if env == "playground" { + hd = consts.Hubs[env] + } else { + hd = config.GenerateCustomHubData() + err := dependencies.InstallCustomDymdVersion() + if err != nil { + pterm.Error.Println("failed to install custom dymd version: ", err) + return "", nil, err + } + } + + return raID, &hd, nil +} + +func VerifyRelayerBalances(hd consts.HubData) error { + insufficientBalances, err := getRelayerInsufficientBalances(hd) + if err != nil { + return err + } + + if len(insufficientBalances) != 0 { + err = keys.PrintInsufficientBalancesIfAny(insufficientBalances) + if err != nil { + return err + } + } + + return nil +} + +func getRelayerInsufficientBalances( + hd consts.HubData, +) ([]keys.NotFundedAddressData, error) { + var insufficientBalances []keys.NotFundedAddressData + home := roller.GetRootDir() + + accData, err := GetRelayerAccountsData(home, hd) + if err != nil { + return nil, err + } + + // consts.Denoms.Hub is used here because as of @202409 we no longer require rollapp + // relayer account funding to establish IBC connection. + for _, acc := range accData { + if acc.Balance.Amount.Cmp(oneDayRelayPrice.BigInt()) < 0 { + insufficientBalances = append( + insufficientBalances, keys.NotFundedAddressData{ + KeyName: consts.KeysIds.HubRelayer, + Address: acc.Address, + CurrentBalance: acc.Balance.Amount, + RequiredBalance: oneDayRelayPrice.BigInt(), + Denom: consts.Denoms.Hub, + Network: hd.ID, + }, + ) + } + } + + return insufficientBalances, nil +} + +func GetRelayerAccountsData( + home string, + hd consts.HubData, +) ([]keys.AccountData, error) { + var data []keys.AccountData + + // rollappRlyAcc, err := getRolRlyAccData(cfg) + // if err != nil { + // return nil, err + // } + // data = append(data, *rollappRlyAcc) + + hubRlyAcc, err := getHubRlyAccData(home, hd) + if err != nil { + return nil, err + } + + data = append(data, *hubRlyAcc) + return data, nil +} + +// nolint: unused +func getRolRlyAccData(home string, raData roller.RollappConfig) (*keys.AccountData, error) { + RollappRlyAddr, err := keys.GetRelayerAddress(home, raData.RollappID) + seq := sequencer.GetInstance(raData) + if err != nil { + return nil, err + } + + RollappRlyBalance, err := keys.QueryBalance( + keys.ChainQueryConfig{ + RPC: seq.GetRPCEndpoint(), + Denom: raData.Denom, + Binary: consts.Executables.RollappEVM, + }, RollappRlyAddr, + ) + if err != nil { + return nil, err + } + + return &keys.AccountData{ + Address: RollappRlyAddr, + Balance: RollappRlyBalance, + }, nil +} + +func getHubRlyAccData(home string, hd consts.HubData) (*keys.AccountData, error) { + HubRlyAddr, err := keys.GetRelayerAddress(home, hd.ID) + if err != nil { + return nil, err + } + + HubRlyBalance, err := keys.QueryBalance( + keys.ChainQueryConfig{ + RPC: hd.RPC_URL, + Denom: consts.Denoms.Hub, + Binary: consts.Executables.Dymension, + }, HubRlyAddr, + ) + if err != nil { + return nil, err + } + + return &keys.AccountData{ + Address: HubRlyAddr, + Balance: HubRlyBalance, + }, nil +} + +func GetHomeDir(home string) string { + return filepath.Join(home, consts.ConfigDirName.Relayer) +} + +func GetConfigFilePath(relayerHome string) string { + return filepath.Join(relayerHome, "config", "config.yaml") } diff --git a/utils/relayer/types.go b/utils/relayer/types.go new file mode 100644 index 00000000..67ce4d6b --- /dev/null +++ b/utils/relayer/types.go @@ -0,0 +1,45 @@ +package relayer + +import cosmossdkmath "cosmossdk.io/math" + +var oneDayRelayPrice, _ = cosmossdkmath.NewIntFromString( + "2000000000000000000", +) // 2000000000000000000 = 2dym + +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"` +} + +// Config struct represents the paths section inside the relayer +// configuration file +type Config struct { + Paths struct { + HubRollapp struct { + Dst struct { + ChainID string `yaml:"chain-id"` + } `yaml:"dst"` + Src struct { + ChainID string `yaml:"chain-id"` + } `yaml:"src"` + } `yaml:"hub-rollapp"` + } `yaml:"paths"` +} diff --git a/utils/rollapp/rollapp.go b/utils/rollapp/rollapp.go index 22e825cc..cda3c8be 100644 --- a/utils/rollapp/rollapp.go +++ b/utils/rollapp/rollapp.go @@ -180,7 +180,7 @@ func GetMetadataFromChain(raID string, hd consts.HubData) (*ShowRollappResponse, return &raResponse, nil } -// nice function name, ik +// misleading function name, how to call this? func PopulateRollerConfigWithRaMetadataFromChain( home, raID string, hd consts.HubData, @@ -216,7 +216,7 @@ func PopulateRollerConfigWithRaMetadataFromChain( Environment: hd.ID, RollappBinaryVersion: version.BuildVersion, Bech32Prefix: raResponse.Rollapp.GenesisInfo.Bech32Prefix, - BaseDenom: "", + BaseDenom: raResponse.Rollapp.GenesisInfo.NativeDenom.Base, MinGasPrices: "0", } diff --git a/utils/roller/config.go b/utils/roller/config.go index 9af99ded..b96b0891 100644 --- a/utils/roller/config.go +++ b/utils/roller/config.go @@ -77,14 +77,14 @@ func PopulateConfig( home, raID string, hd consts.HubData, daData consts.DaData, - rollerData RollappConfig, + vmType string, ) error { rollerConfigFilePath := filepath.Join(home, consts.RollerConfigFileName) rollerTomlData := map[string]any{ "rollapp_id": raID, "rollapp_binary": strings.ToLower(consts.Executables.RollappEVM), - "rollapp_vm_type": string(rollerData.RollappVMType), + "rollapp_vm_type": vmType, "home": home, "HubData.id": hd.ID, @@ -123,14 +123,11 @@ func (c RollappConfig) ValidateConfig() error { return err } - // the assumption is that the supply is coming from the genesis creator - // err = VerifyTokenSupply(c.TokenSupply) - // if err != nil { - // return err - // } + if c.BaseDenom == "" { + return fmt.Errorf("base denom should be populated") + } if !IsValidDAType(string(c.DA.Backend)) { - fmt.Println(c.DA.Backend) return fmt.Errorf("invalid DA type: %s. supported types %s", c.DA, SupportedDas) } diff --git a/utils/roller/roller.go b/utils/roller/roller.go index ea3c0cfc..67dd5888 100644 --- a/utils/roller/roller.go +++ b/utils/roller/roller.go @@ -1,8 +1,6 @@ package roller import ( - "errors" - "io/fs" "os" "path/filepath" "strings" @@ -11,6 +9,7 @@ import ( "github.com/pterm/pterm" "github.com/dymensionxyz/roller/cmd/consts" + "github.com/dymensionxyz/roller/utils/filesystem" "github.com/dymensionxyz/roller/version" ) @@ -19,29 +18,31 @@ func GetRootDir() string { } func GetConfigPath(home string) string { - return filepath.Join(home, "roller.toml") + return filepath.Join(home, consts.RollerConfigFileName) } -func CreateConfigFile(home string) (bool, error) { +func CreateConfigFileIfNotPresent(home string) (bool, error) { rollerConfigFilePath := GetConfigPath(home) - - _, err := os.Stat(rollerConfigFilePath) + ok, err := filesystem.DoesFileExist(rollerConfigFilePath) if err != nil { - if errors.Is(err, fs.ErrNotExist) { - pterm.Info.Println("roller.toml not found, creating") - _, err := os.Create(rollerConfigFilePath) - if err != nil { - pterm.Error.Printf( - "failed to create %s: %v", rollerConfigFilePath, err, - ) - return false, err - } - - return true, nil + pterm.Error.Println("failed to check roller config file existence", err) + return false, err + } + + if !ok { + pterm.Info.Printf("%s does not exist, creating...\n", rollerConfigFilePath) + _, err := os.Create(rollerConfigFilePath) + if err != nil { + pterm.Error.Printf( + "failed to create %s: %v", rollerConfigFilePath, err, + ) + return false, err } + + return true, nil } - return false, nil + return true, nil } // TODO: should be called from root command