use alloc::sync::Arc;
use ibc_proto::ibc::core::channel::v1::{QueryUpgradeErrorRequest, QueryUpgradeRequest};
use ibc_relayer_types::applications::ics28_ccv::msgs::{ConsumerChain, ConsumerId};
use ibc_relayer_types::core::ics02_client::height::Height;
use tokio::runtime::Runtime as TokioRuntime;
use ibc_proto::ibc::apps::fee::v1::{
QueryIncentivizedPacketRequest, QueryIncentivizedPacketResponse,
};
use ibc_relayer_types::applications::ics31_icq::response::CrossChainQueryResponse;
use ibc_relayer_types::core::ics02_client::client_state::ClientState;
use ibc_relayer_types::core::ics02_client::consensus_state::ConsensusState;
use ibc_relayer_types::core::ics02_client::events::UpdateClient;
use ibc_relayer_types::core::ics02_client::header::{AnyHeader, Header};
use ibc_relayer_types::core::ics03_connection::connection::{
ConnectionEnd, IdentifiedConnectionEnd, State,
};
use ibc_relayer_types::core::ics03_connection::version::{get_compatible_versions, Version};
use ibc_relayer_types::core::ics04_channel::channel::{ChannelEnd, IdentifiedChannelEnd};
use ibc_relayer_types::core::ics04_channel::packet::{PacketMsgType, Sequence};
use ibc_relayer_types::core::ics04_channel::upgrade::{ErrorReceipt, Upgrade};
use ibc_relayer_types::core::ics23_commitment::commitment::{
CommitmentPrefix, CommitmentProofBytes,
};
use ibc_relayer_types::core::ics23_commitment::merkle::MerkleProof;
use ibc_relayer_types::core::ics24_host::identifier::{
ChainId, ChannelId, ClientId, ConnectionId, PortId,
};
use ibc_relayer_types::proofs::{ConsensusProof, Proofs};
use ibc_relayer_types::signer::Signer;
use ibc_relayer_types::timestamp::Timestamp;
use ibc_relayer_types::Height as ICSHeight;
use tendermint_rpc::endpoint::broadcast::tx_sync::Response as TxResponse;
use crate::account::Balance;
use crate::chain::client::ClientSettings;
use crate::chain::handle::Subscription;
use crate::chain::requests::*;
use crate::chain::tracking::TrackedMsgs;
use crate::chain::version::Specs;
use crate::client_state::{AnyClientState, IdentifiedAnyClientState};
use crate::config::ChainConfig;
use crate::connection::ConnectionMsgType;
use crate::consensus_state::AnyConsensusState;
use crate::denom::DenomTrace;
use crate::error::Error;
use crate::event::IbcEventWithHeight;
use crate::keyring::{AnySigningKeyPair, KeyRing, SigningKeyPairSized};
use crate::misbehaviour::MisbehaviourEvidence;
#[derive(Debug)]
pub enum HealthCheck {
Healthy,
Unhealthy(Box<Error>),
}
#[derive(Clone, Debug)]
pub struct ChainStatus {
pub height: ICSHeight,
pub timestamp: Timestamp,
}
pub trait ChainEndpoint: Sized {
type LightBlock: Send + Sync;
type Header: Header + Into<AnyHeader>;
type ConsensusState: ConsensusState + Into<AnyConsensusState>;
type ClientState: ClientState + Into<AnyClientState>;
type Time;
type SigningKeyPair: SigningKeyPairSized + Into<AnySigningKeyPair>;
fn id(&self) -> &ChainId;
fn config(&self) -> ChainConfig;
fn bootstrap(config: ChainConfig, rt: Arc<TokioRuntime>) -> Result<Self, Error>;
fn shutdown(self) -> Result<(), Error>;
fn health_check(&mut self) -> Result<HealthCheck, Error>;
fn subscribe(&mut self) -> Result<Subscription, Error>;
fn keybase(&self) -> &KeyRing<Self::SigningKeyPair>;
fn keybase_mut(&mut self) -> &mut KeyRing<Self::SigningKeyPair>;
fn get_signer(&self) -> Result<Signer, Error>;
fn get_key(&self) -> Result<Self::SigningKeyPair, Error>;
fn add_key(&mut self, key_name: &str, key_pair: Self::SigningKeyPair) -> Result<(), Error> {
self.keybase_mut()
.add_key(key_name, key_pair)
.map_err(Error::key_base)?;
Ok(())
}
fn version_specs(&self) -> Result<Specs, Error>;
fn send_messages_and_wait_commit(
&mut self,
tracked_msgs: TrackedMsgs,
) -> Result<Vec<IbcEventWithHeight>, Error>;
fn send_messages_and_wait_check_tx(
&mut self,
tracked_msgs: TrackedMsgs,
) -> Result<Vec<TxResponse>, Error>;
fn verify_header(
&mut self,
trusted: ICSHeight,
target: ICSHeight,
client_state: &AnyClientState,
) -> Result<Self::LightBlock, Error>;
fn check_misbehaviour(
&mut self,
update: &UpdateClient,
client_state: &AnyClientState,
) -> Result<Option<MisbehaviourEvidence>, Error>;
fn query_balance(&self, key_name: Option<&str>, denom: Option<&str>) -> Result<Balance, Error>;
fn query_all_balances(&self, key_name: Option<&str>) -> Result<Vec<Balance>, Error>;
fn query_denom_trace(&self, hash: String) -> Result<DenomTrace, Error>;
fn query_commitment_prefix(&self) -> Result<CommitmentPrefix, Error>;
fn query_compatible_versions(&self) -> Result<Vec<Version>, Error> {
Ok(get_compatible_versions())
}
fn query_application_status(&self) -> Result<ChainStatus, Error>;
fn query_clients(
&self,
request: QueryClientStatesRequest,
) -> Result<Vec<IdentifiedAnyClientState>, Error>;
fn query_client_state(
&self,
request: QueryClientStateRequest,
include_proof: IncludeProof,
) -> Result<(AnyClientState, Option<MerkleProof>), Error>;
fn query_consensus_state(
&self,
request: QueryConsensusStateRequest,
include_proof: IncludeProof,
) -> Result<(AnyConsensusState, Option<MerkleProof>), Error>;
fn query_consensus_state_heights(
&self,
request: QueryConsensusStateHeightsRequest,
) -> Result<Vec<ICSHeight>, Error>;
fn query_upgraded_client_state(
&self,
request: QueryUpgradedClientStateRequest,
) -> Result<(AnyClientState, MerkleProof), Error>;
fn query_upgraded_consensus_state(
&self,
request: QueryUpgradedConsensusStateRequest,
) -> Result<(AnyConsensusState, MerkleProof), Error>;
fn query_connections(
&self,
request: QueryConnectionsRequest,
) -> Result<Vec<IdentifiedConnectionEnd>, Error>;
fn query_client_connections(
&self,
request: QueryClientConnectionsRequest,
) -> Result<Vec<ConnectionId>, Error>;
fn query_connection(
&self,
request: QueryConnectionRequest,
include_proof: IncludeProof,
) -> Result<(ConnectionEnd, Option<MerkleProof>), Error>;
fn query_connection_channels(
&self,
request: QueryConnectionChannelsRequest,
) -> Result<Vec<IdentifiedChannelEnd>, Error>;
fn query_channels(
&self,
request: QueryChannelsRequest,
) -> Result<Vec<IdentifiedChannelEnd>, Error>;
fn query_channel(
&self,
request: QueryChannelRequest,
include_proof: IncludeProof,
) -> Result<(ChannelEnd, Option<MerkleProof>), Error>;
fn query_channel_client_state(
&self,
request: QueryChannelClientStateRequest,
) -> Result<Option<IdentifiedAnyClientState>, Error>;
fn query_packet_commitment(
&self,
request: QueryPacketCommitmentRequest,
include_proof: IncludeProof,
) -> Result<(Vec<u8>, Option<MerkleProof>), Error>;
fn query_packet_commitments(
&self,
request: QueryPacketCommitmentsRequest,
) -> Result<(Vec<Sequence>, ICSHeight), Error>;
fn query_packet_receipt(
&self,
request: QueryPacketReceiptRequest,
include_proof: IncludeProof,
) -> Result<(Vec<u8>, Option<MerkleProof>), Error>;
fn query_unreceived_packets(
&self,
request: QueryUnreceivedPacketsRequest,
) -> Result<Vec<Sequence>, Error>;
fn query_packet_acknowledgement(
&self,
request: QueryPacketAcknowledgementRequest,
include_proof: IncludeProof,
) -> Result<(Vec<u8>, Option<MerkleProof>), Error>;
fn query_packet_acknowledgements(
&self,
request: QueryPacketAcknowledgementsRequest,
) -> Result<(Vec<Sequence>, ICSHeight), Error>;
fn query_unreceived_acknowledgements(
&self,
request: QueryUnreceivedAcksRequest,
) -> Result<Vec<Sequence>, Error>;
fn query_next_sequence_receive(
&self,
request: QueryNextSequenceReceiveRequest,
include_proof: IncludeProof,
) -> Result<(Sequence, Option<MerkleProof>), Error>;
fn query_txs(&self, request: QueryTxRequest) -> Result<Vec<IbcEventWithHeight>, Error>;
fn query_packet_events(
&self,
request: QueryPacketEventDataRequest,
) -> Result<Vec<IbcEventWithHeight>, Error>;
fn query_host_consensus_state(
&self,
request: QueryHostConsensusStateRequest,
) -> Result<Self::ConsensusState, Error>;
fn build_client_state(
&self,
height: ICSHeight,
settings: ClientSettings,
) -> Result<Self::ClientState, Error>;
fn build_consensus_state(
&self,
light_block: Self::LightBlock,
) -> Result<Self::ConsensusState, Error>;
fn build_header(
&mut self,
trusted_height: ICSHeight,
target_height: ICSHeight,
client_state: &AnyClientState,
) -> Result<(Self::Header, Vec<Self::Header>), Error>;
fn build_connection_proofs_and_client_state(
&self,
message_type: ConnectionMsgType,
connection_id: &ConnectionId,
client_id: &ClientId,
height: ICSHeight,
) -> Result<(Option<AnyClientState>, Proofs), Error> {
let (connection_end, maybe_connection_proof) = self.query_connection(
QueryConnectionRequest {
connection_id: connection_id.clone(),
height: QueryHeight::Specific(height),
},
IncludeProof::Yes,
)?;
let Some(connection_proof) = maybe_connection_proof else {
return Err(Error::queried_proof_not_found());
};
match message_type {
ConnectionMsgType::OpenTry => {
if !connection_end.state_matches(&State::Init)
&& !connection_end.state_matches(&State::TryOpen)
{
return Err(Error::bad_connection_state());
}
}
ConnectionMsgType::OpenAck => {
if !connection_end.state_matches(&State::TryOpen)
&& !connection_end.state_matches(&State::Open)
{
return Err(Error::bad_connection_state());
}
}
ConnectionMsgType::OpenConfirm => {
if !connection_end.state_matches(&State::Open) {
return Err(Error::bad_connection_state());
}
}
}
let mut client_state = None;
let mut client_proof = None;
let mut consensus_proof = None;
match message_type {
ConnectionMsgType::OpenTry | ConnectionMsgType::OpenAck => {
let (client_state_value, maybe_client_state_proof) = self.query_client_state(
QueryClientStateRequest {
client_id: client_id.clone(),
height: QueryHeight::Specific(height),
},
IncludeProof::Yes,
)?;
let Some(client_state_proof) = maybe_client_state_proof else {
return Err(Error::queried_proof_not_found());
};
client_proof = Some(
CommitmentProofBytes::try_from(client_state_proof)
.map_err(Error::malformed_proof)?,
);
let consensus_state_proof = {
let (_, maybe_consensus_state_proof) = self.query_consensus_state(
QueryConsensusStateRequest {
client_id: client_id.clone(),
consensus_height: client_state_value.latest_height(),
query_height: QueryHeight::Specific(height),
},
IncludeProof::Yes,
)?;
let Some(consensus_state_proof) = maybe_consensus_state_proof else {
return Err(Error::queried_proof_not_found());
};
consensus_state_proof
};
consensus_proof = Option::from(
ConsensusProof::new(
CommitmentProofBytes::try_from(consensus_state_proof)
.map_err(Error::malformed_proof)?,
client_state_value.latest_height(),
)
.map_err(Error::consensus_proof)?,
);
client_state = Some(client_state_value);
}
_ => {}
}
Ok((
client_state,
Proofs::new(
CommitmentProofBytes::try_from(connection_proof).map_err(Error::malformed_proof)?,
client_proof,
consensus_proof,
None, None,
height.increment(),
)
.map_err(Error::malformed_proof)?,
))
}
fn build_channel_proofs(
&self,
port_id: &PortId,
channel_id: &ChannelId,
height: ICSHeight,
) -> Result<Proofs, Error> {
let (_, maybe_channel_proof) = self.query_channel(
QueryChannelRequest {
port_id: port_id.clone(),
channel_id: channel_id.clone(),
height: QueryHeight::Specific(height),
},
IncludeProof::Yes,
)?;
let Some(channel_proof) = maybe_channel_proof else {
return Err(Error::queried_proof_not_found());
};
let channel_proof_bytes =
CommitmentProofBytes::try_from(channel_proof).map_err(Error::malformed_proof)?;
Proofs::new(
channel_proof_bytes,
None,
None,
None,
None,
height.increment(),
)
.map_err(Error::malformed_proof)
}
fn build_packet_proofs(
&self,
packet_type: PacketMsgType,
port_id: PortId,
channel_id: ChannelId,
sequence: Sequence,
height: ICSHeight,
) -> Result<Proofs, Error> {
let (maybe_packet_proof, channel_proof) = match packet_type {
PacketMsgType::Recv => {
let (_, maybe_packet_proof) = self.query_packet_commitment(
QueryPacketCommitmentRequest {
port_id,
channel_id,
sequence,
height: QueryHeight::Specific(height),
},
IncludeProof::Yes,
)?;
(maybe_packet_proof, None)
}
PacketMsgType::Ack => {
let (_, maybe_packet_proof) = self.query_packet_acknowledgement(
QueryPacketAcknowledgementRequest {
port_id,
channel_id,
sequence,
height: QueryHeight::Specific(height),
},
IncludeProof::Yes,
)?;
(maybe_packet_proof, None)
}
PacketMsgType::TimeoutUnordered => {
let (_, maybe_packet_proof) = self.query_packet_receipt(
QueryPacketReceiptRequest {
port_id,
channel_id,
sequence,
height: QueryHeight::Specific(height),
},
IncludeProof::Yes,
)?;
(maybe_packet_proof, None)
}
PacketMsgType::TimeoutOrdered => {
let (_, maybe_packet_proof) = self.query_next_sequence_receive(
QueryNextSequenceReceiveRequest {
port_id,
channel_id,
height: QueryHeight::Specific(height),
},
IncludeProof::Yes,
)?;
(maybe_packet_proof, None)
}
PacketMsgType::TimeoutOnCloseUnordered => {
let channel_proof = {
let (_, maybe_channel_proof) = self.query_channel(
QueryChannelRequest {
port_id: port_id.clone(),
channel_id: channel_id.clone(),
height: QueryHeight::Specific(height),
},
IncludeProof::Yes,
)?;
let Some(channel_merkle_proof) = maybe_channel_proof else {
return Err(Error::queried_proof_not_found());
};
Some(
CommitmentProofBytes::try_from(channel_merkle_proof)
.map_err(Error::malformed_proof)?,
)
};
let (_, maybe_packet_proof) = self.query_packet_receipt(
QueryPacketReceiptRequest {
port_id,
channel_id,
sequence,
height: QueryHeight::Specific(height),
},
IncludeProof::Yes,
)?;
(maybe_packet_proof, channel_proof)
}
PacketMsgType::TimeoutOnCloseOrdered => {
let channel_proof = {
let (_, maybe_channel_proof) = self.query_channel(
QueryChannelRequest {
port_id: port_id.clone(),
channel_id: channel_id.clone(),
height: QueryHeight::Specific(height),
},
IncludeProof::Yes,
)?;
let Some(channel_merkle_proof) = maybe_channel_proof else {
return Err(Error::queried_proof_not_found());
};
Some(
CommitmentProofBytes::try_from(channel_merkle_proof)
.map_err(Error::malformed_proof)?,
)
};
let (_, maybe_packet_proof) = self.query_next_sequence_receive(
QueryNextSequenceReceiveRequest {
port_id,
channel_id,
height: QueryHeight::Specific(height),
},
IncludeProof::Yes,
)?;
(maybe_packet_proof, channel_proof)
}
};
let Some(packet_proof) = maybe_packet_proof else {
return Err(Error::queried_proof_not_found());
};
let proofs = Proofs::new(
CommitmentProofBytes::try_from(packet_proof).map_err(Error::malformed_proof)?,
None,
None,
None,
channel_proof,
height.increment(),
)
.map_err(Error::malformed_proof)?;
Ok(proofs)
}
fn maybe_register_counterparty_payee(
&mut self,
channel_id: &ChannelId,
port_id: &PortId,
counterparty_payee: &Signer,
) -> Result<(), Error>;
fn cross_chain_query(
&self,
requests: Vec<CrossChainQueryRequest>,
) -> Result<Vec<CrossChainQueryResponse>, Error>;
fn query_incentivized_packet(
&self,
request: QueryIncentivizedPacketRequest,
) -> Result<QueryIncentivizedPacketResponse, Error>;
fn query_consumer_chains(&self) -> Result<Vec<ConsumerChain>, Error>;
fn query_upgrade(
&self,
request: QueryUpgradeRequest,
height: Height,
include_proof: IncludeProof,
) -> Result<(Upgrade, Option<MerkleProof>), Error>;
fn query_upgrade_error(
&self,
request: QueryUpgradeErrorRequest,
height: Height,
include_proof: IncludeProof,
) -> Result<(ErrorReceipt, Option<MerkleProof>), Error>;
fn query_ccv_consumer_id(&self, client_id: ClientId) -> Result<ConsumerId, Error>;
}