Files
nym/nym-api/src/circulating_supply_api/cache/mod.rs
T
2023-08-17 10:52:37 +01:00

93 lines
3.5 KiB
Rust

// Copyright 2022-2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use self::data::CirculatingSupplyCacheData;
use cosmwasm_std::Addr;
use nym_api_requests::models::CirculatingSupplyResponse;
use nym_validator_client::nyxd::error::NyxdError;
use nym_validator_client::nyxd::Coin;
use rocket::fairing::AdHoc;
use std::ops::Deref;
use std::{
sync::{atomic::AtomicBool, Arc},
time::Duration,
};
use thiserror::Error;
use tokio::sync::RwLock;
use tokio::time;
mod data;
pub(crate) mod refresher;
#[derive(Debug, Error)]
enum CirculatingSupplyCacheError {
// this can only happen if somebody decides to set their staking address
// before https://github.com/nymtech/nym/pull/2796 is deployed
#[error("vesting account owned by {owner} with id {account_id} appeared more than once in the query response")]
DuplicateVestingAccountEntry { owner: Addr, account_id: u32 },
// this can happen if somehow the query was incomplete, like some paged sub-query didn't return full result
// or there's a bug with paging. or if, somehow, a vesting account got removed from the contract
#[error("got an inconsistent number of vesting account. received data on {got}, but expected {expected}")]
InconsistentNumberOfVestingAccounts { expected: usize, got: usize },
#[error(transparent)]
ClientError {
#[from]
source: NyxdError,
},
}
/// A cache for the circulating supply of the network. Circulating supply is calculated by
/// taking the initial supply of 1bn coins, and subtracting the amount of coins that are
/// in the mixmining pool and tied up in vesting.
///
/// The cache is quite simple and does not include an update listener that the other caches have.
#[derive(Clone)]
pub(crate) struct CirculatingSupplyCache {
initialised: Arc<AtomicBool>,
data: Arc<RwLock<CirculatingSupplyCacheData>>,
}
impl CirculatingSupplyCache {
fn new(mix_denom: String) -> CirculatingSupplyCache {
CirculatingSupplyCache {
initialised: Arc::new(AtomicBool::new(false)),
data: Arc::new(RwLock::new(CirculatingSupplyCacheData::new(mix_denom))),
}
}
pub(crate) async fn get_circulating_supply(&self) -> Option<CirculatingSupplyResponse> {
match time::timeout(Duration::from_millis(100), self.data.read()).await {
Ok(cache) => Some(cache.deref().into()),
Err(err) => {
error!("Failed to get circulating supply: {err}");
None
}
}
}
pub(crate) fn stage(mix_denom: String) -> AdHoc {
AdHoc::on_ignite("Circulating Supply Cache Stage", |rocket| async {
rocket.manage(Self::new(mix_denom))
})
}
pub(crate) async fn update(&self, mixmining_reserve: Coin, vesting_tokens: Coin) {
let mut cache = self.data.write().await;
let mut circulating_supply = cache.total_supply.clone();
circulating_supply.amount -= mixmining_reserve.amount;
circulating_supply.amount -= vesting_tokens.amount;
log::info!("Updating circulating supply cache");
log::info!("the mixmining reserve is now {mixmining_reserve}");
log::info!("the number of tokens still vesting is now {vesting_tokens}");
log::info!("the circulating supply is now {circulating_supply}");
cache.mixmining_reserve.update(mixmining_reserve);
cache.vesting_tokens.update(vesting_tokens);
cache.circulating_supply.update(circulating_supply);
}
}