liminal_protocol/lifecycle/checkpoint_codec/
owner_tokens.rs1use super::{
2 Reader, Writer, read_committed_terminal, read_ordinary_authority, write_committed_terminal,
3 write_epoch, write_ordinary_authority, write_wide,
4};
5use crate::lifecycle::{
6 BindingOrigin, CapsuleDecodeError, ClosureState, FencedAttachCommit,
7 OrdinaryBindingAuthorityRestore, OrdinaryBindingFateRestore, SealedBindingFateToken,
8 StorageRestoreError, StoredEdge,
9};
10use alloc::vec::Vec;
11
12#[derive(Clone, Copy, Debug, PartialEq, Eq)]
14pub enum OwnerCheckpointRestoreError {
15 Framing(CapsuleDecodeError),
17 Provenance(StorageRestoreError),
19 Field(&'static str),
21}
22
23pub(in crate::lifecycle) fn encode_ordinary_fate(fate: &OrdinaryBindingFateRestore) -> Vec<u8> {
24 let mut w = Writer::default();
25 write_ordinary_authority(&mut w, fate.authority);
26 write_committed_terminal(&mut w, fate.terminal);
27 w.put_u64(fate.resulting_floor);
28 w.bytes
29}
30
31pub(in crate::lifecycle) fn decode_ordinary_fate(
32 body: &[u8],
33) -> Result<OrdinaryBindingFateRestore, OwnerCheckpointRestoreError> {
34 let read = || -> Result<_, CapsuleDecodeError> {
35 let mut r = Reader::new(body, 8);
36 let fate = OrdinaryBindingFateRestore {
37 authority: read_ordinary_authority(&mut r)?,
38 terminal: read_committed_terminal(&mut r)?,
39 resulting_floor: r.take_u64()?,
40 };
41 r.finish()?;
42 Ok(fate)
43 };
44 read().map_err(OwnerCheckpointRestoreError::Framing)
45}
46
47pub(in crate::lifecycle) fn encode_fate_token(
48 token: &SealedBindingFateToken,
49) -> Result<Vec<u8>, OwnerCheckpointRestoreError> {
50 let mut w = Writer::default();
51 w.put_u64(token.cursor);
52 match (&token.ordinary, &token.recovered) {
53 (Some(ordinary), None) if ordinary.through_seq() == token.cursor => {
54 w.put_u8(1);
55 write_ordinary_authority(
56 &mut w,
57 OrdinaryBindingAuthorityRestore {
58 binding: ordinary.binding(),
59 through_seq: ordinary.through_seq(),
60 },
61 );
62 }
63 (None, Some(proof)) => {
64 w.put_u8(2);
65 w.put_u64(proof.conversation_id());
66 w.put_u64(proof.participant_id());
67 w.put_u64(proof.marker_delivery_seq());
68 write_epoch(&mut w, proof.prior_binding_epoch());
69 write_epoch(&mut w, proof.new_binding_epoch());
70 match proof.next_state() {
71 ClosureState::Clear => w.put_u8(1),
72 ClosureState::Owed {
73 debt,
74 edge: StoredEdge::ObserverProjection(edge),
75 } => {
76 w.put_u8(2);
77 write_wide(&mut w, debt.value());
78 w.put_u64(edge.through_seq());
79 }
80 ClosureState::Owed {
81 debt,
82 edge: StoredEdge::PhysicalCompaction(edge),
83 } => {
84 w.put_u8(3);
85 write_wide(&mut w, debt.value());
86 w.put_u64(edge.from_floor());
87 w.put_u64(edge.through_seq());
88 }
89 ClosureState::Owed { .. } => {
90 return Err(OwnerCheckpointRestoreError::Field("sealed_fate.successor"));
91 }
92 }
93 }
94 _ => {
95 return Err(OwnerCheckpointRestoreError::Field(
96 "sealed_fate.class_or_cursor",
97 ));
98 }
99 }
100 Ok(w.bytes)
101}
102
103pub(in crate::lifecycle) fn restore_fate_token(
104 body: &[u8],
105 origin: &BindingOrigin,
106 cursor: u64,
107 recovered: Option<FencedAttachCommit>,
108) -> Result<SealedBindingFateToken, OwnerCheckpointRestoreError> {
109 let mut r = Reader::new(body, 7);
110 let saved_cursor = r.take_u64().map_err(OwnerCheckpointRestoreError::Framing)?;
111 if saved_cursor != cursor {
112 return Err(OwnerCheckpointRestoreError::Field("sealed_fate.cursor"));
113 }
114 match r.take_u8().map_err(OwnerCheckpointRestoreError::Framing)? {
115 1 => {
116 if recovered.is_some() {
117 return Err(OwnerCheckpointRestoreError::Field(
118 "sealed_fate.unexpected_recovered_proof",
119 ));
120 }
121 let ordinary = read_ordinary_authority(&mut r)
122 .map_err(OwnerCheckpointRestoreError::Framing)?
123 .restore_with_origin(origin)
124 .map_err(OwnerCheckpointRestoreError::Provenance)?;
125 r.finish().map_err(OwnerCheckpointRestoreError::Framing)?;
126 if ordinary.through_seq() != cursor {
127 return Err(OwnerCheckpointRestoreError::Field(
128 "sealed_fate.ordinary_cursor",
129 ));
130 }
131 Ok(SealedBindingFateToken {
132 ordinary: Some(ordinary),
133 recovered: None,
134 cursor,
135 })
136 }
137 2 => {
138 let proof = recovered.ok_or(OwnerCheckpointRestoreError::Field(
139 "sealed_fate.missing_validated_fenced_proof",
140 ))?;
141 let saved_origin = (
142 origin.conversation_id(),
143 origin.participant_id(),
144 origin.binding_epoch(),
145 origin.recovered_marker(),
146 );
147 let proof_origin = (
148 proof.conversation_id(),
149 proof.participant_id(),
150 proof.new_binding_epoch(),
151 Some((proof.marker_delivery_seq(), proof.prior_binding_epoch())),
152 );
153 if saved_origin != proof_origin {
154 return Err(OwnerCheckpointRestoreError::Field(
155 "sealed_fate.recovered_origin",
156 ));
157 }
158 let token = SealedBindingFateToken {
159 ordinary: None,
160 recovered: Some(proof),
161 cursor,
162 };
163 if encode_fate_token(&token)? != body {
164 return Err(OwnerCheckpointRestoreError::Field(
165 "sealed_fate.recovered_source",
166 ));
167 }
168 Ok(token)
169 }
170 _ => Err(OwnerCheckpointRestoreError::Field("sealed_fate.class")),
171 }
172}