use super::{
Reader, Writer, read_committed_terminal, read_ordinary_authority, write_committed_terminal,
write_epoch, write_ordinary_authority, write_wide,
};
use crate::lifecycle::{
BindingOrigin, CapsuleDecodeError, ClosureState, FencedAttachCommit,
OrdinaryBindingAuthorityRestore, OrdinaryBindingFateRestore, SealedBindingFateToken,
StorageRestoreError, StoredEdge,
};
use alloc::vec::Vec;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum OwnerCheckpointRestoreError {
Framing(CapsuleDecodeError),
Provenance(StorageRestoreError),
Field(&'static str),
}
pub(in crate::lifecycle) fn encode_ordinary_fate(fate: &OrdinaryBindingFateRestore) -> Vec<u8> {
let mut w = Writer::default();
write_ordinary_authority(&mut w, fate.authority);
write_committed_terminal(&mut w, fate.terminal);
w.put_u64(fate.resulting_floor);
w.bytes
}
pub(in crate::lifecycle) fn decode_ordinary_fate(
body: &[u8],
) -> Result<OrdinaryBindingFateRestore, OwnerCheckpointRestoreError> {
let read = || -> Result<_, CapsuleDecodeError> {
let mut r = Reader::new(body, 8);
let fate = OrdinaryBindingFateRestore {
authority: read_ordinary_authority(&mut r)?,
terminal: read_committed_terminal(&mut r)?,
resulting_floor: r.take_u64()?,
};
r.finish()?;
Ok(fate)
};
read().map_err(OwnerCheckpointRestoreError::Framing)
}
pub(in crate::lifecycle) fn encode_fate_token(
token: &SealedBindingFateToken,
) -> Result<Vec<u8>, OwnerCheckpointRestoreError> {
let mut w = Writer::default();
w.put_u64(token.cursor);
match (&token.ordinary, &token.recovered) {
(Some(ordinary), None) if ordinary.through_seq() == token.cursor => {
w.put_u8(1);
write_ordinary_authority(
&mut w,
OrdinaryBindingAuthorityRestore {
binding: ordinary.binding(),
through_seq: ordinary.through_seq(),
},
);
}
(None, Some(proof)) => {
w.put_u8(2);
w.put_u64(proof.conversation_id());
w.put_u64(proof.participant_id());
w.put_u64(proof.marker_delivery_seq());
write_epoch(&mut w, proof.prior_binding_epoch());
write_epoch(&mut w, proof.new_binding_epoch());
match proof.next_state() {
ClosureState::Clear => w.put_u8(1),
ClosureState::Owed {
debt,
edge: StoredEdge::ObserverProjection(edge),
} => {
w.put_u8(2);
write_wide(&mut w, debt.value());
w.put_u64(edge.through_seq());
}
ClosureState::Owed {
debt,
edge: StoredEdge::PhysicalCompaction(edge),
} => {
w.put_u8(3);
write_wide(&mut w, debt.value());
w.put_u64(edge.from_floor());
w.put_u64(edge.through_seq());
}
ClosureState::Owed { .. } => {
return Err(OwnerCheckpointRestoreError::Field("sealed_fate.successor"));
}
}
}
_ => {
return Err(OwnerCheckpointRestoreError::Field(
"sealed_fate.class_or_cursor",
));
}
}
Ok(w.bytes)
}
pub(in crate::lifecycle) fn restore_fate_token(
body: &[u8],
origin: &BindingOrigin,
cursor: u64,
recovered: Option<FencedAttachCommit>,
) -> Result<SealedBindingFateToken, OwnerCheckpointRestoreError> {
let mut r = Reader::new(body, 7);
let saved_cursor = r.take_u64().map_err(OwnerCheckpointRestoreError::Framing)?;
if saved_cursor != cursor {
return Err(OwnerCheckpointRestoreError::Field("sealed_fate.cursor"));
}
match r.take_u8().map_err(OwnerCheckpointRestoreError::Framing)? {
1 => {
if recovered.is_some() {
return Err(OwnerCheckpointRestoreError::Field(
"sealed_fate.unexpected_recovered_proof",
));
}
let ordinary = read_ordinary_authority(&mut r)
.map_err(OwnerCheckpointRestoreError::Framing)?
.restore_with_origin(origin)
.map_err(OwnerCheckpointRestoreError::Provenance)?;
r.finish().map_err(OwnerCheckpointRestoreError::Framing)?;
if ordinary.through_seq() != cursor {
return Err(OwnerCheckpointRestoreError::Field(
"sealed_fate.ordinary_cursor",
));
}
Ok(SealedBindingFateToken {
ordinary: Some(ordinary),
recovered: None,
cursor,
})
}
2 => {
let proof = recovered.ok_or(OwnerCheckpointRestoreError::Field(
"sealed_fate.missing_validated_fenced_proof",
))?;
let saved_origin = (
origin.conversation_id(),
origin.participant_id(),
origin.binding_epoch(),
origin.recovered_marker(),
);
let proof_origin = (
proof.conversation_id(),
proof.participant_id(),
proof.new_binding_epoch(),
Some((proof.marker_delivery_seq(), proof.prior_binding_epoch())),
);
if saved_origin != proof_origin {
return Err(OwnerCheckpointRestoreError::Field(
"sealed_fate.recovered_origin",
));
}
let token = SealedBindingFateToken {
ordinary: None,
recovered: Some(proof),
cursor,
};
if encode_fate_token(&token)? != body {
return Err(OwnerCheckpointRestoreError::Field(
"sealed_fate.recovered_source",
));
}
Ok(token)
}
_ => Err(OwnerCheckpointRestoreError::Field("sealed_fate.class")),
}
}