From dc8e2fe29fe37eed0729eb64997806518ddc829a Mon Sep 17 00:00:00 2001 From: Adi Seredinschi Date: Thu, 16 Jun 2022 17:02:23 +0200 Subject: [PATCH] Add support for fetching & parsing the Tendermint version of a chain (#2302) * Fix for #2301 * changelog * changelog broken link * KV pairs in log h/t Mikhail --- .../2301-tendermint-version-support.md | 2 + relayer/src/chain/cosmos/version.rs | 72 +++++++++++++++---- 2 files changed, 60 insertions(+), 14 deletions(-) create mode 100644 .changelog/unreleased/features/relayer/2301-tendermint-version-support.md diff --git a/.changelog/unreleased/features/relayer/2301-tendermint-version-support.md b/.changelog/unreleased/features/relayer/2301-tendermint-version-support.md new file mode 100644 index 0000000000..40e5abb490 --- /dev/null +++ b/.changelog/unreleased/features/relayer/2301-tendermint-version-support.md @@ -0,0 +1,2 @@ +- Add support for fetching & parsing the Tendermint version of a network that + Hermes is connected to. ([#2301](https://github.com/informalsystems/ibc-rs/issues/2301)) diff --git a/relayer/src/chain/cosmos/version.rs b/relayer/src/chain/cosmos/version.rs index 5c605bf989..e115226e4f 100644 --- a/relayer/src/chain/cosmos/version.rs +++ b/relayer/src/chain/cosmos/version.rs @@ -1,5 +1,5 @@ //! Utilities for extracting and parsing versioning information -//! of Cosmos-SDK chains. The extracted version specification +//! of Cosmos-SDK networks. The extracted version specification //! is captured in a domain-type semver format in [`Specs`]. use flex_error::define_error; @@ -7,9 +7,9 @@ use tracing::trace; use ibc_proto::cosmos::base::tendermint::v1beta1::VersionInfo; -/// Specifies the SDK & IBC-go modules path, as it is expected +/// Specifies the SDK, IBC-go, and Tendermint modules path, as expected /// to appear in the application version information of a -/// Cosmos chain. +/// Cosmos-SDK network. /// /// The module identification is captured in a [`Module`] /// with the following structure as an example: @@ -22,17 +22,19 @@ use ibc_proto::cosmos::base::tendermint::v1beta1::VersionInfo; /// ``` const SDK_MODULE_NAME: &str = "cosmos/cosmos-sdk"; const IBC_GO_MODULE_NAME: &str = "cosmos/ibc-go"; +const TENDERMINT_MODULE_NAME: &str = "tendermint/tendermint"; /// Captures the version(s) specification of different -/// modules of a chain. +/// modules of a network. /// -/// Assumes that the chain runs on Cosmos SDK. +/// Assumes that the network runs on Cosmos SDK. /// Stores both the SDK version as well as /// the IBC-go module version (if existing). #[derive(Debug)] pub struct Specs { pub sdk_version: semver::Version, pub ibc_go_version: Option, + pub tendermint_version: semver::Version, } define_error! { @@ -42,7 +44,14 @@ define_error! { address: String, app: AppInfo, } - |e| { format!("node at {} running chain {} not caught up", e.address, e.app) }, + |e| { format!("failed to find the SDK module dependency ('{}') for application {}", e.address, e.app) }, + + TendermintModuleNotFound + { + address: String, + app: AppInfo, + } + |e| { format!("failed to find the Tendermint dependency ('{}') for application {}", e.address, e.app) }, VersionParsingFailed { @@ -51,7 +60,7 @@ define_error! { cause: String, app: AppInfo, } - |e| { format!("failed parsing the SDK module ('{}') version number '{}' into a semver for application {}; cause: {}", + |e| { format!("failed parsing the module path ('{}') version number '{}' into a semver for application {}; cause: {}", e.module_path, e.raw_version, e.app, e.cause) }, } } @@ -63,19 +72,22 @@ impl TryFrom for Specs { // Get the Cosmos SDK version let sdk_version = parse_sdk_version(&raw_version)?; let ibc_go_version = parse_ibc_go_version(&raw_version)?; + let tendermint_version = parse_tendermint_version(&raw_version)?; trace!( - "parsed version specification for {} {}@{} -> SDK={}; Ibc-Go status={:?}", - raw_version.app_name, - raw_version.version, - raw_version.git_commit, - sdk_version, - ibc_go_version + application = %raw_version.app_name, + version = %raw_version.version, + git_commit = %raw_version.git_commit, + sdk_version = %sdk_version, + ibc_go_status = ?ibc_go_version, + tendermint_version = %tendermint_version, + "parsed version specification" ); Ok(Self { sdk_version, ibc_go_version, + tendermint_version, }) } } @@ -117,7 +129,8 @@ fn parse_ibc_go_version(version_info: &VersionInfo) -> Result Ok(None), Some(ibc_module) => { // The raw version number has a leading 'v', trim it out; @@ -142,6 +155,37 @@ fn parse_ibc_go_version(version_info: &VersionInfo) -> Result Result { + let module = version_info + .build_deps + .iter() + .find(|&m| m.path.contains(TENDERMINT_MODULE_NAME)) + .ok_or_else(|| { + Error::tendermint_module_not_found( + TENDERMINT_MODULE_NAME.to_string(), + AppInfo::from(version_info), + ) + })?; + + // The raw version number has a leading 'v', trim it out; + let plain_version = module.version.trim_start_matches('v'); + + // Parse the module version + let mut version = semver::Version::parse(plain_version).map_err(|e| { + Error::version_parsing_failed( + module.path.clone(), + module.version.clone(), + e.to_string(), + AppInfo::from(version_info), + ) + })?; + + // Remove the pre-release version to ensure we don't give special treatment to pre-releases. + version.pre = semver::Prerelease::EMPTY; + + Ok(version) +} + /// Helper struct to capture all the reported information of an /// IBC application, e.g., `gaiad`. #[derive(Clone, Debug)]