use alloc::vec::Vec;
use crypto::hashes::{blake2b::Blake2b256, Digest};
use packable::{
bounded::BoundedU16,
error::{UnpackError, UnpackErrorExt},
packer::Packer,
prefix::BoxedSlicePrefix,
unpacker::Unpacker,
Packable, PackableExt,
};
use crate::{
parent::Parents,
payload::milestone::{MerkleRoot, MilestoneId, MilestoneIndex, MilestoneOptions},
protocol::ProtocolParameters,
Error,
};
pub(crate) type MilestoneMetadataLength = BoundedU16<{ u16::MIN }, { u16::MAX }>;
#[derive(Clone, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct MilestoneEssence {
index: MilestoneIndex,
timestamp: u32,
protocol_version: u8,
previous_milestone_id: MilestoneId,
parents: Parents,
inclusion_merkle_root: MerkleRoot,
applied_merkle_root: MerkleRoot,
metadata: BoxedSlicePrefix<u8, MilestoneMetadataLength>,
options: MilestoneOptions,
}
impl MilestoneEssence {
#[allow(clippy::too_many_arguments)]
pub fn new(
index: MilestoneIndex,
timestamp: u32,
protocol_version: u8,
previous_milestone_id: MilestoneId,
parents: Parents,
inclusion_merkle_root: MerkleRoot,
applied_merkle_root: MerkleRoot,
metadata: Vec<u8>,
options: MilestoneOptions,
) -> Result<Self, Error> {
let metadata = metadata
.into_boxed_slice()
.try_into()
.map_err(Error::InvalidMilestoneMetadataLength)?;
Ok(Self {
index,
timestamp,
protocol_version,
previous_milestone_id,
parents,
inclusion_merkle_root,
applied_merkle_root,
metadata,
options,
})
}
pub fn index(&self) -> MilestoneIndex {
self.index
}
pub fn timestamp(&self) -> u32 {
self.timestamp
}
pub fn protocol_version(&self) -> u8 {
self.protocol_version
}
pub fn previous_milestone_id(&self) -> &MilestoneId {
&self.previous_milestone_id
}
pub fn parents(&self) -> &Parents {
&self.parents
}
pub fn inclusion_merkle_root(&self) -> &MerkleRoot {
&self.inclusion_merkle_root
}
pub fn applied_merkle_root(&self) -> &MerkleRoot {
&self.applied_merkle_root
}
pub fn metadata(&self) -> &[u8] {
&self.metadata
}
pub fn options(&self) -> &MilestoneOptions {
&self.options
}
pub fn hash(&self) -> [u8; 32] {
Blake2b256::digest(&self.pack_to_vec()).into()
}
}
impl Packable for MilestoneEssence {
type UnpackError = Error;
type UnpackVisitor = ProtocolParameters;
fn pack<P: Packer>(&self, packer: &mut P) -> Result<(), P::Error> {
self.index.pack(packer)?;
self.timestamp.pack(packer)?;
self.protocol_version.pack(packer)?;
self.previous_milestone_id.pack(packer)?;
self.parents.pack(packer)?;
self.inclusion_merkle_root.pack(packer)?;
self.applied_merkle_root.pack(packer)?;
self.metadata.pack(packer)?;
self.options.pack(packer)?;
Ok(())
}
fn unpack<U: Unpacker, const VERIFY: bool>(
unpacker: &mut U,
visitor: &Self::UnpackVisitor,
) -> Result<Self, UnpackError<Self::UnpackError, U::Error>> {
let index = MilestoneIndex::unpack::<_, VERIFY>(unpacker, &()).coerce()?;
let timestamp = u32::unpack::<_, VERIFY>(unpacker, &()).coerce()?;
let protocol_version = u8::unpack::<_, VERIFY>(unpacker, &()).coerce()?;
if VERIFY && protocol_version != visitor.protocol_version() {
return Err(UnpackError::Packable(Error::ProtocolVersionMismatch {
expected: visitor.protocol_version(),
actual: protocol_version,
}));
}
let previous_milestone_id = MilestoneId::unpack::<_, VERIFY>(unpacker, &()).coerce()?;
let parents = Parents::unpack::<_, VERIFY>(unpacker, &())?;
let inclusion_merkle_root = MerkleRoot::unpack::<_, VERIFY>(unpacker, &()).coerce()?;
let applied_merkle_root = MerkleRoot::unpack::<_, VERIFY>(unpacker, &()).coerce()?;
let metadata = BoxedSlicePrefix::<u8, MilestoneMetadataLength>::unpack::<_, VERIFY>(unpacker, &())
.map_packable_err(|e| Error::InvalidMilestoneMetadataLength(e.into_prefix_err().into()))?;
let options = MilestoneOptions::unpack::<_, VERIFY>(unpacker, visitor)?;
Ok(Self {
index,
timestamp,
protocol_version,
previous_milestone_id,
parents,
inclusion_merkle_root,
applied_merkle_root,
metadata,
options,
})
}
}