use core::fmt::{Display, Error as FmtError, Formatter};
use std::collections::HashMap;
use std::sync::{Arc, RwLock, RwLockReadGuard};
use crossbeam_channel as channel;
use tracing::{debug, Span};
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::events::UpdateClient;
use ibc_relayer_types::core::ics03_connection::connection::ConnectionEnd;
use ibc_relayer_types::core::ics03_connection::connection::IdentifiedConnectionEnd;
use ibc_relayer_types::core::ics03_connection::version::Version;
use ibc_relayer_types::core::ics04_channel::channel::ChannelEnd;
use ibc_relayer_types::core::ics04_channel::channel::IdentifiedChannelEnd;
use ibc_relayer_types::core::ics04_channel::packet::{PacketMsgType, Sequence};
use ibc_relayer_types::core::ics23_commitment::commitment::CommitmentPrefix;
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::Proofs;
use ibc_relayer_types::signer::Signer;
use ibc_relayer_types::Height;
use crate::account::Balance;
use crate::chain::client::ClientSettings;
use crate::chain::endpoint::{ChainStatus, HealthCheck};
use crate::chain::handle::{ChainHandle, ChainRequest, Subscription};
use crate::chain::requests::*;
use crate::chain::tracking::TrackedMsgs;
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;
use crate::light_client::AnyHeader;
use crate::misbehaviour::MisbehaviourEvidence;
use crate::util::lock::LockExt;
#[derive(Debug, Clone)]
pub struct CountingChainHandle<Handle> {
inner: Handle,
metrics: Arc<RwLock<HashMap<String, u64>>>,
}
impl<Handle> CountingChainHandle<Handle> {
pub fn new(handle: Handle) -> Self {
Self {
inner: handle,
metrics: Arc::new(RwLock::new(HashMap::new())),
}
}
fn inner(&self) -> &Handle {
&self.inner
}
pub fn metrics(&self) -> RwLockReadGuard<'_, HashMap<String, u64>> {
self.metrics.acquire_read()
}
fn inc_metric(&self, key: &str) {
let mut metrics = self.metrics.acquire_write();
if let Some(entry) = metrics.get_mut(key) {
*entry += 1;
} else {
metrics.insert(key.to_string(), 1);
}
}
}
impl<Handle: ChainHandle> Display for CountingChainHandle<Handle> {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
write!(
f,
"CountingChainHandle {{ chain_id: {} }}",
self.inner().id()
)
}
}
impl<Handle: ChainHandle> ChainHandle for CountingChainHandle<Handle> {
fn new(chain_id: ChainId, sender: channel::Sender<(Span, ChainRequest)>) -> Self {
Self::new(Handle::new(chain_id, sender))
}
fn id(&self) -> ChainId {
self.inner().id()
}
fn shutdown(&self) -> Result<(), Error> {
debug!(
"shutting down chain handle {}. usage metrics for chain: \n {:?}",
self.id(),
self.metrics()
);
self.inner().shutdown()
}
fn health_check(&self) -> Result<HealthCheck, Error> {
self.inc_metric("health_check");
self.inner().health_check()
}
fn subscribe(&self) -> Result<Subscription, Error> {
self.inc_metric("subscribe");
self.inner().subscribe()
}
fn send_messages_and_wait_commit(
&self,
tracked_msgs: TrackedMsgs,
) -> Result<Vec<IbcEventWithHeight>, Error> {
self.inc_metric("send_messages_and_wait_commit");
self.inner().send_messages_and_wait_commit(tracked_msgs)
}
fn send_messages_and_wait_check_tx(
&self,
tracked_msgs: TrackedMsgs,
) -> Result<Vec<tendermint_rpc::endpoint::broadcast::tx_sync::Response>, Error> {
self.inc_metric("send_messages_and_wait_check_tx");
self.inner().send_messages_and_wait_check_tx(tracked_msgs)
}
fn get_signer(&self) -> Result<Signer, Error> {
self.inc_metric("get_signer");
self.inner().get_signer()
}
fn config(&self) -> Result<ChainConfig, Error> {
self.inc_metric("config");
self.inner().config()
}
fn get_key(&self) -> Result<AnySigningKeyPair, Error> {
self.inc_metric("get_key");
self.inner().get_key()
}
fn add_key(&self, key_name: String, key: AnySigningKeyPair) -> Result<(), Error> {
self.inc_metric("add_key");
self.inner().add_key(key_name, key)
}
fn ibc_version(&self) -> Result<Option<semver::Version>, Error> {
self.inc_metric("ibc_version");
self.inner().ibc_version()
}
fn query_balance(
&self,
key_name: Option<String>,
denom: Option<String>,
) -> Result<Balance, Error> {
self.inc_metric("query_balance");
self.inner().query_balance(key_name, denom)
}
fn query_all_balances(&self, key_name: Option<String>) -> Result<Vec<Balance>, Error> {
self.inc_metric("query_all_balance");
self.inner().query_all_balances(key_name)
}
fn query_denom_trace(&self, hash: String) -> Result<DenomTrace, Error> {
self.inc_metric("query_denom_trace");
self.inner().query_denom_trace(hash)
}
fn query_application_status(&self) -> Result<ChainStatus, Error> {
self.inc_metric("query_application_status");
self.inner().query_application_status()
}
fn query_latest_height(&self) -> Result<Height, Error> {
self.inc_metric("query_latest_height");
self.inner().query_latest_height()
}
fn query_clients(
&self,
request: QueryClientStatesRequest,
) -> Result<Vec<IdentifiedAnyClientState>, Error> {
self.inc_metric("query_clients");
self.inner().query_clients(request)
}
fn query_client_state(
&self,
request: QueryClientStateRequest,
include_proof: IncludeProof,
) -> Result<(AnyClientState, Option<MerkleProof>), Error> {
self.inc_metric(&format!(
"query_client_state({}, {})",
request.client_id, request.height
));
self.inner().query_client_state(request, include_proof)
}
fn query_client_connections(
&self,
request: QueryClientConnectionsRequest,
) -> Result<Vec<ConnectionId>, Error> {
self.inc_metric("query_client_connections");
self.inner().query_client_connections(request)
}
fn query_consensus_state_heights(
&self,
request: QueryConsensusStateHeightsRequest,
) -> Result<Vec<Height>, Error> {
self.inner().query_consensus_state_heights(request)
}
fn query_consensus_state(
&self,
request: QueryConsensusStateRequest,
include_proof: IncludeProof,
) -> Result<(AnyConsensusState, Option<MerkleProof>), Error> {
self.inc_metric("query_consensus_state");
self.inner().query_consensus_state(request, include_proof)
}
fn query_upgraded_client_state(
&self,
request: QueryUpgradedClientStateRequest,
) -> Result<(AnyClientState, MerkleProof), Error> {
self.inc_metric("query_upgraded_client_state");
self.inner().query_upgraded_client_state(request)
}
fn query_upgraded_consensus_state(
&self,
request: QueryUpgradedConsensusStateRequest,
) -> Result<(AnyConsensusState, MerkleProof), Error> {
self.inc_metric("query_upgraded_consensus_state");
self.inner().query_upgraded_consensus_state(request)
}
fn query_commitment_prefix(&self) -> Result<CommitmentPrefix, Error> {
self.inc_metric("query_commitment_prefix");
self.inner().query_commitment_prefix()
}
fn query_compatible_versions(&self) -> Result<Vec<Version>, Error> {
self.inc_metric("query_compatible_versions");
self.inner().query_compatible_versions()
}
fn query_connection(
&self,
request: QueryConnectionRequest,
include_proof: IncludeProof,
) -> Result<(ConnectionEnd, Option<MerkleProof>), Error> {
self.inc_metric("query_connection");
self.inner().query_connection(request, include_proof)
}
fn query_connections(
&self,
request: QueryConnectionsRequest,
) -> Result<Vec<IdentifiedConnectionEnd>, Error> {
self.inc_metric("query_connections");
self.inner().query_connections(request)
}
fn query_connection_channels(
&self,
request: QueryConnectionChannelsRequest,
) -> Result<Vec<IdentifiedChannelEnd>, Error> {
self.inc_metric("query_connection_channels");
self.inner().query_connection_channels(request)
}
fn query_next_sequence_receive(
&self,
request: QueryNextSequenceReceiveRequest,
include_proof: IncludeProof,
) -> Result<(Sequence, Option<MerkleProof>), Error> {
self.inc_metric("query_next_sequence_receive");
self.inner()
.query_next_sequence_receive(request, include_proof)
}
fn query_channels(
&self,
request: QueryChannelsRequest,
) -> Result<Vec<IdentifiedChannelEnd>, Error> {
self.inc_metric("query_channels");
self.inner().query_channels(request)
}
fn query_channel(
&self,
request: QueryChannelRequest,
include_proof: IncludeProof,
) -> Result<(ChannelEnd, Option<MerkleProof>), Error> {
self.inc_metric("query_channel");
self.inner().query_channel(request, include_proof)
}
fn query_channel_client_state(
&self,
request: QueryChannelClientStateRequest,
) -> Result<Option<IdentifiedAnyClientState>, Error> {
self.inc_metric("query_channel_client_state");
self.inner().query_channel_client_state(request)
}
fn build_header(
&self,
trusted_height: Height,
target_height: Height,
client_state: AnyClientState,
) -> Result<(AnyHeader, Vec<AnyHeader>), Error> {
self.inc_metric("build_header");
self.inner()
.build_header(trusted_height, target_height, client_state)
}
fn build_client_state(
&self,
height: Height,
options: ClientSettings,
) -> Result<AnyClientState, Error> {
self.inc_metric("build_client_state");
self.inner().build_client_state(height, options)
}
fn build_consensus_state(
&self,
trusted: Height,
target: Height,
client_state: AnyClientState,
) -> Result<AnyConsensusState, Error> {
self.inc_metric("build_consensus_state");
self.inner()
.build_consensus_state(trusted, target, client_state)
}
fn check_misbehaviour(
&self,
update: UpdateClient,
client_state: AnyClientState,
) -> Result<Option<MisbehaviourEvidence>, Error> {
self.inc_metric("check_misbehaviour");
self.inner().check_misbehaviour(update, client_state)
}
fn build_connection_proofs_and_client_state(
&self,
message_type: ConnectionMsgType,
connection_id: &ConnectionId,
client_id: &ClientId,
height: Height,
) -> Result<(Option<AnyClientState>, Proofs), Error> {
self.inc_metric("build_connection_proofs_and_client_state");
self.inner().build_connection_proofs_and_client_state(
message_type,
connection_id,
client_id,
height,
)
}
fn build_channel_proofs(
&self,
port_id: &PortId,
channel_id: &ChannelId,
height: Height,
) -> Result<Proofs, Error> {
self.inc_metric("build_channel_proofs");
self.inner()
.build_channel_proofs(port_id, channel_id, height)
}
fn build_packet_proofs(
&self,
packet_type: PacketMsgType,
port_id: &PortId,
channel_id: &ChannelId,
sequence: Sequence,
height: Height,
) -> Result<Proofs, Error> {
self.inc_metric("build_packet_proofs");
self.inner()
.build_packet_proofs(packet_type, port_id, channel_id, sequence, height)
}
fn query_packet_commitment(
&self,
request: QueryPacketCommitmentRequest,
include_proof: IncludeProof,
) -> Result<(Vec<u8>, Option<MerkleProof>), Error> {
self.inc_metric("query_packet_commitment");
self.inner().query_packet_commitment(request, include_proof)
}
fn query_packet_commitments(
&self,
request: QueryPacketCommitmentsRequest,
) -> Result<(Vec<Sequence>, Height), Error> {
self.inc_metric("query_packet_commitments");
self.inner().query_packet_commitments(request)
}
fn query_packet_receipt(
&self,
request: QueryPacketReceiptRequest,
include_proof: IncludeProof,
) -> Result<(Vec<u8>, Option<MerkleProof>), Error> {
self.inc_metric("query_packet_receipt");
self.inner().query_packet_receipt(request, include_proof)
}
fn query_unreceived_packets(
&self,
request: QueryUnreceivedPacketsRequest,
) -> Result<Vec<Sequence>, Error> {
self.inc_metric("query_unreceived_packets");
self.inner().query_unreceived_packets(request)
}
fn query_packet_acknowledgement(
&self,
request: QueryPacketAcknowledgementRequest,
include_proof: IncludeProof,
) -> Result<(Vec<u8>, Option<MerkleProof>), Error> {
self.inc_metric("query_packet_acknowledgement");
self.inner()
.query_packet_acknowledgement(request, include_proof)
}
fn query_packet_acknowledgements(
&self,
request: QueryPacketAcknowledgementsRequest,
) -> Result<(Vec<Sequence>, Height), Error> {
self.inc_metric("query_packet_acknowledgements");
self.inner().query_packet_acknowledgements(request)
}
fn query_unreceived_acknowledgements(
&self,
request: QueryUnreceivedAcksRequest,
) -> Result<Vec<Sequence>, Error> {
self.inc_metric("query_unreceived_acknowledgement");
self.inner().query_unreceived_acknowledgements(request)
}
fn query_txs(&self, request: QueryTxRequest) -> Result<Vec<IbcEventWithHeight>, Error> {
self.inc_metric("query_txs");
self.inner().query_txs(request)
}
fn query_packet_events(
&self,
request: QueryPacketEventDataRequest,
) -> Result<Vec<IbcEventWithHeight>, Error> {
self.inc_metric("query_packet_events");
self.inner().query_packet_events(request)
}
fn query_host_consensus_state(
&self,
request: QueryHostConsensusStateRequest,
) -> Result<AnyConsensusState, Error> {
self.inc_metric("query_host_consensus_state");
self.inner.query_host_consensus_state(request)
}
fn maybe_register_counterparty_payee(
&self,
channel_id: ChannelId,
port_id: PortId,
counterparty_payee: Signer,
) -> Result<(), Error> {
self.inc_metric("maybe_register_counterparty_payee");
self.inner
.maybe_register_counterparty_payee(channel_id, port_id, counterparty_payee)
}
fn cross_chain_query(
&self,
request: Vec<CrossChainQueryRequest>,
) -> Result<Vec<CrossChainQueryResponse>, Error> {
self.inc_metric("cross_chain_query");
self.inner.cross_chain_query(request)
}
fn query_incentivized_packet(
&self,
request: QueryIncentivizedPacketRequest,
) -> Result<QueryIncentivizedPacketResponse, Error> {
self.inc_metric("query_incentivized_packet");
self.inner.query_incentivized_packet(request)
}
}