use std::collections::BTreeMap;
use allocative::Allocative;
use linera_base::{
data_types::{Blob, Round},
ensure,
identifiers::BlobId,
};
use linera_views::{
context::Context,
map_view::MapView,
register_view::RegisterView,
views::{ClonableView, View},
ViewError,
};
use crate::ChainError;
#[cfg_attr(with_graphql, derive(async_graphql::SimpleObject))]
#[derive(Debug, View, ClonableView, Allocative)]
#[allocative(bound = "C")]
pub struct PendingBlobsView<C>
where
C: Clone + Context,
{
pub round: RegisterView<C, Round>,
pub validated: RegisterView<C, bool>,
pub pending_blobs: MapView<C, BlobId, Option<Blob>>,
}
impl<C> PendingBlobsView<C>
where
C: Clone + Context,
{
pub async fn get(&self, blob_id: &BlobId) -> Result<Option<Blob>, ViewError> {
Ok(self.pending_blobs.get(blob_id).await?.flatten())
}
pub async fn maybe_insert(&mut self, blob: &Blob) -> Result<bool, ViewError> {
let blob_id = blob.id();
let Some(maybe_blob) = self.pending_blobs.get_mut(&blob_id).await? else {
return Ok(false);
};
if maybe_blob.is_none() {
*maybe_blob = Some(blob.clone());
}
Ok(true)
}
pub fn update(
&mut self,
round: Round,
validated: bool,
maybe_blobs: BTreeMap<BlobId, Option<Blob>>,
) -> Result<(), ChainError> {
let existing_round = *self.round.get();
ensure!(
existing_round <= round,
ChainError::InsufficientRound(existing_round)
);
if existing_round < round {
self.clear();
self.round.set(round);
self.validated.set(validated);
}
for (blob_id, maybe_blob) in maybe_blobs {
self.pending_blobs.insert(&blob_id, maybe_blob)?;
}
Ok(())
}
}