diff --git a/crates/relayer-all-in-one/src/one_for_all/components.rs b/crates/relayer-all-in-one/src/one_for_all/components.rs index f686b816e5..1eebd0ca4c 100644 --- a/crates/relayer-all-in-one/src/one_for_all/components.rs +++ b/crates/relayer-all-in-one/src/one_for_all/components.rs @@ -1,3 +1,4 @@ +use ibc_relayer_components::relay::impls::client::update::BuildUpdateClientMessages; use ibc_relayer_components::relay::impls::message_senders::chain_sender::SendIbcMessagesToChain; use ibc_relayer_components::relay::impls::message_senders::update_client::SendIbcMessagesWithUpdateClient; use ibc_relayer_components::relay::impls::messages::skip_update_client::SkipUpdateClient; @@ -20,15 +21,13 @@ use ibc_relayer_components_extra::telemetry::impls::status::ChainStatusTelemetry use crate::one_for_all::impls::chain::queries::consensus_state::SendConsensusStateQueryToOfa; use crate::one_for_all::impls::chain::queries::status::SendChainStatusQueryToOfa; -use crate::one_for_all::impls::relay::message_builders::update_client::BuildUpdateClientMessageFromOfa; use crate::one_for_all::impls::relay::packet_filter::FilterPacketFromOfa; pub type ChainStatusQuerier = ChainStatusTelemetryQuerier; pub type ConsensusStateQuerier = ConsensusStateTelemetryQuerier; -pub type UpdateClientMessageBuilder = - SkipUpdateClient>; +pub type UpdateClientMessageBuilder = SkipUpdateClient>; pub type AckPacketRelayer = BaseAckPacketRelayer; diff --git a/crates/relayer-all-in-one/src/one_for_all/impls/chain/client.rs b/crates/relayer-all-in-one/src/one_for_all/impls/chain/client.rs index 97d15962f6..571fd63612 100644 --- a/crates/relayer-all-in-one/src/one_for_all/impls/chain/client.rs +++ b/crates/relayer-all-in-one/src/one_for_all/impls/chain/client.rs @@ -1,8 +1,16 @@ use async_trait::async_trait; +use ibc_relayer_components::chain::traits::client::client_state::CanQueryClientState; +use ibc_relayer_components::chain::traits::client::consensus_state::CanFindConsensusStateHeight; use ibc_relayer_components::chain::traits::client::create::{ CanBuildCreateClientMessage, CanBuildCreateClientPayload, HasCreateClientEvent, HasCreateClientOptions, HasCreateClientPayload, }; +use ibc_relayer_components::chain::traits::client::update::{ + CanBuildUpdateClientMessage, CanBuildUpdateClientPayload, HasUpdateClientPayload, +}; +use ibc_relayer_components::chain::traits::types::client_state::{ + HasClientStateFields, HasClientStateType, +}; use crate::one_for_all::traits::chain::OfaIbcChain; use crate::one_for_all::types::chain::OfaChainWrapper; @@ -76,3 +84,104 @@ where .await } } + +#[async_trait] +impl HasClientStateType> + for OfaChainWrapper +where + Chain: OfaIbcChain, + Counterparty: OfaIbcChain, +{ + type ClientState = Chain::ClientState; +} + +#[async_trait] +impl HasUpdateClientPayload> + for OfaChainWrapper +where + Chain: OfaIbcChain, + Counterparty: OfaIbcChain, +{ + type UpdateClientPayload = Chain::UpdateClientPayload; +} + +#[async_trait] +impl CanBuildUpdateClientPayload> + for OfaChainWrapper +where + Chain: OfaIbcChain, + Counterparty: OfaIbcChain, +{ + async fn build_update_client_payload( + &self, + trusted_height: &Self::Height, + target_height: &Self::Height, + client_state: Self::ClientState, + ) -> Result { + self.chain + .build_update_client_payload(trusted_height, target_height, client_state) + .await + } +} + +#[async_trait] +impl CanBuildUpdateClientMessage> + for OfaChainWrapper +where + Chain: OfaIbcChain, + Counterparty: OfaIbcChain, +{ + async fn build_update_client_message( + &self, + client_id: &Self::ClientId, + payload: Counterparty::UpdateClientPayload, + ) -> Result, Self::Error> { + self.chain + .build_update_client_message(client_id, payload) + .await + } +} + +#[async_trait] +impl CanFindConsensusStateHeight> + for OfaChainWrapper +where + Chain: OfaIbcChain, + Counterparty: OfaIbcChain, +{ + async fn find_consensus_state_height_before( + &self, + client_id: &Self::ClientId, + target_height: &Counterparty::Height, + ) -> Result { + self.chain + .find_consensus_state_height_before(client_id, target_height) + .await + } +} + +impl HasClientStateFields> + for OfaChainWrapper +where + Chain: OfaIbcChain, + Counterparty: OfaIbcChain, +{ + fn client_state_latest_height(client_state: &Self::ClientState) -> &Self::Height { + Chain::client_state_latest_height(client_state) + } +} + +#[async_trait] +impl CanQueryClientState> + for OfaChainWrapper +where + Chain: OfaIbcChain, + Counterparty: OfaIbcChain, +{ + async fn query_client_state( + &self, + client_id: &Self::ClientId, + ) -> Result { + self.chain.query_client_state(client_id).await + } +} diff --git a/crates/relayer-all-in-one/src/one_for_all/impls/relay/message_builders/update_client.rs b/crates/relayer-all-in-one/src/one_for_all/impls/relay/message_builders/update_client.rs index 3438e20000..a070e6577f 100644 --- a/crates/relayer-all-in-one/src/one_for_all/impls/relay/message_builders/update_client.rs +++ b/crates/relayer-all-in-one/src/one_for_all/impls/relay/message_builders/update_client.rs @@ -4,58 +4,12 @@ use ibc_relayer_components::relay::traits::messages::update_client::{ CanBuildUpdateClientMessage, UpdateClientMessageBuilder, }; use ibc_relayer_components::relay::traits::target::ChainTarget; -use ibc_relayer_components::relay::traits::target::{DestinationTarget, SourceTarget}; use crate::one_for_all::components; -use crate::one_for_all::traits::chain::OfaChain; use crate::one_for_all::traits::relay::OfaRelay; use crate::one_for_all::types::relay::OfaRelayWrapper; use crate::std_prelude::*; -pub struct BuildUpdateClientMessageFromOfa; - -#[async_trait] -impl UpdateClientMessageBuilder, SourceTarget> - for BuildUpdateClientMessageFromOfa -where - Relay: OfaRelay, - SrcChain: OfaChain, -{ - async fn build_update_client_messages( - context: &OfaRelayWrapper, - _target: SourceTarget, - height: &::Height, - ) -> Result, Relay::Error> { - let messages = context - .relay - .build_src_update_client_messages(height) - .await?; - - Ok(messages) - } -} - -#[async_trait] -impl UpdateClientMessageBuilder, DestinationTarget> - for BuildUpdateClientMessageFromOfa -where - Relay: OfaRelay, - DstChain: OfaChain, -{ - async fn build_update_client_messages( - context: &OfaRelayWrapper, - _target: DestinationTarget, - height: &::Height, - ) -> Result, Relay::Error> { - let messages = context - .relay - .build_dst_update_client_messages(height) - .await?; - - Ok(messages) - } -} - #[async_trait] impl CanBuildUpdateClientMessage for OfaRelayWrapper where diff --git a/crates/relayer-all-in-one/src/one_for_all/traits/chain.rs b/crates/relayer-all-in-one/src/one_for_all/traits/chain.rs index 85f7755322..ea25b19e2e 100644 --- a/crates/relayer-all-in-one/src/one_for_all/traits/chain.rs +++ b/crates/relayer-all-in-one/src/one_for_all/traits/chain.rs @@ -170,12 +170,16 @@ where */ type OutgoingPacket: Async; + type ClientState: Async; + type CreateClientPayloadOptions: Async; type CreateClientPayload: Async; type CreateClientEvent: Async; + type UpdateClientPayload: Async; + type ConnectionDetails: Async; type ConnectionVersion: Eq + Default + Async; @@ -237,6 +241,8 @@ where fn outgoing_packet_timeout_timestamp(packet: &Self::OutgoingPacket) -> &Counterparty::Timestamp; + fn client_state_latest_height(client_state: &Self::ClientState) -> &Self::Height; + fn log_incoming_packet<'a>( event: &'a Self::IncomingPacket, ) -> ::LogValue<'a>; @@ -292,6 +298,11 @@ where port_id: &Self::PortId, ) -> Result; + async fn query_client_state( + &self, + client_id: &Self::ClientId, + ) -> Result; + async fn query_consensus_state( &self, client_id: &Self::ClientId, @@ -339,6 +350,25 @@ where counterparty_payload: Counterparty::CreateClientPayload, ) -> Result; + async fn build_update_client_payload( + &self, + trusted_height: &Self::Height, + target_height: &Self::Height, + client_state: Self::ClientState, + ) -> Result; + + async fn build_update_client_message( + &self, + client_id: &Self::ClientId, + payload: Counterparty::UpdateClientPayload, + ) -> Result, Self::Error>; + + async fn find_consensus_state_height_before( + &self, + client_id: &Self::ClientId, + target_height: &Counterparty::Height, + ) -> Result; + async fn build_connection_open_init_payload( &self, ) -> Result; diff --git a/crates/relayer-all-in-one/src/one_for_all/traits/relay.rs b/crates/relayer-all-in-one/src/one_for_all/traits/relay.rs index 9df7dfbcb2..62bad07009 100644 --- a/crates/relayer-all-in-one/src/one_for_all/traits/relay.rs +++ b/crates/relayer-all-in-one/src/one_for_all/traits/relay.rs @@ -85,16 +85,6 @@ pub trait OfaRelay: Async { fn dst_chain(&self) -> &OfaChainWrapper; - async fn build_src_update_client_messages( - &self, - height: &::Height, - ) -> Result::Message>, Self::Error>; - - async fn build_dst_update_client_messages( - &self, - height: &::Height, - ) -> Result::Message>, Self::Error>; - async fn try_acquire_packet_lock<'a>( &'a self, packet: &'a Self::Packet, diff --git a/crates/relayer-components/src/chain/traits/client/client_state.rs b/crates/relayer-components/src/chain/traits/client/client_state.rs index 1c6044d230..46fd9e43ac 100644 --- a/crates/relayer-components/src/chain/traits/client/client_state.rs +++ b/crates/relayer-components/src/chain/traits/client/client_state.rs @@ -1,13 +1,17 @@ use async_trait::async_trait; -use crate::chain::traits::types::client_state::HasClientStateSettingsType; +use crate::chain::traits::types::client_state::HasClientStateType; +use crate::chain::traits::types::ibc::HasIbcChainTypes; +use crate::core::traits::error::HasErrorType; use crate::std_prelude::*; #[async_trait] -pub trait CanBuildClientState: HasClientStateSettingsType { - async fn build_client_state( +pub trait CanQueryClientState: HasIbcChainTypes + HasErrorType +where + Counterparty: HasClientStateType, +{ + async fn query_client_state( &self, - height: &Self::Height, - settings: &Self::ClientStateSettings, - ) -> Self::ClientState; + client_id: &Self::ClientId, + ) -> Result; } diff --git a/crates/relayer-components/src/chain/traits/client/consensus_state.rs b/crates/relayer-components/src/chain/traits/client/consensus_state.rs index b99284bc07..7cfdf0b2bb 100644 --- a/crates/relayer-components/src/chain/traits/client/consensus_state.rs +++ b/crates/relayer-components/src/chain/traits/client/consensus_state.rs @@ -1,17 +1,27 @@ use async_trait::async_trait; -use crate::chain::traits::types::client_state::HasClientStateType; -use crate::chain::traits::types::consensus_state::HasConsensusStateType; +use crate::chain::traits::types::height::HasHeightType; +use crate::chain::traits::types::ibc::HasIbcChainTypes; use crate::core::traits::error::HasErrorType; use crate::std_prelude::*; #[async_trait] -pub trait CanBuildConsensusState: - HasConsensusStateType + HasClientStateType + HasErrorType +pub trait CanFindConsensusStateHeight: + HasIbcChainTypes + HasErrorType +where + Counterparty: HasHeightType, { - async fn build_consensus_state( - trusted_height: &Self::Height, - target_height: &Self::Height, - client_state: &Self::ClientState, - ) -> Result; + /** + Query the chain to find a consensus state that has a height that is + less than or equal the target height. This is needed as a base trusted + height to build the headers for UpdateClient. + + Invariant: the returned height must be less than or equal to the given + target height. + */ + async fn find_consensus_state_height_before( + &self, + client_id: &Self::ClientId, + target_height: &Counterparty::Height, + ) -> Result; } diff --git a/crates/relayer-components/src/chain/traits/client/mod.rs b/crates/relayer-components/src/chain/traits/client/mod.rs index 8c6e9c92fd..31b7e8c435 100644 --- a/crates/relayer-components/src/chain/traits/client/mod.rs +++ b/crates/relayer-components/src/chain/traits/client/mod.rs @@ -1,3 +1,4 @@ pub mod client_state; pub mod consensus_state; pub mod create; +pub mod update; diff --git a/crates/relayer-components/src/chain/traits/client/update.rs b/crates/relayer-components/src/chain/traits/client/update.rs new file mode 100644 index 0000000000..011a2746cf --- /dev/null +++ b/crates/relayer-components/src/chain/traits/client/update.rs @@ -0,0 +1,36 @@ +use async_trait::async_trait; + +use crate::chain::traits::types::client_state::HasClientStateType; +use crate::chain::traits::types::ibc::HasIbcChainTypes; +use crate::core::traits::error::HasErrorType; +use crate::core::traits::sync::Async; +use crate::std_prelude::*; + +pub trait HasUpdateClientPayload: HasIbcChainTypes { + type UpdateClientPayload: Async; +} + +#[async_trait] +pub trait CanBuildUpdateClientPayload: + HasUpdateClientPayload + HasClientStateType + HasErrorType +{ + async fn build_update_client_payload( + &self, + trusted_height: &Self::Height, + target_height: &Self::Height, + client_state: Self::ClientState, + ) -> Result; +} + +#[async_trait] +pub trait CanBuildUpdateClientMessage: + HasIbcChainTypes + HasErrorType +where + Counterparty: HasUpdateClientPayload, +{ + async fn build_update_client_message( + &self, + client_id: &Self::ClientId, + payload: Counterparty::UpdateClientPayload, + ) -> Result, Self::Error>; +} diff --git a/crates/relayer-components/src/chain/traits/queries/client.rs b/crates/relayer-components/src/chain/traits/queries/client.rs deleted file mode 100644 index 55bf83f879..0000000000 --- a/crates/relayer-components/src/chain/traits/queries/client.rs +++ /dev/null @@ -1,16 +0,0 @@ -use async_trait::async_trait; - -use crate::chain::traits::types::client_state::HasClientStateType; -use crate::core::traits::error::HasErrorType; -use crate::std_prelude::*; - -#[async_trait] -pub trait CanQueryClientState: - HasClientStateType + HasErrorType -{ - async fn query_connection( - &self, - client_id: &Self::ClientId, - height: &Self::Height, - ) -> Result; -} diff --git a/crates/relayer-components/src/chain/traits/queries/mod.rs b/crates/relayer-components/src/chain/traits/queries/mod.rs index 46d762e7c5..82b9d57b2c 100644 --- a/crates/relayer-components/src/chain/traits/queries/mod.rs +++ b/crates/relayer-components/src/chain/traits/queries/mod.rs @@ -1,5 +1,4 @@ pub mod channel; -pub mod client; pub mod connection; pub mod consensus_state; pub mod received_packet; diff --git a/crates/relayer-components/src/chain/traits/types/client_state.rs b/crates/relayer-components/src/chain/traits/types/client_state.rs index 5c0508c2de..eeb8e300f5 100644 --- a/crates/relayer-components/src/chain/traits/types/client_state.rs +++ b/crates/relayer-components/src/chain/traits/types/client_state.rs @@ -8,6 +8,6 @@ pub trait HasClientStateType: HasIbcChainTypes { type ClientState: Async; } -pub trait HasClientStateSettingsType: HasClientStateType { - type ClientStateSettings: Async; +pub trait HasClientStateFields: HasClientStateType { + fn client_state_latest_height(client_state: &Self::ClientState) -> &Self::Height; } diff --git a/crates/relayer-components/src/relay/impls/client/mod.rs b/crates/relayer-components/src/relay/impls/client/mod.rs index c5fb369c1d..82a5ce72ba 100644 --- a/crates/relayer-components/src/relay/impls/client/mod.rs +++ b/crates/relayer-components/src/relay/impls/client/mod.rs @@ -1 +1,2 @@ pub mod create; +pub mod update; diff --git a/crates/relayer-components/src/relay/impls/client/update.rs b/crates/relayer-components/src/relay/impls/client/update.rs new file mode 100644 index 0000000000..33bf790acf --- /dev/null +++ b/crates/relayer-components/src/relay/impls/client/update.rs @@ -0,0 +1,84 @@ +use async_trait::async_trait; + +use crate::chain::traits::client::client_state::CanQueryClientState; +use crate::chain::traits::client::consensus_state::CanFindConsensusStateHeight; +use crate::chain::traits::client::update::{ + CanBuildUpdateClientMessage, CanBuildUpdateClientPayload, +}; +use crate::chain::traits::types::client_state::HasClientStateFields; +use crate::relay::traits::chains::HasRelayChains; +use crate::relay::traits::messages::update_client::UpdateClientMessageBuilder; +use crate::relay::traits::target::ChainTarget; +use crate::std_prelude::*; + +pub struct BuildUpdateClientMessages; + +#[async_trait] +impl UpdateClientMessageBuilder + for BuildUpdateClientMessages +where + Relay: HasRelayChains, + Target: ChainTarget, + TargetChain: CanQueryClientState + + CanBuildUpdateClientMessage + + CanFindConsensusStateHeight, + CounterpartyChain: CanBuildUpdateClientPayload + HasClientStateFields, + CounterpartyChain::Height: Clone, +{ + async fn build_update_client_messages( + relay: &Relay, + _target: Target, + target_height: &CounterpartyChain::Height, + ) -> Result, Relay::Error> { + let target_client_id = Target::target_client_id(relay); + + let target_chain = Target::target_chain(relay); + let counterparty_chain = Target::counterparty_chain(relay); + + let client_state = target_chain + .query_client_state(target_client_id) + .await + .map_err(Target::target_chain_error)?; + + let client_state_height = CounterpartyChain::client_state_latest_height(&client_state); + + // If the client state height is already the same as target height, then there + // is no need to build any UpdateClient message + if client_state_height == target_height { + return Ok(Vec::new()); + } + + let trusted_height = if client_state_height < target_height { + // If the client state height is less than the target height, we can use that + // as a base trust height to build our UpdateClient headers. + client_state_height.clone() + } else { + // If the client state height is greater than the target height, it means we + // have to find a previous consensus height that is less than the target height. + let consensus_state_height = target_chain + .find_consensus_state_height_before(target_client_id, target_height) + .await + .map_err(Target::target_chain_error)?; + + // If we happen to find a consensus height that matches the target height, + // then there is no need to build any UpdateClient message. + if &consensus_state_height == target_height { + return Ok(Vec::new()); + } + + consensus_state_height + }; + + let update_payload = counterparty_chain + .build_update_client_payload(&trusted_height, target_height, client_state) + .await + .map_err(Target::counterparty_chain_error)?; + + let messages = target_chain + .build_update_client_message(target_client_id, update_payload) + .await + .map_err(Target::target_chain_error)?; + + Ok(messages) + } +} diff --git a/crates/relayer-components/src/relay/traits/messages/update_client.rs b/crates/relayer-components/src/relay/traits/messages/update_client.rs index 6d5d2ed714..e6a2fe41da 100644 --- a/crates/relayer-components/src/relay/traits/messages/update_client.rs +++ b/crates/relayer-components/src/relay/traits/messages/update_client.rs @@ -24,7 +24,7 @@ where Target: ChainTarget, { async fn build_update_client_messages( - context: &Relay, + relay: &Relay, _target: Target, height: &Height, ) -> Result>, Relay::Error>; diff --git a/crates/relayer-components/src/relay/traits/target.rs b/crates/relayer-components/src/relay/traits/target.rs index e5047bbc2f..bb67d74e66 100644 --- a/crates/relayer-components/src/relay/traits/target.rs +++ b/crates/relayer-components/src/relay/traits/target.rs @@ -21,14 +21,14 @@ pub trait ChainTarget: Async + Default + Copy + private:: e: ::Error, ) -> Relay::Error; - fn target_chain(context: &Relay) -> &Self::TargetChain; + fn target_chain(relay: &Relay) -> &Self::TargetChain; - fn counterparty_chain(context: &Relay) -> &Self::CounterpartyChain; + fn counterparty_chain(relay: &Relay) -> &Self::CounterpartyChain; - fn target_client_id(context: &Relay) -> &ClientId; + fn target_client_id(relay: &Relay) -> &ClientId; fn counterparty_client_id( - context: &Relay, + relay: &Relay, ) -> &ClientId; } diff --git a/crates/relayer-cosmos/src/contexts/builder.rs b/crates/relayer-cosmos/src/contexts/builder.rs index 3ba15c5486..d8cccae7a2 100644 --- a/crates/relayer-cosmos/src/contexts/builder.rs +++ b/crates/relayer-cosmos/src/contexts/builder.rs @@ -11,7 +11,6 @@ use ibc_relayer::chain::handle::BaseChainHandle; use ibc_relayer::chain::handle::ChainHandle; use ibc_relayer::config::filter::PacketFilter; use ibc_relayer::config::Config; -use ibc_relayer::foreign_client::ForeignClient; use ibc_relayer::keyring::AnySigningKeyPair; use ibc_relayer::keyring::Secp256k1KeyPair; use ibc_relayer::spawn::spawn_chain_runtime; @@ -133,24 +132,12 @@ impl CosmosBuilder { src_batch_sender: CosmosBatchSender, dst_batch_sender: CosmosBatchSender, ) -> Result, Error> { - let client_src_to_dst = ForeignClient::restore( - dst_client_id.clone(), - dst_chain.chain.handle.clone(), - src_chain.chain.handle.clone(), - ); - - let client_dst_to_src = ForeignClient::restore( - src_client_id.clone(), - src_chain.chain.handle.clone(), - dst_chain.chain.handle.clone(), - ); - let relay = CosmosRelay::new( self.runtime.clone(), src_chain, dst_chain, - client_src_to_dst, - client_dst_to_src, + src_client_id.clone(), + dst_client_id.clone(), self.packet_filter.clone(), src_batch_sender, dst_batch_sender, diff --git a/crates/relayer-cosmos/src/contexts/relay.rs b/crates/relayer-cosmos/src/contexts/relay.rs index db7acb128e..80590abf9b 100644 --- a/crates/relayer-cosmos/src/contexts/relay.rs +++ b/crates/relayer-cosmos/src/contexts/relay.rs @@ -4,12 +4,11 @@ use alloc::sync::Arc; use futures::lock::Mutex; use ibc_relayer::chain::handle::ChainHandle; use ibc_relayer::config::filter::PacketFilter; -use ibc_relayer::foreign_client::ForeignClient; use ibc_relayer_all_in_one::one_for_all::types::chain::OfaChainWrapper; use ibc_relayer_all_in_one::one_for_all::types::runtime::OfaRuntimeWrapper; use ibc_relayer_runtime::tokio::context::TokioRuntimeContext; use ibc_relayer_types::core::ics04_channel::packet::Sequence; -use ibc_relayer_types::core::ics24_host::identifier::{ChannelId, PortId}; +use ibc_relayer_types::core::ics24_host::identifier::{ChannelId, ClientId, PortId}; use crate::contexts::chain::CosmosChain; use crate::types::batch::CosmosBatchSender; @@ -22,8 +21,8 @@ where pub runtime: OfaRuntimeWrapper, pub src_chain: OfaChainWrapper>, pub dst_chain: OfaChainWrapper>, - pub src_to_dst_client: ForeignClient, - pub dst_to_src_client: ForeignClient, + pub src_client_id: ClientId, + pub dst_client_id: ClientId, pub packet_filter: PacketFilter, pub packet_lock_mutex: Arc>>, pub src_chain_message_batch_sender: CosmosBatchSender, @@ -39,8 +38,8 @@ where runtime: OfaRuntimeWrapper, src_chain: OfaChainWrapper>, dst_chain: OfaChainWrapper>, - src_to_dst_client: ForeignClient, - dst_to_src_client: ForeignClient, + src_client_id: ClientId, + dst_client_id: ClientId, packet_filter: PacketFilter, src_chain_message_batch_sender: CosmosBatchSender, dst_chain_message_batch_sender: CosmosBatchSender, @@ -49,8 +48,8 @@ where runtime, src_chain, dst_chain, - src_to_dst_client, - dst_to_src_client, + src_client_id, + dst_client_id, packet_filter, src_chain_message_batch_sender, dst_chain_message_batch_sender, diff --git a/crates/relayer-cosmos/src/impls/chain.rs b/crates/relayer-cosmos/src/impls/chain.rs index 8b44e30dd1..10b3b1809b 100644 --- a/crates/relayer-cosmos/src/impls/chain.rs +++ b/crates/relayer-cosmos/src/impls/chain.rs @@ -1,13 +1,15 @@ use alloc::sync::Arc; use async_trait::async_trait; +use core::iter; use eyre::eyre; use ibc_relayer::chain::client::ClientSettings; use ibc_relayer::chain::counterparty::counterparty_chain_from_channel; use ibc_relayer::chain::endpoint::ChainStatus; use ibc_relayer::chain::handle::ChainHandle; use ibc_relayer::chain::requests::{ - IncludeProof, Qualified, QueryChannelRequest, QueryConnectionRequest, - QueryConsensusStateRequest, QueryHeight, QueryUnreceivedPacketsRequest, + IncludeProof, PageRequest, Qualified, QueryChannelRequest, QueryClientStateRequest, + QueryConnectionRequest, QueryConsensusStateHeightsRequest, QueryConsensusStateRequest, + QueryHeight, QueryUnreceivedPacketsRequest, }; use ibc_relayer::client_state::AnyClientState; use ibc_relayer::connection::ConnectionMsgType; @@ -17,6 +19,7 @@ use ibc_relayer::event::{ connection_open_ack_try_from_abci_event, connection_open_try_try_from_abci_event, extract_packet_and_write_ack_from_tx, }; +use ibc_relayer::light_client::AnyHeader; use ibc_relayer::link::packet_events::query_write_ack_events; use ibc_relayer::path::PathIdentifiers; use ibc_relayer_all_in_one::one_for_all::traits::chain::{OfaChain, OfaIbcChain}; @@ -30,8 +33,10 @@ use ibc_relayer_runtime::tokio::logger::tracing::TracingLogger; use ibc_relayer_runtime::tokio::logger::value::LogValue; use ibc_relayer_types::clients::ics07_tendermint::client_state::ClientState; use ibc_relayer_types::clients::ics07_tendermint::consensus_state::ConsensusState; +use ibc_relayer_types::clients::ics07_tendermint::header::Header as TendermintHeader; use ibc_relayer_types::core::ics02_client::events::CLIENT_ID_ATTRIBUTE_KEY; use ibc_relayer_types::core::ics02_client::msgs::create_client::MsgCreateClient; +use ibc_relayer_types::core::ics02_client::msgs::update_client::MsgUpdateClient; use ibc_relayer_types::core::ics03_connection::connection::ConnectionEnd; use ibc_relayer_types::core::ics03_connection::connection::Counterparty as ConnectionCounterparty; use ibc_relayer_types::core::ics03_connection::msgs::conn_open_ack::MsgConnectionOpenAck; @@ -221,12 +226,16 @@ where type OutgoingPacket = Packet; + type ClientState = ClientState; + type CreateClientPayloadOptions = ClientSettings; type CreateClientPayload = (ClientState, ConsensusState); type CreateClientEvent = CosmosCreateClientEvent; + type UpdateClientPayload = Vec; + type ConnectionVersion = ConnectionVersion; type ConnectionDetails = ConnectionEnd; @@ -319,6 +328,10 @@ where &packet.timeout_timestamp } + fn client_state_latest_height(client_state: &Self::ClientState) -> &Self::Height { + &client_state.latest_height + } + fn log_incoming_packet(packet: &Packet) -> LogValue<'_> { LogValue::Display(packet) } @@ -487,6 +500,34 @@ where .map_err(BaseError::join)? } + async fn query_client_state(&self, client_id: &ClientId) -> Result { + let chain_handle = self.handle.clone(); + + let client_id = client_id.clone(); + + self.runtime + .runtime + .runtime + .spawn_blocking(move || { + let (client_state, _) = chain_handle + .query_client_state( + QueryClientStateRequest { + client_id, + height: QueryHeight::Latest, + }, + IncludeProof::No, + ) + .map_err(BaseError::relayer)?; + + match client_state { + AnyClientState::Tendermint(client_state) => Ok(client_state), + _ => Err(BaseError::generic(eyre!("expected tendermint client state")).into()), + } + }) + .await + .map_err(BaseError::join)? + } + async fn query_consensus_state( &self, client_id: &ClientId, @@ -818,6 +859,111 @@ where .map_err(BaseError::join)? } + async fn build_update_client_payload( + &self, + trusted_height: &Height, + target_height: &Height, + client_state: ClientState, + ) -> Result, Self::Error> { + let trusted_height = *trusted_height; + let target_height = *target_height; + let chain_handle = self.handle.clone(); + + self.runtime + .runtime + .runtime + .spawn_blocking(move || { + let (header, support) = chain_handle + .build_header( + trusted_height, + target_height, + AnyClientState::Tendermint(client_state), + ) + .map_err(BaseError::relayer)?; + + let headers = iter::once(header) + .chain(support.into_iter()) + .map(|header| match header { + AnyHeader::Tendermint(header) => Ok(header), + _ => Err(BaseError::generic(eyre!("expect tendermint header")).into()), + }) + .collect::, Error>>()?; + + Ok(headers) + }) + .await + .map_err(BaseError::join)? + } + + async fn build_update_client_message( + &self, + client_id: &ClientId, + headers: Vec, + ) -> Result, Self::Error> { + let messages = headers + .into_iter() + .map(|header| { + let client_id = client_id.clone(); + let message = CosmosIbcMessage::new(None, move |signer| { + let message = MsgUpdateClient { + client_id: client_id.clone(), + header: header.clone().into(), + signer: signer.clone(), + }; + + Ok(message.to_any()) + }); + + message + }) + .collect(); + + Ok(messages) + } + + async fn find_consensus_state_height_before( + &self, + client_id: &ClientId, + target_height: &Height, + ) -> Result { + let client_id = client_id.clone(); + let target_height = *target_height; + + let chain_handle = self.handle.clone(); + + self.runtime + .runtime + .runtime + .spawn_blocking(move || { + let heights = { + let mut heights = chain_handle + .query_consensus_state_heights(QueryConsensusStateHeightsRequest { + client_id, + pagination: Some(PageRequest::all()), + }) + .map_err(BaseError::relayer)?; + + heights.sort_by_key(|&h| core::cmp::Reverse(h)); + + heights + }; + + let height = heights + .into_iter() + .find(|height| height < &target_height) + .ok_or_else(|| { + BaseError::generic(eyre!( + "no consensus state found that is smaller than target height {}", + target_height + )) + })?; + + Ok(height) + }) + .await + .map_err(BaseError::join)? + } + async fn build_connection_open_try_payload( &self, height: &Height, diff --git a/crates/relayer-cosmos/src/impls/relay.rs b/crates/relayer-cosmos/src/impls/relay.rs index f2ea6e2e5d..e330d6890c 100644 --- a/crates/relayer-cosmos/src/impls/relay.rs +++ b/crates/relayer-cosmos/src/impls/relay.rs @@ -2,7 +2,6 @@ use async_trait::async_trait; use eyre::eyre; use futures::channel::oneshot::{channel, Sender}; use ibc_relayer::chain::handle::ChainHandle; -use ibc_relayer::foreign_client::ForeignClient; use ibc_relayer_all_in_one::one_for_all::traits::chain::OfaChain; use ibc_relayer_all_in_one::one_for_all::traits::relay::OfaRelay; use ibc_relayer_all_in_one::one_for_all::types::chain::OfaChainWrapper; @@ -12,14 +11,11 @@ use ibc_relayer_runtime::tokio::error::Error as TokioError; use ibc_relayer_runtime::tokio::logger::tracing::TracingLogger; use ibc_relayer_types::core::ics04_channel::packet::Packet; use ibc_relayer_types::core::ics24_host::identifier::{ChannelId, ClientId, ConnectionId}; -use ibc_relayer_types::tx_msg::Msg; -use ibc_relayer_types::Height; use crate::contexts::chain::CosmosChain; use crate::contexts::relay::CosmosRelay; use crate::types::batch::CosmosBatchSender; use crate::types::error::{BaseError, Error}; -use crate::types::message::CosmosIbcMessage; pub struct PacketLock { pub release_sender: Option>, @@ -74,11 +70,11 @@ where } fn src_client_id(&self) -> &ClientId { - &self.dst_to_src_client.id + &self.src_client_id } fn dst_client_id(&self) -> &ClientId { - &self.src_to_dst_client.id + &self.dst_client_id } fn src_chain(&self) -> &OfaChainWrapper { @@ -89,36 +85,6 @@ where &self.dst_chain } - async fn build_src_update_client_messages( - &self, - height: &Height, - ) -> Result, Self::Error> { - let height = *height; - let client = self.dst_to_src_client.clone(); - - self.runtime - .runtime - .runtime - .spawn_blocking(move || build_update_client_messages(&client, height)) - .await - .map_err(BaseError::join)? - } - - async fn build_dst_update_client_messages( - &self, - height: &Height, - ) -> Result, Self::Error> { - let height = *height; - let client = self.src_to_dst_client.clone(); - - self.runtime - .runtime - .runtime - .spawn_blocking(move || build_update_client_messages(&client, height)) - .await - .map_err(BaseError::join)? - } - async fn try_acquire_packet_lock<'a>(&'a self, packet: &'a Packet) -> Option { let packet_key = ( packet.source_channel.clone(), @@ -218,29 +184,3 @@ where &self.dst_chain_message_batch_sender } } - -fn build_update_client_messages( - foreign_client: &ForeignClient, - height: Height, -) -> Result, Error> -where - SrcChain: ChainHandle, - DstChain: ChainHandle, -{ - let messages = foreign_client - .build_update_client_with_trusted(height, None) - .map_err(BaseError::foreign_client)?; - - let ibc_messages = messages - .into_iter() - .map(|update_message| { - CosmosIbcMessage::new(Some(height), move |signer| { - let mut update_message = update_message.clone(); - update_message.signer = signer.clone(); - Ok(update_message.to_any()) - }) - }) - .collect(); - - Ok(ibc_messages) -} diff --git a/crates/relayer/src/light_client.rs b/crates/relayer/src/light_client.rs index 5f19bba177..4a98aa6acb 100644 --- a/crates/relayer/src/light_client.rs +++ b/crates/relayer/src/light_client.rs @@ -81,6 +81,7 @@ pub fn decode_header(header_bytes: &[u8]) -> Result, Error> { #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] #[allow(clippy::large_enum_variant)] +#[non_exhaustive] pub enum AnyHeader { Tendermint(TendermintHeader), }