use crate::routing::{
error::{Error, Result},
log_markers::LogMarker,
};
use std::sync::Arc;
use tokio::sync::RwLock;
use uluru::LRUCache;
const KEY_CACHE_SIZE: usize = 50;
#[derive(custom_debug::Debug, Clone)]
pub(crate) struct SectionKeyShare {
pub(crate) public_key_set: bls::PublicKeySet,
pub(crate) index: usize,
#[debug(skip)]
pub(crate) secret_key_share: bls::SecretKeyShare,
}
#[derive(Debug, Clone)]
pub(crate) struct SectionKeysProvider {
cache: Arc<RwLock<LRUCache<SectionKeyShare, KEY_CACHE_SIZE>>>,
}
impl SectionKeysProvider {
pub(crate) async fn new(current: Option<SectionKeyShare>) -> Self {
let section_keys_provider = Self {
cache: Arc::new(RwLock::new(LRUCache::default())),
};
if let Some(share) = current {
section_keys_provider.insert(share).await;
}
section_keys_provider
}
pub(crate) async fn wipe(&self) {
self.cache.write().await.clear();
}
pub(crate) async fn key_share(&self, public_key: &bls::PublicKey) -> Result<SectionKeyShare> {
match self
.cache
.write()
.await
.find(|share| public_key == &share.public_key_set.public_key())
{
Some(key_share) => Ok(key_share.clone()),
None => Err(Error::MissingSecretKeyShare(*public_key)),
}
}
pub(crate) async fn sign_with(
&self,
data: &[u8],
public_key: &bls::PublicKey,
) -> Result<(usize, bls::SignatureShare)> {
let key_share = self.key_share(public_key).await?;
Ok((key_share.index, key_share.secret_key_share.sign(data)))
}
pub(crate) async fn is_empty(&self) -> bool {
self.cache.read().await.is_empty()
}
pub(crate) async fn insert(&self, share: SectionKeyShare) {
let public_key = share.public_key_set.public_key();
if let Some(evicted) = self.cache.write().await.insert(share) {
trace!("evicted old key share from cache: {:?}", evicted);
}
trace!(
"{} in cache (total {}): {:?}",
LogMarker::NewKeyShareStored,
self.cache.read().await.len(),
public_key
);
}
}