Skip to content

Commit

Permalink
Update wallet_balance metric to f64 instead of u64 (#2440)
Browse files Browse the repository at this point in the history
  • Loading branch information
ljoss17 authored Jul 20, 2022
1 parent 5fb3e48 commit c61ae18
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 59 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
- Updated telemetry metric `wallet_balance` to f64 and removed downscaling
displayed value. Please note that when converting the balance to f64 a loss in
precision might be introduced in the displayed value.
([#2381](https://github.com/informalsystems/ibc-rs/issues/2381))
9 changes: 5 additions & 4 deletions guide/src/telemetry.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ The following table describes the metrics currently tracked by the telemetry ser
| `ibc_receive_packets` | Number of receive packets relayed per channel | `u64` Counter |
| `ibc_acknowledgment_packets` | Number of acknowledgment packets relayed per channel | `u64` Counter |
| `ibc_timeout_packets` | Number of timeout packets relayed per channel | `u64` Counter |
| `wallet_balance` | How much balance (coins) there is left in each wallet key that Hermes is using. | `u64` ValueRecorder |
| `wallet_balance` | The balance of each wallet Hermes uses per chain. Please note that when converting the balance to f64 a loss in
precision might be introduced in the displayed value | `f64` ValueRecorder |
| `ws_events` | How many IBC events did Hermes receive via the websocket subscription, in total since starting up, per chain. | Counter |
| `ws_reconnect` | Number of times Hermes had to reconnect to the WebSocket endpoint | Counter |
| `tx_latency_submitted` | Latency for all transactions submitted to a chain (i.e., difference between the moment when Hermes received an event until the corresponding transaction(s) were submitted). | `u64` ValueRecorder |
Expand Down Expand Up @@ -173,9 +174,9 @@ tx_latency_submitted_sum{chain="ibc-2",channel="channel-0",counterparty="ibc-0",
tx_latency_submitted_count{chain="ibc-2",channel="channel-0",counterparty="ibc-0",port="transfer"} 1
# HELP wallet_balance The balance in each wallet that Hermes is using, per wallet, denom and chain. The amount is of unit: 10^6 * `denom`
# TYPE wallet_balance gauge
wallet_balance{account="cosmos1lfq283ph84d49hywahpngxueqsv4wgxt6x5d7z",chain="ibc-0",denom="stake"} 95
wallet_balance{account="cosmos1mmkyea9pmqhlewrap0urpes2vx0r4gnz7eq5vl",chain="ibc-1",denom="stake"} 93
wallet_balance{account="cosmos1pmypcnlkgzfuayzlxr3w9ykp7d0pd4lg027e46",chain="ibc-2",denom="stake"} 94
wallet_balance{account="cosmos1lfq283ph84d49hywahpngxueqsv4wgxt6x5d7z",chain="ibc-0",denom="stake"} 99981718
wallet_balance{account="cosmos1mmkyea9pmqhlewrap0urpes2vx0r4gnz7eq5vl",chain="ibc-1",denom="stake"} 99984434
wallet_balance{account="cosmos1pmypcnlkgzfuayzlxr3w9ykp7d0pd4lg027e46",chain="ibc-2",denom="stake"} 99977817
# HELP workers Number of workers per object
# TYPE workers gauge
workers{type="client"} 6
Expand Down
73 changes: 24 additions & 49 deletions relayer/src/worker/wallet.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
use std::{ops::Div, time::Duration};
use std::time::Duration;

use tracing::{error_span, trace};

use ibc::bigint::U256;
use tracing::{error_span, trace, warn};

use crate::{
chain::handle::ChainHandle,
Expand All @@ -22,61 +20,38 @@ pub fn spawn_wallet_worker<Chain: ChainHandle>(chain: Chain) -> TaskHandle {
TaskError::Ignore(format!("failed to query balance for the account: {e}"))
})?;

let amount: U256 = U256::from_dec_str(&balance.amount).map_err(|_| {
TaskError::Ignore(format!(
"failed to parse amount into U256: {}",
balance.amount
))
})?;

trace!(%amount, denom = %balance.denom, account = %key.account, "wallet balance");

// The input domain `balance.amount` may exceed u64::MAX, which is the
// largest value that can be reported via the Prometheus exporter.
//
// To work around this, we scale down the amount by 10^6 in an attempt
// to fit it into a u64, effectively turning the denomination from
// eg. uatom to atom. If the scaled down amount does not fit, we do
// not report it.
//
// Example input that overflows, from sifchain-1: `349999631379421794336`.
//
if let Some(_scaled_amount) = scale_down(amount) {
telemetry!(
wallet_balance,
&chain.id(),
&key.account,
_scaled_amount,
&balance.denom,
);
} else {
trace!(
%amount, denom = %balance.denom, account = %key.account,
"amount cannot be scaled down to fit into u64 and therefore won't be reported to telemetry"
);
match balance.amount.parse::<f64>() {
Ok(amount) => {
telemetry!(
wallet_balance,
&chain.id(),
&key.account,
amount,
&balance.denom,
);
trace!(%amount, denom = %balance.denom, account = %key.account, "wallet balance");
}
Err(e) => {
warn!(
%balance.amount, denom = %balance.denom, account = %key.account,
"Unable to parse the wallet balance into a f64, the balance will therefore not be reported to telemetry. Reason: {}", e
);
}
}

Ok(Next::Continue)
})
}

/// Scale down the given amount by a factor of 10^6,
/// and return it as a `u64` if it fits.
fn scale_down(amount: U256) -> Option<u64> {
amount.div(10_u64.pow(6)).try_into().ok()
}

#[cfg(test)]
mod tests {
use super::scale_down;
use ibc::bigint::U256;

// Test to confirm that any u256 fits in f64
#[test]
fn example_input() {
let u: U256 =
U256::from_dec_str("349999631379421794336").expect("failed to parse into U256");
fn compare_f64_max_to_u256_max() {
let f64_max = f64::MAX;
let u256_max = U256::MAX;

let s = scale_down(u);
assert_eq!(s, Some(349999631379421_u64));
assert!(f64_max > u256_max.to_string().parse::<f64>().unwrap());
}
}
12 changes: 6 additions & 6 deletions telemetry/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,8 @@ pub struct TelemetryState {
/// How many messages Hermes submitted to the chain, per chain
msg_num: Counter<u64>,

/// The balance in each wallet that Hermes is using, per wallet, denom and chain.
/// The amount given is of unit: 10^6 * `denom`
wallet_balance: ValueRecorder<u64>,
/// The balance of each wallet Hermes uses per chain
wallet_balance: ValueRecorder<f64>,

/// Indicates the latency for all transactions submitted to a specific chain,
/// i.e. the difference between the moment when Hermes received a batch of events
Expand Down Expand Up @@ -243,7 +242,7 @@ impl TelemetryState {

/// The balance in each wallet that Hermes is using, per account, denom and chain.
/// The amount given is of unit: 10^6 * `denom`
pub fn wallet_balance(&self, chain_id: &ChainId, account: &str, amount: u64, denom: &str) {
pub fn wallet_balance(&self, chain_id: &ChainId, account: &str, amount: f64, denom: &str) {
let labels = &[
KeyValue::new("chain", chain_id.to_string()),
KeyValue::new("account", account.to_string()),
Expand Down Expand Up @@ -571,8 +570,9 @@ impl Default for TelemetryState {
.init(),

wallet_balance: meter
.u64_value_recorder("wallet_balance")
.with_description("The balance in each wallet that Hermes is using, per wallet, denom and chain. The amount is of unit: 10^6 * `denom`")
.f64_value_recorder("wallet_balance")
.with_description("The balance of each wallet Hermes uses per chain. Please note that when converting the balance to f64 a loss in
precision might be introduced in the displayed value")
.init(),

send_packet_count: meter
Expand Down

0 comments on commit c61ae18

Please sign in to comment.