ic_memory/ledger/
payload.rs1const LEDGER_PAYLOAD_MAGIC: &[u8; 8] = b"ICMEMLED";
2const LEDGER_PAYLOAD_HEADER_LEN: usize = 8 + 8;
3
4#[derive(Clone, Debug, Eq, PartialEq)]
17pub struct LedgerPayloadEnvelope {
18 payload: Vec<u8>,
19}
20
21impl LedgerPayloadEnvelope {
22 #[must_use]
24 pub const fn current(payload: Vec<u8>) -> Self {
25 Self { payload }
26 }
27
28 #[must_use]
30 pub fn encode(&self) -> Vec<u8> {
31 let mut bytes = Vec::with_capacity(LEDGER_PAYLOAD_HEADER_LEN + self.payload.len());
32 bytes.extend_from_slice(LEDGER_PAYLOAD_MAGIC);
33 bytes.extend_from_slice(
34 &u64::try_from(self.payload.len())
35 .expect("payload length does not fit in u64")
36 .to_le_bytes(),
37 );
38 bytes.extend_from_slice(&self.payload);
39 bytes
40 }
41
42 pub fn decode(bytes: &[u8]) -> Result<Self, LedgerPayloadEnvelopeError> {
44 if bytes.len() < LEDGER_PAYLOAD_HEADER_LEN {
45 return Err(LedgerPayloadEnvelopeError::Truncated {
46 actual: bytes.len(),
47 minimum: LEDGER_PAYLOAD_HEADER_LEN,
48 });
49 }
50
51 let magic = <[u8; 8]>::try_from(&bytes[0..8]).expect("magic slice length");
52 if &magic != LEDGER_PAYLOAD_MAGIC {
53 return Err(LedgerPayloadEnvelopeError::BadMagic { found: magic });
54 }
55
56 let payload_len = u64::from_le_bytes(bytes[8..16].try_into().expect("u64 slice"));
57 let payload_len = usize::try_from(payload_len)
58 .map_err(|_| LedgerPayloadEnvelopeError::PayloadTooLarge { len: payload_len })?;
59 let expected_len = LEDGER_PAYLOAD_HEADER_LEN
60 .checked_add(payload_len)
61 .ok_or(LedgerPayloadEnvelopeError::PayloadLengthOverflow { len: payload_len })?;
62 if bytes.len() != expected_len {
63 return Err(LedgerPayloadEnvelopeError::LengthMismatch {
64 declared: payload_len,
65 actual: bytes.len().saturating_sub(LEDGER_PAYLOAD_HEADER_LEN),
66 });
67 }
68
69 Ok(Self {
70 payload: bytes[LEDGER_PAYLOAD_HEADER_LEN..].to_vec(),
71 })
72 }
73
74 #[must_use]
76 pub fn payload(&self) -> &[u8] {
77 &self.payload
78 }
79}
80
81#[derive(Clone, Debug, Eq, thiserror::Error, PartialEq)]
86pub enum LedgerPayloadEnvelopeError {
87 #[error("ledger payload envelope is truncated: {actual} bytes, need at least {minimum}")]
89 Truncated {
90 actual: usize,
92 minimum: usize,
94 },
95 #[error("ledger payload envelope has bad magic {found:?}")]
97 BadMagic {
98 found: [u8; 8],
100 },
101 #[error("ledger payload envelope length {len} is too large")]
103 PayloadTooLarge {
104 len: u64,
106 },
107 #[error("ledger payload envelope length {len} overflows total length")]
109 PayloadLengthOverflow {
110 len: usize,
112 },
113 #[error("ledger payload envelope declared {declared} payload bytes but contained {actual}")]
115 LengthMismatch {
116 declared: usize,
118 actual: usize,
120 },
121}