substrate_relay_helper/messages/
metrics.rs1use crate::TaggedAccount;
20
21use bp_relayers::{RewardsAccountOwner, RewardsAccountParams};
22use codec::{Decode, EncodeLike};
23use frame_system::AccountInfo;
24use messages_relay::Labeled;
25use pallet_balances::AccountData;
26use relay_substrate_client::{
27 metrics::{FixedU128OrOne, FloatStorageValue, FloatStorageValueMetric},
28 AccountIdOf, BalanceOf, Chain, ChainWithBalances, ChainWithMessages, ChainWithRewards, Client,
29 Error as SubstrateError, NonceOf,
30};
31use relay_utils::metrics::{MetricsParams, StandaloneMetric};
32use sp_core::storage::StorageData;
33use sp_runtime::{FixedPointNumber, FixedU128};
34use std::{fmt::Debug, marker::PhantomData};
35
36pub async fn add_relay_balances_metrics<C: ChainWithBalances>(
38 client: impl Client<C>,
39 metrics: &MetricsParams,
40 relay_accounts: &Vec<TaggedAccount<AccountIdOf<C>>>,
41) -> anyhow::Result<()>
42where
43 BalanceOf<C>: Into<u128> + std::fmt::Debug,
44{
45 if relay_accounts.is_empty() {
46 return Ok(())
47 }
48
49 let token_decimals = client
51 .token_decimals()
52 .await?
53 .inspect(|token_decimals| {
54 log::info!(target: "bridge", "Read `tokenDecimals` for {}: {}", C::NAME, token_decimals);
55 })
56 .unwrap_or_else(|| {
57 log::info!(target: "bridge", "Using default (zero) `tokenDecimals` value for {}", C::NAME);
60 0
61 });
62 let token_decimals = u32::try_from(token_decimals).map_err(|e| {
63 anyhow::format_err!(
64 "Token decimals value ({}) of {} doesn't fit into u32: {:?}",
65 token_decimals,
66 C::NAME,
67 e,
68 )
69 })?;
70
71 for account in relay_accounts {
72 let relay_account_balance_metric = FloatStorageValueMetric::new(
73 AccountBalanceFromAccountInfo::<C> { token_decimals, _phantom: Default::default() },
74 client.clone(),
75 C::account_info_storage_key(account.id()),
76 format!("at_{}_relay_{}_balance", C::NAME, account.tag()),
77 format!("Balance of the {} relay account at the {}", account.tag(), C::NAME),
78 )?;
79 relay_account_balance_metric.register_and_spawn(&metrics.registry)?;
80 }
81
82 Ok(())
83}
84
85pub async fn add_relay_rewards_metrics<C: ChainWithRewards, BC: ChainWithMessages, LaneId>(
87 client: impl Client<C>,
88 metrics: &MetricsParams,
89 relay_accounts: &Vec<TaggedAccount<AccountIdOf<C>>>,
90 lanes: &[LaneId],
91) -> anyhow::Result<()>
92where
93 C::RewardBalance: Into<u128> + std::fmt::Debug,
94 C::Reward: From<RewardsAccountParams<LaneId>>,
95 LaneId: Clone + Copy + Decode + EncodeLike + Send + Sync + Labeled,
96{
97 if relay_accounts.is_empty() {
98 return Ok(())
99 }
100
101 for account in relay_accounts {
102 if let Some(_) = C::WITH_CHAIN_RELAYERS_PALLET_NAME {
103 for lane in lanes {
104 FloatStorageValueMetric::new(
105 FixedU128OrOne,
106 client.clone(),
107 C::account_reward_storage_key(account.id(), RewardsAccountParams::new(*lane, BC::ID, RewardsAccountOwner::ThisChain)),
108 format!("at_{}_relay_{}_reward_for_msgs_from_{}_on_lane_{}", C::NAME, account.tag(), BC::NAME, lane.label()),
109 format!("Reward of the {} relay account at {} for delivering messages from {} on lane {:?}", account.tag(), C::NAME, BC::NAME, lane.label()),
110 )?.register_and_spawn(&metrics.registry)?;
111
112 FloatStorageValueMetric::new(
113 FixedU128OrOne,
114 client.clone(),
115 C::account_reward_storage_key(account.id(), RewardsAccountParams::new(*lane, BC::ID, RewardsAccountOwner::BridgedChain)),
116 format!("at_{}_relay_{}_reward_for_msgs_to_{}_on_lane_{}", C::NAME, account.tag(), BC::NAME, lane.label()),
117 format!("Reward of the {} relay account at {} for delivering messages confirmations from {} on lane {:?}", account.tag(), C::NAME, BC::NAME, lane.label()),
118 )?.register_and_spawn(&metrics.registry)?;
119 }
120 }
121 }
122
123 Ok(())
124}
125
126#[derive(Clone, Debug)]
128struct AccountBalanceFromAccountInfo<C> {
129 token_decimals: u32,
130 _phantom: PhantomData<C>,
131}
132
133impl<C> FloatStorageValue for AccountBalanceFromAccountInfo<C>
134where
135 C: Chain,
136 BalanceOf<C>: Into<u128>,
137{
138 type Value = FixedU128;
139
140 fn decode(
141 &self,
142 maybe_raw_value: Option<StorageData>,
143 ) -> Result<Option<Self::Value>, SubstrateError> {
144 maybe_raw_value
145 .map(|raw_value| {
146 AccountInfo::<NonceOf<C>, AccountData<BalanceOf<C>>>::decode(&mut &raw_value.0[..])
147 .map_err(SubstrateError::ResponseParseFailed)
148 .map(|account_data| {
149 convert_to_token_balance(account_data.data.free.into(), self.token_decimals)
150 })
151 })
152 .transpose()
153 }
154}
155
156fn convert_to_token_balance(balance: u128, token_decimals: u32) -> FixedU128 {
159 FixedU128::from_inner(balance.saturating_mul(FixedU128::DIV / 10u128.pow(token_decimals)))
160}
161
162#[cfg(test)]
163mod tests {
164 use super::*;
165 #[test]
166 fn token_decimals_used_properly() {
167 let plancks = 425_000_000_000;
168 let token_decimals = 10;
169 let dots = convert_to_token_balance(plancks, token_decimals);
170 assert_eq!(dots, FixedU128::saturating_from_rational(425, 10));
171 }
172}