use crate::collators::claim_queue_at;
use cumulus_primitives_core::CoreSelector;
use cumulus_relay_chain_interface::RelayChainInterface;
use polkadot_node_subsystem_util::runtime::ClaimQueueSnapshot;
use polkadot_primitives::{
Hash as RelayHash, Header as RelayHeader, Id as ParaId, OccupiedCoreAssumption,
};
use sp_runtime::generic::BlockId;
#[derive(Clone, Debug)]
pub struct RelayChainData {
pub relay_parent_header: RelayHeader,
pub claim_queue: ClaimQueueSnapshot,
pub max_pov_size: u32,
pub last_claimed_core_selector: Option<CoreSelector>,
}
pub struct RelayChainDataCache<RI> {
relay_client: RI,
para_id: ParaId,
cached_data: schnellru::LruMap<RelayHash, RelayChainData>,
}
impl<RI> RelayChainDataCache<RI>
where
RI: RelayChainInterface + 'static,
{
pub fn new(relay_client: RI, para_id: ParaId) -> Self {
Self {
relay_client,
para_id,
cached_data: schnellru::LruMap::new(schnellru::ByLength::new(50)),
}
}
pub async fn get_mut_relay_chain_data(
&mut self,
relay_parent: RelayHash,
) -> Result<&mut RelayChainData, ()> {
let insert_data = if self.cached_data.peek(&relay_parent).is_some() {
tracing::trace!(target: crate::LOG_TARGET, %relay_parent, "Using cached data for relay parent.");
None
} else {
tracing::trace!(target: crate::LOG_TARGET, %relay_parent, "Relay chain best block changed, fetching new data from relay chain.");
Some(self.update_for_relay_parent(relay_parent).await?)
};
Ok(self
.cached_data
.get_or_insert(relay_parent, || {
insert_data.expect("`insert_data` exists if not cached yet; qed")
})
.expect("There is space for at least one element; qed"))
}
async fn update_for_relay_parent(&self, relay_parent: RelayHash) -> Result<RelayChainData, ()> {
let claim_queue = claim_queue_at(relay_parent, &self.relay_client).await;
let Ok(Some(relay_parent_header)) =
self.relay_client.header(BlockId::Hash(relay_parent)).await
else {
tracing::warn!(target: crate::LOG_TARGET, "Unable to fetch latest relay chain block header.");
return Err(())
};
let max_pov_size = match self
.relay_client
.persisted_validation_data(relay_parent, self.para_id, OccupiedCoreAssumption::Included)
.await
{
Ok(None) => return Err(()),
Ok(Some(pvd)) => pvd.max_pov_size,
Err(err) => {
tracing::error!(target: crate::LOG_TARGET, ?err, "Failed to gather information from relay-client");
return Err(())
},
};
Ok(RelayChainData {
relay_parent_header,
claim_queue,
max_pov_size,
last_claimed_core_selector: None,
})
}
#[cfg(test)]
pub(crate) fn insert_test_data(&mut self, relay_parent: RelayHash, data: RelayChainData) {
self.cached_data.insert(relay_parent, data);
}
}