Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
daniel-savu committed Nov 24, 2023
1 parent 1cebc39 commit 9e81247
Show file tree
Hide file tree
Showing 14 changed files with 211 additions and 171 deletions.
2 changes: 2 additions & 0 deletions rust/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 13 additions & 1 deletion rust/agents/relayer/src/relayer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use hyperlane_base::{
use hyperlane_core::{
HyperlaneDomain, HyperlaneMessage, InterchainGasPayment, MerkleTreeInsertion, U256,
};
use hyperlane_ethereum::Signers;
use tokio::{
sync::{
mpsc::{self, UnboundedReceiver, UnboundedSender},
Expand Down Expand Up @@ -188,9 +189,20 @@ impl BaseAgent for Relayer {
.collect();

let mut msg_ctxs = HashMap::new();
// let mut custom_metrics = HashMap::new();
for destination in &settings.destination_chains {
let destination_chain_setup = core.settings.chain_setup(destination).unwrap().clone();

let agent_metrics_conf = destination_chain_setup
.agent_metrics_conf("relayer".to_owned())
.await?;
println!("~~~ agent metrics: {:?}", agent_metrics_conf);
println!("~~~ agent signer: {:?}", destination_chain_setup.signer);
// custom_metrics.insert(
// destination.id(),
// destination_chain_setup
// .metrics(destination)
// .expect("Missing metrics config"),
// );
let transaction_gas_limit: Option<U256> =
if skip_transaction_gas_limit_for.contains(&destination.id()) {
None
Expand Down
12 changes: 12 additions & 0 deletions rust/chains/hyperlane-ethereum/src/agent_metrics.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
use async_trait::async_trait;
use hyperlane_core::{metrics::agent::AgenMetricsFetcher, ChainResult};

pub struct MetricsFetcher {}

#[async_trait]
impl AgenMetricsFetcher for MetricsFetcher {
async fn get_balance(&self, address: &String) -> ChainResult<u64> {
// Should the provider be part of the `MetricsFetcher`?
Ok(0)
}
}
1 change: 1 addition & 0 deletions rust/chains/hyperlane-ethereum/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ mod signers;
#[cfg(not(doctest))]
mod singleton_signer;

pub mod agent_metrics;
mod config;

fn extract_fn_map(abi: &'static Lazy<abi::Abi>) -> HashMap<Vec<u8>, &'static str> {
Expand Down
167 changes: 20 additions & 147 deletions rust/ethers-prometheus/src/middleware/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use ethers::abi::AbiEncode;
use ethers::prelude::*;
use ethers::types::transaction::eip2718::TypedTransaction;
use ethers::utils::hex::ToHex;
use log::{debug, trace, warn};
use log::{debug, trace};
use maplit::hashmap;
use prometheus::{CounterVec, GaugeVec, IntCounterVec, IntGaugeVec};
use static_assertions::assert_impl_all;
Expand All @@ -23,35 +23,11 @@ use tokio::time::MissedTickBehavior;

pub use error::PrometheusMiddlewareError;

use crate::contracts::erc_20::Erc20;
use crate::u256_as_scaled_f64;
pub use crate::ChainInfo;

mod error;

/// Some basic information about a token.
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(tag = "type", rename_all = "camelCase"))]
pub struct TokenInfo {
/// Full name of the token. E.g. Ether.
pub name: String,
/// Token symbol. E.g. ETH.
pub symbol: String,
/// Number of
pub decimals: u8,
}

impl Default for TokenInfo {
fn default() -> Self {
Self {
name: "Unknown".into(),
symbol: "".into(),
decimals: 18,
}
}
}

/// Some basic information about a wallet.
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
Expand Down Expand Up @@ -148,18 +124,6 @@ pub const TRANSACTION_SEND_TOTAL_LABELS: &[&str] =
/// Help string for the metric.
pub const TRANSACTION_SEND_TOTAL_HELP: &str = "Number of transactions sent";

/// Expected label names for the `wallet_balance` metric.
pub const WALLET_BALANCE_LABELS: &[&str] = &[
"chain",
"wallet_address",
"wallet_name",
"token_address",
"token_symbol",
"token_name",
];
/// Help string for the metric.
pub const WALLET_BALANCE_HELP: &str = "Current balance of eth and other tokens in the `tokens` map for the wallet addresses in the `wallets` set";

/// Container for all the relevant middleware metrics.
#[derive(Clone, Builder)]
pub struct MiddlewareMetrics {
Expand Down Expand Up @@ -238,24 +202,23 @@ pub struct MiddlewareMetrics {
/// - `txn_status`: `dispatched`, `completed`, or `failed`
#[builder(setter(into, strip_option), default)]
transaction_send_total: Option<IntCounterVec>,

// /// Gas spent on completed transactions.
// /// - `chain`: the chain name (or ID if the name is unknown) of the chain the tx occurred
// on. /// - `address_from`: source address of the transaction.
// /// - `address_to`: destination address of the transaction.
// #[builder(setter(into, strip_option), default)]
// transaction_send_gas_eth_total: Option<CounterVec>,
/// Current balance of eth and other tokens in the `tokens` map for the
/// wallet addresses in the `wallets` set.
/// - `chain`: the chain name (or chain ID if the name is unknown) of the
/// chain the tx occurred on.
/// - `wallet_address`: Address of the wallet holding the funds.
/// - `wallet_name`: Name of the address holding the funds.
/// - `token_address`: Address of the token.
/// - `token_symbol`: Symbol of the token.
/// - `token_name`: Full name of the token.
#[builder(setter(into, strip_option), default)]
wallet_balance: Option<GaugeVec>,
// /// Current balance of eth and other tokens in the `tokens` map for the
// /// wallet addresses in the `wallets` set.
// /// - `chain`: the chain name (or chain ID if the name is unknown) of the
// /// chain the tx occurred on.
// /// - `wallet_address`: Address of the wallet holding the funds.
// /// - `wallet_name`: Name of the address holding the funds.
// /// - `token_address`: Address of the token.
// /// - `token_symbol`: Symbol of the token.
// /// - `token_name`: Full name of the token.
// #[builder(setter(into, strip_option), default)]
// wallet_balance: Option<GaugeVec>,
}

/// An ethers-rs middleware that instruments calls with prometheus metrics. To
Expand All @@ -273,14 +236,9 @@ pub struct PrometheusMiddleware<M> {
#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(tag = "type", rename_all = "camelCase"))]
pub struct PrometheusMiddlewareConf {
/// The tokens to track and identifying info
#[cfg_attr(feature = "serde", serde(default))]
pub tokens: HashMap<Address, TokenInfo>,

/// The wallets to track and identifying info
#[cfg_attr(feature = "serde", serde(default))]
pub wallets: HashMap<Address, WalletInfo>,

// /// The wallets to track and identifying info
// #[cfg_attr(feature = "serde", serde(default))]
// pub wallets: HashMap<Address, WalletInfo>,
/// Contract info for more useful metrics
#[cfg_attr(feature = "serde", serde(default))]
pub contracts: HashMap<Address, ContractInfo>,
Expand Down Expand Up @@ -521,32 +479,6 @@ impl<M> PrometheusMiddleware<M> {
conf: Arc::new(RwLock::new(conf)),
}
}

/// Start tracking metrics for a new token.
pub async fn track_new_token(&self, addr: Address, info: TokenInfo) {
self.track_new_tokens([(addr, info)]).await;
}

/// Start tacking metrics for new tokens.
pub async fn track_new_tokens(&self, iter: impl IntoIterator<Item = (Address, TokenInfo)>) {
let mut data = self.conf.write().await;
for (addr, info) in iter {
data.tokens.insert(addr, info);
}
}

/// Start tracking metrics for a new wallet.
pub async fn track_new_wallet(&self, addr: Address, info: WalletInfo) {
self.track_new_wallets([(addr, info)]).await;
}

/// Start tracking metrics for new wallets.
pub async fn track_new_wallets(&self, iter: impl IntoIterator<Item = (Address, WalletInfo)>) {
let mut data = self.conf.write().await;
for (addr, info) in iter {
data.wallets.insert(addr, info);
}
}
}

impl<M: Middleware> PrometheusMiddleware<M> {
Expand Down Expand Up @@ -580,7 +512,7 @@ impl<M: Middleware + Send + Sync> PrometheusMiddleware<M> {
/// prometheus scrape interval.
pub fn update(&self) -> impl Future<Output = ()> {
// all metrics are Arcs internally so just clone the ones we want to report for.
let wallet_balance = self.metrics.wallet_balance.clone();
// let wallet_balance = self.metrics.wallet_balance.clone();
let block_height = self.metrics.block_height.clone();
let gas_price_gwei = self.metrics.gas_price_gwei.clone();

Expand All @@ -595,9 +527,9 @@ impl<M: Middleware + Send + Sync> PrometheusMiddleware<M> {
if block_height.is_some() || gas_price_gwei.is_some() {
Self::update_block_details(&*client, chain, block_height, gas_price_gwei).await;
}
if let Some(wallet_balance) = wallet_balance {
Self::update_wallet_balances(client.clone(), &data, chain, wallet_balance).await;
}
// if let Some(wallet_balance) = wallet_balance {
// Self::update_wallet_balances(client.clone(), &data, chain, wallet_balance).await;
// }

// more metrics to come...
}
Expand All @@ -609,9 +541,7 @@ impl<M: Middleware + Send + Sync> PrometheusMiddleware<M> {
block_height: Option<IntGaugeVec>,
gas_price_gwei: Option<GaugeVec>,
) {
let current_block = if let Ok(Some(b)) = client.get_block(BlockNumber::Latest).await {
b
} else {
let Ok(Some(current_block)) = client.get_block(BlockNumber::Latest).await else {
return;
};

Expand All @@ -635,63 +565,6 @@ impl<M: Middleware + Send + Sync> PrometheusMiddleware<M> {
}
}
}

async fn update_wallet_balances(
client: Arc<M>,
data: &PrometheusMiddlewareConf,
chain: &str,
wallet_balance_metric: GaugeVec,
) {
for (wallet_addr, wallet_info) in data.wallets.iter() {
let wallet_addr_str: String = wallet_addr.encode_hex();
let wallet_name = wallet_info.name.as_deref().unwrap_or("none");

match client.get_balance(*wallet_addr, None).await {
Ok(balance) => {
// Okay, so the native type is not a token, but whatever, close enough.
// Note: This is ETH for many chains, but not all so that is why we use `N` and `Native`
// TODO: can we get away with scaling as 18 in all cases here? I am guessing not.
let balance = u256_as_scaled_f64(balance, 18);
trace!("Wallet {wallet_name} ({wallet_addr_str}) on chain {chain} balance is {balance} of the native currency");
wallet_balance_metric
.with(&hashmap! {
"chain" => chain,
"wallet_address" => wallet_addr_str.as_str(),
"wallet_name" => wallet_name,
"token_address" => "none",
"token_symbol" => "Native",
"token_name" => "Native"
}).set(balance)
},
Err(e) => warn!("Metric update failed for wallet {wallet_name} ({wallet_addr_str}) on chain {chain} balance for native currency; {e}")
}
for (token_addr, token) in data.tokens.iter() {
let token_addr_str: String = token_addr.encode_hex();
let balance = match Erc20::new(*token_addr, client.clone())
.balance_of(*wallet_addr)
.call()
.await
{
Ok(b) => u256_as_scaled_f64(b, token.decimals),
Err(e) => {
warn!("Metric update failed for wallet {wallet_name} ({wallet_addr_str}) on chain {chain} balance for {name}; {e}", name=token.name);
continue;
}
};
trace!("Wallet {wallet_name} ({wallet_addr_str}) on chain {chain} balance is {balance}{}", token.symbol);
wallet_balance_metric
.with(&hashmap! {
"chain" => chain,
"wallet_address" => wallet_addr_str.as_str(),
"wallet_name" => wallet_name,
"token_address" => token_addr_str.as_str(),
"token_symbol" => token.symbol.as_str(),
"token_name" => token.symbol.as_str()
})
.set(balance);
}
}
}
}

impl<M: Middleware> Debug for PrometheusMiddleware<M> {
Expand Down
2 changes: 2 additions & 0 deletions rust/hyperlane-base/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,15 @@ bs58.workspace = true
color-eyre = { workspace = true, optional = true }
config.workspace = true
convert_case.workspace = true
derive_builder.workspace = true
derive-new.workspace = true
ed25519-dalek.workspace = true
ethers.workspace = true
eyre.workspace = true
fuels.workspace = true
futures-util.workspace = true
itertools.workspace = true
maplit.workspace = true
paste.workspace = true
prometheus.workspace = true
rocksdb.workspace = true
Expand Down
Loading

0 comments on commit 9e81247

Please sign in to comment.