use crate::types::Height; use bytes::{Buf, BufMut}; use commonware_codec::{Codec, EncodeSize, Error, Read, ReadExt, Write, varint::UInt}; use commonware_cryptography::{Digest, Digestible, Hasher}; use std::fmt::Debug; /// A mock block with no explicit consensus context. /// Its parent digest also serves as its certification context. pub struct EmptyBlock { /// The parent block's digest. pub parent: H::Digest, /// The height of the block in the blockchain. pub height: Height, /// The timestamp of the block (in milliseconds since the Unix epoch). pub timestamp: u64, } impl EmptyBlock { pub const fn new(parent: H::Digest, height: Height, timestamp: u64) -> Self { Self { parent, height, timestamp, } } } impl Clone for EmptyBlock { fn clone(&self) -> Self { Self { parent: self.parent, height: self.height, timestamp: self.timestamp, } } } impl Debug for EmptyBlock { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("EmptyBlock") .field("parent", &self.parent) .field("height", &self.height) .field("timestamp", &self.timestamp) .finish() } } impl PartialEq for EmptyBlock { fn eq(&self, other: &Self) -> bool { self.parent == other.parent && self.height == other.height && self.timestamp == other.timestamp } } impl Eq for EmptyBlock {} impl Write for EmptyBlock { fn write(&self, writer: &mut impl BufMut) { self.parent.write(writer); self.height.write(writer); UInt(self.timestamp).write(writer); } } impl Read for EmptyBlock { type Cfg = (); fn read_cfg(reader: &mut impl Buf, _: &Self::Cfg) -> Result { let parent = H::Digest::read(reader)?; let height = Height::read(reader)?; let timestamp = UInt::read(reader)?.into(); Ok(Self { parent, height, timestamp, }) } } impl EncodeSize for EmptyBlock { fn encode_size(&self) -> usize { self.parent.encode_size() + self.height.encode_size() + UInt(self.timestamp).encode_size() } } impl Digestible for EmptyBlock { type Digest = H::Digest; fn digest(&self) -> H::Digest { H::hash(&[ self.parent.as_ref(), &self.height.get().to_be_bytes(), &self.timestamp.to_be_bytes(), ]) } } impl crate::Heightable for EmptyBlock { fn height(&self) -> Height { self.height } } impl crate::Block for EmptyBlock { fn parent(&self) -> Self::Digest { self.parent } } impl crate::CertifiableBlock for EmptyBlock { type Context = H::Digest; fn context(&self) -> Self::Context { self.parent } } /// A mock block type for testing that stores consensus context. /// /// The context type `C` should be the consensus context (e.g., `simplex::types::Context`). #[derive(Clone, Debug, PartialEq, Eq)] pub struct Block { /// The consensus context that was used when this block was proposed. pub context: C, /// The parent block's digest. pub parent: D, /// The height of the block in the blockchain. pub height: Height, /// The timestamp of the block (in milliseconds since the Unix epoch). pub timestamp: u64, /// Pre-computed digest of the block. digest: D, } impl Block { fn compute_digest>( context: &C, parent: &D, height: Height, timestamp: u64, ) -> D { H::hash(&[ parent.as_ref(), &height.get().to_be_bytes(), &context.encode(), ×tamp.to_be_bytes(), ]) } pub fn new>( context: C, parent: D, height: Height, timestamp: u64, ) -> Self { let digest = Self::compute_digest::(&context, &parent, height, timestamp); Self { context, parent, height, timestamp, digest, } } } impl Write for Block { fn write(&self, writer: &mut impl BufMut) { self.context.write(writer); self.parent.write(writer); self.height.write(writer); UInt(self.timestamp).write(writer); self.digest.write(writer); } } impl> Read for Block { type Cfg = (); fn read_cfg(reader: &mut impl Buf, _: &Self::Cfg) -> Result { let context = C::read(reader)?; let parent = D::read(reader)?; let height = Height::read(reader)?; let timestamp = UInt::read(reader)?.into(); let digest = D::read(reader)?; Ok(Self { context, parent, height, timestamp, digest, }) } } impl EncodeSize for Block { fn encode_size(&self) -> usize { self.context.encode_size() + self.parent.encode_size() + self.height.encode_size() + UInt(self.timestamp).encode_size() + self.digest.encode_size() } } impl Digestible for Block { type Digest = D; fn digest(&self) -> D { self.digest } } impl crate::Heightable for Block { fn height(&self) -> Height { self.height } } impl + Clone + Send + Sync + 'static> crate::Block for Block { fn parent(&self) -> Self::Digest { self.parent } } impl + Clone + Send + Sync + 'static> crate::CertifiableBlock for Block { type Context = C; fn context(&self) -> Self::Context { self.context.clone() } }