extern crate alloc;
use alloc::vec::Vec;
use crate::metis::Cut;
use crate::metis::dot_set::HAVE_SET_WIRE_HEADER_LEN;
use thiserror::Error;
use super::super::gate::{EpochAddress, InvalidEpochAddress};
use super::error::WireCutError;
use super::shared::{
WIRE_ADDRESS_LEN, cut_embedding_len, decode_cut, encode_address_into, encode_cut_into,
read_address_parts,
};
const CONFIRMATION_WIRE_V1: u8 = 0x01;
const CONFIRMATION_WIRE_PREFIX_LEN: usize = 1 + WIRE_ADDRESS_LEN;
const CONFIRMATION_WIRE_MIN_LEN: usize = CONFIRMATION_WIRE_PREFIX_LEN + HAVE_SET_WIRE_HEADER_LEN;
#[non_exhaustive]
#[derive(Error, Debug, Clone, Copy, PartialEq, Eq)]
pub enum ConfirmationDecodeError {
#[error("unknown confirmation wire version: {0:#04x}")]
UnknownVersion(u8),
#[error("unexpected confirmation frame length: expected {expected}, found {found}")]
UnexpectedLength {
expected: usize,
found: usize,
},
#[error("confirmation address: {0}")]
Address(#[from] InvalidEpochAddress),
#[error("confirmation cut: {0}")]
Cut(#[from] WireCutError),
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ConfirmationRecord {
epoch: EpochAddress,
delivered: Cut,
}
impl ConfirmationRecord {
#[must_use]
pub const fn new(epoch: EpochAddress, delivered: Cut) -> Self {
Self { epoch, delivered }
}
#[must_use]
pub const fn epoch(&self) -> EpochAddress {
self.epoch
}
#[must_use]
pub const fn delivered(&self) -> &Cut {
&self.delivered
}
#[must_use]
pub fn into_parts(self) -> (EpochAddress, Cut) {
(self.epoch, self.delivered)
}
#[must_use]
pub fn to_bytes(&self) -> Vec<u8> {
let mut out = Vec::with_capacity(self.encoded_len());
out.push(CONFIRMATION_WIRE_V1);
encode_address_into(&mut out, self.epoch);
encode_cut_into(&mut out, self.delivered.as_vector());
out
}
#[must_use]
pub fn encoded_len(&self) -> usize {
CONFIRMATION_WIRE_PREFIX_LEN + cut_embedding_len(self.delivered.as_vector())
}
pub fn from_bytes(bytes: &[u8]) -> Result<Self, ConfirmationDecodeError> {
if bytes.len() < CONFIRMATION_WIRE_MIN_LEN {
return Err(ConfirmationDecodeError::UnexpectedLength {
expected: CONFIRMATION_WIRE_MIN_LEN,
found: bytes.len(),
});
}
let version = bytes[0];
if version != CONFIRMATION_WIRE_V1 {
return Err(ConfirmationDecodeError::UnknownVersion(version));
}
let short = ConfirmationDecodeError::UnexpectedLength {
expected: CONFIRMATION_WIRE_MIN_LEN,
found: bytes.len(),
};
let ((generation, dot), rest) = read_address_parts(&bytes[1..]).ok_or(short)?;
let epoch = EpochAddress::try_from_parts(generation, dot)?;
let (delivered, tail) = decode_cut(rest)?;
if !tail.is_empty() {
return Err(ConfirmationDecodeError::UnexpectedLength {
expected: bytes.len() - tail.len(),
found: bytes.len(),
});
}
Ok(Self {
epoch,
delivered: Cut::from_witnessed(delivered),
})
}
}