Skip to main content

blockworx/doc_ng/
stamp.rs

1use crate::doc_ng::{id::ActorId, lamport::Lamport};
2use serde::{Deserialize, Serialize};
3
4/// LWW arbitration: (lamport, actor), derived Ord = total order + tiebreak.
5/// Default = BOTTOM = (0, nil actor); real clocks start at 1, so BOTTOM sorts
6/// below every minted stamp.
7#[derive(
8    Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Hash, Ord, Default, Serialize, Deserialize,
9)]
10pub struct Stamp {
11    pub lamport: Lamport,
12    pub actor: ActorId,
13}
14
15impl Stamp {
16    pub const BOTTOM: Stamp = Stamp {
17        lamport: Lamport::ZERO,
18        actor: ActorId::NULL,
19    };
20}
21
22#[cfg(test)]
23mod tests {
24    use super::*;
25    use uuid::Uuid;
26
27    fn actor(byte: u8) -> ActorId {
28        ActorId::from_uuid(Uuid::from_bytes([byte; 16]))
29    }
30
31    /// The property the whole merge rests on: any two stamps from distinct
32    /// actors are ordered, so `max` over them is well defined.
33    #[test]
34    fn equal_lamports_are_broken_by_actor() {
35        let (low, high) = (actor(1), actor(2));
36        assert!(low < high, "the fixture's actors must differ to order them");
37
38        let a = Stamp {
39            lamport: Lamport::new(7),
40            actor: low,
41        };
42        let b = Stamp {
43            lamport: Lamport::new(7),
44            actor: high,
45        };
46        assert!(a < b);
47    }
48
49    /// Lamport dominates the actor tiebreak — otherwise a replica with a
50    /// high-sorting id would win every race regardless of causality.
51    #[test]
52    fn lamport_outranks_actor() {
53        let earlier = Stamp {
54            lamport: Lamport::new(7),
55            actor: actor(9),
56        };
57        let later = Stamp {
58            lamport: Lamport::new(8),
59            actor: actor(1),
60        };
61        assert!(earlier < later);
62    }
63}