Skip to main content

krabka_remote_storage/worm/manifest/
linkage.rs

1//! Where a manifest sits in its partition's hash chain.
2//!
3//! The chain-position values — the epoch, the sequence number, and the head
4//! they carry — live here with `manifest_head`, which computes the head one
5//! manifest body produces from the head that preceded it.
6
7use {
8    super::{
9        ManifestBody,
10        encoding::canonical_manifest_bytes,
11        hex_bytes::{deserialize_hex32, serialize_hex},
12    },
13    derive_more::{Display, From, Into},
14    krabka_audit::chain::{GENESIS_HEAD, chain_hash},
15    serde::{Deserialize, Serialize},
16    uuid::Uuid,
17};
18
19/// Position of one manifest in its partition's hash chain.
20#[derive(
21    Debug,
22    Clone,
23    Copy,
24    PartialEq,
25    Eq,
26    Hash,
27    PartialOrd,
28    Ord,
29    Display,
30    From,
31    Into,
32    Serialize,
33    Deserialize,
34)]
35#[serde(transparent)]
36pub struct ManifestSeq(pub u64);
37
38/// Identifier of one unbroken run of a partition's chain.
39///
40/// A chain that cannot find its previous head starts a new epoch rather than
41/// silently restarting the old one at genesis.
42#[derive(
43    Debug,
44    Clone,
45    Copy,
46    PartialEq,
47    Eq,
48    Hash,
49    PartialOrd,
50    Ord,
51    Display,
52    From,
53    Into,
54    Serialize,
55    Deserialize,
56)]
57#[serde(transparent)]
58pub struct EpochId(pub Uuid);
59
60#[derive(derive_more::From, derive_more::Into)]
61/// Head of a partition's manifest hash chain.
62///
63/// Serialises as a lowercase hex string.
64#[derive(
65    Clone,
66    Copy,
67    PartialEq,
68    Eq,
69    Hash,
70    PartialOrd,
71    Ord,
72    derive_more::Debug,
73    Display,
74    Serialize,
75    Deserialize,
76)]
77#[display("{}", hex::encode(_0))]
78#[debug("ChainHead({})", hex::encode(_0))]
79#[serde(transparent)]
80pub struct ChainHead(
81    #[serde(
82        serialize_with = "serialize_hex",
83        deserialize_with = "deserialize_hex32"
84    )]
85    pub [u8; 32],
86);
87
88impl ChainHead {
89    /// The head before a chain writes its first manifest.
90    pub const GENESIS: Self = Self(GENESIS_HEAD);
91}
92
93/// Where this manifest sits in its partition's hash chain.
94#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
95#[serde(deny_unknown_fields)]
96pub struct ChainStamp {
97    /// Chain run this manifest belongs to.
98    pub epoch_id: EpochId,
99    /// Position within the run, counted from zero.
100    pub seq: ManifestSeq,
101    /// Chain head as it was before this manifest.
102    pub prev_head: ChainHead,
103}
104
105/// Chain head after `body`.
106///
107/// Chains the canonical bytes of the body onto the head the body itself
108/// records as its predecessor.
109#[must_use]
110pub fn manifest_head(body: &ManifestBody) -> ChainHead {
111    ChainHead(chain_hash(
112        &body.chain.prev_head.0,
113        body.chain.seq.0,
114        &canonical_manifest_bytes(body),
115    ))
116}
117
118#[cfg(test)]
119mod tests {
120    use {super::*, assert2::check, krabka_audit::chain::GENESIS_HEAD};
121
122    #[test]
123    fn genesis_head_is_the_audit_genesis() {
124        check!(ChainHead::GENESIS.0 == GENESIS_HEAD);
125    }
126}