use std::collections::{HashMap, HashSet};
use std::sync::Mutex;
pub const PRESIGN_MINT_PER_HOUR: u64 = 1_000;
#[derive(Default)]
pub struct PresignGate {
state: Mutex<GateState>,
}
#[derive(Default)]
struct GateState {
blocked: HashSet<String>,
minted: HashMap<(String, i64), u64>,
}
pub enum PresignDenied {
ProjectBlocked,
RateLimited,
}
impl PresignGate {
pub fn new() -> Self {
Self::default()
}
pub fn set_blocked(&self, blocked: HashSet<String>) {
self.state.lock().unwrap().blocked = blocked;
}
pub fn try_mint(&self, project_id: &str, epoch_hour: i64) -> Result<(), PresignDenied> {
let mut state = self.state.lock().unwrap();
if state.blocked.contains(project_id) {
return Err(PresignDenied::ProjectBlocked);
}
let minted = state
.minted
.entry((project_id.to_string(), epoch_hour))
.or_insert(0);
if *minted >= PRESIGN_MINT_PER_HOUR {
return Err(PresignDenied::RateLimited);
}
*minted += 1;
Ok(())
}
pub fn snapshot_minted(&self, current_epoch_hour: i64) -> Vec<(String, i64, u64)> {
let mut state = self.state.lock().unwrap();
let snapshot = state
.minted
.iter()
.map(|((project_id, hour), count)| (project_id.clone(), *hour, *count))
.collect();
state
.minted
.retain(|(_, hour), _| *hour >= current_epoch_hour - 1);
snapshot
}
}