From 6f3c25c4aa27045703d205c09840ce2c2a965aef Mon Sep 17 00:00:00 2001 From: gianfra-t <96739519+gianfra-t@users.noreply.github.com> Date: Fri, 18 Oct 2024 16:02:59 +0300 Subject: [PATCH] Support liquidated vaults in metrics (#559) * support liquidated vaults for metrics * add method to fetch only active vaults ids from manager, only accept requests if not liquidated * add metric for liquidated * clippy fixes * simplify liquidation status metric updater * remove comment * remove unused method --- clients/vault/src/metrics.rs | 24 ++++++++++++-- clients/vault/src/system.rs | 43 +++++++++++++++++++++---- pallets/stellar-relay/src/validation.rs | 4 +-- 3 files changed, 59 insertions(+), 12 deletions(-) diff --git a/clients/vault/src/metrics.rs b/clients/vault/src/metrics.rs index 05f484a02..9209647ff 100644 --- a/clients/vault/src/metrics.rs +++ b/clients/vault/src/metrics.rs @@ -9,8 +9,10 @@ use lazy_static::lazy_static; use primitives::{stellar, Asset, DecimalsLookup}; use runtime::{ prometheus::{ - gather, proto::MetricFamily, Encoder, Gauge, GaugeVec, IntCounter, IntGaugeVec, Opts, - Registry, TextEncoder, + core::{AtomicI64, GenericGauge}, + gather, + proto::MetricFamily, + Encoder, Gauge, GaugeVec, IntCounter, IntGaugeVec, Opts, Registry, TextEncoder, }, types::currency_id::CurrencyIdExt, AggregateUpdatedEvent, CollateralBalancesPallet, CurrencyId, Error as RuntimeError, FixedU128, @@ -83,6 +85,11 @@ lazy_static! { pub static ref RESTART_COUNT: IntCounter = IntCounter::new("restart_count", "Number of service restarts") .expect("Failed to create prometheus metric"); + pub static ref LIQUIDATED: IntGaugeVec = IntGaugeVec::new( + Opts::new("liquidated", "Boolean reporting if the vault is currently liquidated"), + &[CURRENCY_LABEL] + ) + .expect("Failed to create prometheus metric"); } const STELLAR_NATIVE_ASSET_TYPE: [u8; 6] = *b"native"; @@ -108,6 +115,7 @@ pub struct PerCurrencyMetrics { asset_balance: XLMBalance, issues: RequestCounter, redeems: RequestCounter, + liquidated: GenericGauge<AtomicI64>, } #[async_trait] @@ -117,8 +125,9 @@ pub trait VaultDataReader { #[async_trait] impl VaultDataReader for VaultIdManager { + // get_all_entries fetches from active and liquidated vaults async fn get_entries(&self) -> Vec<VaultData> { - self.get_entries().await + self.get_all_entries().await } } @@ -231,6 +240,7 @@ impl PerCurrencyMetrics { completed_count: REDEEMS.with(&request_type_label("completed")), expired_count: REDEEMS.with(&request_type_label("expired")), }, + liquidated: LIQUIDATED.with(&labels), } } @@ -242,6 +252,7 @@ impl PerCurrencyMetrics { publish_locked_collateral(vault, parachain_rpc.clone()), publish_required_collateral(vault, parachain_rpc.clone()), publish_collateralization(vault, parachain_rpc.clone()), + update_liquidation_status(vault) ); } } @@ -259,6 +270,7 @@ pub fn register_custom_metrics() -> Result<(), RuntimeError> { REGISTRY.register(Box::new(MEAN_POLL_DURATION.clone()))?; REGISTRY.register(Box::new(MEAN_SCHEDULED_DURATION.clone()))?; REGISTRY.register(Box::new(RESTART_COUNT.clone()))?; + REGISTRY.register(Box::new(LIQUIDATED.clone()))?; Ok(()) } @@ -481,6 +493,11 @@ async fn publish_redeem_count<V: VaultDataReader>( } } +async fn update_liquidation_status(vault: &VaultData) { + let liquidated_flag: i64 = if vault.liquidated { 1 } else { 0 }; + vault.metrics.liquidated.set(liquidated_flag); +} + pub async fn monitor_bridge_metrics( parachain_rpc: SpacewalkParachain, vault_id_manager: VaultIdManager, @@ -499,6 +516,7 @@ pub async fn monitor_bridge_metrics( .iter() .filter(|vault| vault.vault_id.collateral_currency() == **currency_id) { + let _ = update_liquidation_status(vault).await; let _ = publish_locked_collateral(vault, parachain_rpc.clone()).await; let _ = publish_required_collateral(vault, parachain_rpc.clone()).await; publish_collateralization(vault, parachain_rpc.clone()).await; diff --git a/clients/vault/src/system.rs b/clients/vault/src/system.rs index c654d54ad..cab45adcc 100644 --- a/clients/vault/src/system.rs +++ b/clients/vault/src/system.rs @@ -52,6 +52,7 @@ pub struct VaultData { pub vault_id: VaultId, pub stellar_wallet: ArcRwLock<StellarWallet>, pub metrics: PerCurrencyMetrics, + pub liquidated: bool, } #[derive(Clone)] @@ -88,6 +89,7 @@ impl VaultIdManager { vault_id: key.clone(), stellar_wallet: stellar_wallet.clone(), metrics: PerCurrencyMetrics::dummy(), + liquidated: false, }, ) }) @@ -95,12 +97,13 @@ impl VaultIdManager { Self { vault_data: Arc::new(RwLock::new(vault_data)), spacewalk_parachain, stellar_wallet } } - async fn add_vault_id(&self, vault_id: VaultId) -> Result<(), Error> { + async fn add_vault_id(&self, vault_id: VaultId, is_liquidated: bool) -> Result<(), Error> { let metrics = PerCurrencyMetrics::new(&vault_id); let data = VaultData { vault_id: vault_id.clone(), stellar_wallet: self.stellar_wallet.clone(), metrics, + liquidated: is_liquidated, }; PerCurrencyMetrics::initialize_values(self.spacewalk_parachain.clone(), &data).await; @@ -119,11 +122,14 @@ impl VaultIdManager { { // check if vault is registered match self.spacewalk_parachain.get_vault(&vault_id).await { - Ok(_) => self.add_vault_id(vault_id.clone()).await?, - Err(RuntimeError::VaultLiquidated) => tracing::error!( - "[{}] Vault is liquidated -- not going to process events for this vault.", - vault_id.pretty_print() - ), + Ok(_) => self.add_vault_id(vault_id.clone(), false).await?, + Err(RuntimeError::VaultLiquidated) => { + self.add_vault_id(vault_id.clone(), true).await?; + tracing::error!( + "[{}] Vault is liquidated -- not going to process events for this vault.", + vault_id.pretty_print() + ); + }, Err(e) => return Err(e.into()), } } @@ -138,7 +144,7 @@ impl VaultIdManager { let vault_id = event.vault_id; if self.spacewalk_parachain.is_this_vault(&vault_id) { tracing::info!("New vault registered: {}", vault_id.pretty_print()); - let _ = self.add_vault_id(vault_id).await; + let _ = self.add_vault_id(vault_id, false).await; } }, |err| tracing::error!("Error (RegisterVaultEvent): {}", err.to_string()), @@ -150,11 +156,32 @@ impl VaultIdManager { self.vault_data.read().await.get(vault_id).map(|x| x.stellar_wallet.clone()) } + pub async fn get_active_vault(&self, vault_id: &VaultId) -> Option<VaultData> { + let vault = self.vault_data.read().await.get(vault_id)?.clone(); + // Filter liquidated + if vault.liquidated { + return None; + } + return Some(vault); + } + pub async fn get_vault(&self, vault_id: &VaultId) -> Option<VaultData> { self.vault_data.read().await.get(vault_id).cloned() } + // Get all ACTIVE vaults pub async fn get_entries(&self) -> Vec<VaultData> { + self.vault_data + .read() + .await + .iter() + .filter(|(_, value)| !value.liquidated) + .map(|(_, value)| value.clone()) + .collect() + } + + // Get all vaults including liquidated ones. + pub async fn get_all_entries(&self) -> Vec<VaultData> { self.vault_data.read().await.iter().map(|(_, value)| value.clone()).collect() } @@ -163,6 +190,7 @@ impl VaultIdManager { .read() .await .iter() + .filter(|(_, value)| !value.liquidated) .map(|(vault_id, _)| vault_id.clone()) .collect() } @@ -174,6 +202,7 @@ impl VaultIdManager { .read() .await .iter() + .filter(|(_, value)| !value.liquidated) .map(|(vault_id, data)| (vault_id.clone(), data.stellar_wallet.clone())) .collect() } diff --git a/pallets/stellar-relay/src/validation.rs b/pallets/stellar-relay/src/validation.rs index cce5b8cf5..783317e34 100644 --- a/pallets/stellar-relay/src/validation.rs +++ b/pallets/stellar-relay/src/validation.rs @@ -92,7 +92,7 @@ fn is_node_id_exist<T: Config>( envelope.statement.slot_index, envelope.statement.node_id ); - return None + return None; } Some(node_id) @@ -174,7 +174,7 @@ pub fn validate_envelopes<'a, T: Config>( for envelope in envelopes { let Some(node_id) = is_node_id_exist::<T>(envelope, validators) else { // ignore this envelope; continue to the next ones - continue + continue; }; // Check if all envelopes are using the same slot index