use crate::{Block, simplex::scheme::Scheme, types::Round};
use commonware_codec::{Codec, Error as CodecError, Input, Read};
use commonware_cryptography::{Digest, Digested, Digestible, PublicKey};
use commonware_p2p::Recipients;
use commonware_parallel::Strategy;
use commonware_utils::channel::oneshot;
use std::{future::Future, marker::PhantomData};
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ExpectedCommitment<C> {
Trusted(C),
Untrusted(C),
}
pub trait Variant: Clone + Send + Sync + 'static {
type Block: Block<Digest = <Self::ApplicationBlock as Digestible>::Digest>
+ Into<Self::StoredBlock>;
type ApplicationBlock: Block + Codec;
type StoredBlock: Block<Digest = <Self::Block as Digestible>::Digest>
+ Codec<Cfg = <Self::ApplicationBlock as Read>::Cfg>;
type Commitment: Digest;
fn commitment(block: &Self::Block) -> Self::Commitment;
fn commitment_to_inner(commitment: Self::Commitment) -> <Self::Block as Digestible>::Digest;
fn parent_commitment(block: &Self::Block) -> Self::Commitment;
fn stored_parent_commitment(block: &Self::StoredBlock) -> Self::Commitment;
fn check_payload<S>(scheme: &S, payload: Self::Commitment) -> bool
where
S: Scheme<Self::Commitment>;
fn decode_block(
buf: impl Input,
block_cfg: &<Self::ApplicationBlock as Read>::Cfg,
expected: ExpectedCommitment<Self::Commitment>,
strategy: &impl Strategy,
) -> impl Future<Output = Result<Self::Block, CodecError>> + Send;
fn restore(
stored: Self::StoredBlock,
digest: <Self::Block as Digestible>::Digest,
) -> Self::Block;
fn restore_across(
stored: Self::StoredBlock,
strategy: &impl Strategy,
) -> impl Future<Output = Self::Block> + Send;
fn into_shared(block: Self::Block) -> Digested<Self::ApplicationBlock>;
fn from_application_block(
block: Digested<Self::ApplicationBlock>,
payload: Self::Commitment,
) -> Self::Block;
fn max_backfill_block_size(application: usize) -> usize;
fn max_buffer_payload_size(participants: u32, application: usize) -> usize;
}
pub trait Buffer<V: Variant>: Clone + Send + Sync + 'static {
type PublicKey: PublicKey;
fn find_by_digest(
&self,
digest: <V::Block as Digestible>::Digest,
) -> impl Future<Output = Option<V::Block>> + Send;
fn find_by_commitment(
&self,
commitment: V::Commitment,
) -> impl Future<Output = Option<V::Block>> + Send;
fn subscribe_by_digest(
&self,
digest: <V::Block as Digestible>::Digest,
) -> Option<oneshot::Receiver<V::Block>>;
fn subscribe_by_commitment(
&self,
commitment: V::Commitment,
) -> Option<oneshot::Receiver<V::Block>>;
fn send(&self, round: Round, block: V::Block, recipients: Recipients<Self::PublicKey>);
}
pub(super) struct NoBuffer<P> {
_public_key: PhantomData<fn() -> P>,
}
impl<P> NoBuffer<P> {
pub(super) const fn new() -> Self {
Self {
_public_key: PhantomData,
}
}
}
impl<P> Clone for NoBuffer<P> {
fn clone(&self) -> Self {
*self
}
}
impl<P> Copy for NoBuffer<P> {}
impl<V, P> Buffer<V> for NoBuffer<P>
where
V: Variant,
P: PublicKey,
{
type PublicKey = P;
async fn find_by_digest(&self, _: <V::Block as Digestible>::Digest) -> Option<V::Block> {
None
}
async fn find_by_commitment(&self, _: V::Commitment) -> Option<V::Block> {
None
}
fn subscribe_by_digest(
&self,
_: <V::Block as Digestible>::Digest,
) -> Option<oneshot::Receiver<V::Block>> {
None
}
fn subscribe_by_commitment(&self, _: V::Commitment) -> Option<oneshot::Receiver<V::Block>> {
None
}
fn send(&self, _: Round, _: V::Block, _: Recipients<Self::PublicKey>) {}
}