liminal-protocol 0.14.0

Shared participant-lifecycle protocol types for liminal
Documentation
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;

/// Canonical owner framing or the original native provenance refusal.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum OwnerCheckpointRestoreError {
    /// Canonical framing could not be decoded.
    Framing(CapsuleDecodeError),
    /// Native origin or death provenance failed validation.
    Provenance(StorageRestoreError),
    /// The named saved field differs from its validated source.
    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")),
    }
}