liminal-protocol 0.13.1

Shared participant-lifecycle protocol types for liminal
Documentation
//! Proofs that a live [`ClaimFrontiers`] describes itself back into the exact
//! restore input, ledgers, and issuance latch that reproduce it.

use alloc::vec::Vec;

use crate::{algebra::ResourceVector, outcome::ParticipantStateCorruptReason};

use super::{
    PhysicalCompaction, StoredEdge,
    claim_frontier::{
        ClaimFrontiers, ClaimFrontiersDescription, ExitProductRangeRestore, FrontierBinding,
        HistoricalMarkerDeliveryFactRestore, ImmutableOrderCandidateMajorRestore,
        MarkerRecordRequest, RecoveryOrderBlockRestore, RecoverySequenceBlock,
        RecoverySequenceBlockRestore, ReplacementTerminalProductRangeRestore,
        TerminalProductRangeRestore, ValidatedConversationHistory,
    },
    claim_frontier_tests::{
        detached_dcr_fixture, epoch, initial_enrollment_operation, recovery_candidate_fixture,
        single_bound_marker_fixture, two_participant_product_fixture,
    },
};

/// Conversation named by the detached recovery `detached_dcr_fixture` mints;
/// a fenced-marker take refuses a recovery from any other conversation.
const DCR_CONVERSATION_ID: u64 = 1;

/// Restores a description that needs no retained-marker token or stored edge.
fn restore_described(
    description: ClaimFrontiersDescription,
) -> Result<ClaimFrontiers, ParticipantStateCorruptReason> {
    let history = ValidatedConversationHistory::empty();
    ClaimFrontiers::prevalidate_description(description, &history)?.finish(None)
}

/// Asserts that every described field equals the live getter it was taken from.
fn assert_describes_live(
    frontiers: &ClaimFrontiers,
    description: &ClaimFrontiersDescription,
    retained_record_limit: u64,
) {
    let restore = &description.restore;
    assert_eq!(restore.conversation_id, frontiers.conversation_id());
    assert_eq!(
        restore.active_identities.as_slice(),
        frontiers.active_identities().participants()
    );
    assert_eq!(restore.identity_slot_limit, frontiers.identity_slot_limit());
    assert_eq!(restore.retained_floor, frontiers.retained_floor());
    assert_eq!(restore.retained_record_limit, retained_record_limit);
    assert_eq!(
        restore.retained_records.as_slice(),
        frontiers.retained_records()
    );
    let anchors: Vec<_> = frontiers
        .retained_marker_records()
        .iter()
        .map(|record| record.delivery_seq)
        .collect();
    assert_eq!(restore.active_marker_anchors, anchors);
    let deliveries: Vec<_> = frontiers
        .historical_marker_deliveries()
        .iter()
        .map(|authority| HistoricalMarkerDeliveryFactRestore {
            conversation_id: frontiers.conversation_id(),
            participant_index: authority.participant_index(),
            marker_delivery_seq: authority.marker_delivery_seq(),
            delivered_binding_epoch: authority.delivered_binding_epoch(),
        })
        .collect();
    assert_eq!(restore.historical_marker_deliveries, deliveries);
    assert_describes_live_sequence(frontiers, description);
    assert_describes_live_order(frontiers, description);
}

/// Asserts that the described sequence side equals the live sequence frontier.
fn assert_describes_live_sequence(
    frontiers: &ClaimFrontiers,
    description: &ClaimFrontiersDescription,
) {
    let restore = &description.restore;
    let sequence = frontiers.sequence();
    assert_eq!(
        restore.sequence.movable_claims.as_slice(),
        sequence.movable_claims()
    );
    assert_eq!(
        restore.sequence.immutable_candidates.as_slice(),
        sequence.immutable_candidates()
    );
    let terminal_products: Vec<_> = sequence
        .products()
        .live_times_terminal()
        .iter()
        .map(|range| TerminalProductRangeRestore {
            start: range.start(),
            length: range.length(),
            terminal: range.terminal(),
        })
        .collect();
    assert_eq!(
        restore.sequence.products.live_times_terminal,
        terminal_products
    );
    assert_eq!(
        restore.sequence.products.live_times_replacement_terminal,
        sequence
            .products()
            .live_times_replacement_terminal()
            .map(|range| ReplacementTerminalProductRangeRestore {
                start: range.start(),
                length: range.length(),
            })
    );
    let exit_products: Vec<_> = sequence
        .products()
        .other_live_times_exit()
        .iter()
        .map(|range| ExitProductRangeRestore {
            start: range.start(),
            length: range.length(),
            exit_participant: range.exit_participant(),
        })
        .collect();
    assert_eq!(
        restore.sequence.products.other_live_times_exit,
        exit_products
    );
    assert_eq!(
        restore.sequence.recovery,
        sequence
            .recovery()
            .map(|block| RecoverySequenceBlockRestore {
                terminal: block.terminal(),
                recovery_attach_seq: block.recovery_attach_seq(),
                replacement_terminal_seq: block.replacement_terminal_seq(),
            })
    );
    assert_eq!(
        restore.recovery_marker_delivery_seq,
        sequence
            .recovery()
            .map(RecoverySequenceBlock::marker_delivery_seq)
    );
    assert_eq!(description.sequence_ledger, sequence.ledger());
}

/// Asserts that the described order side equals the live order frontier.
fn assert_describes_live_order(
    frontiers: &ClaimFrontiers,
    description: &ClaimFrontiersDescription,
) {
    let restore = &description.restore;
    let order = frontiers.order();
    assert_eq!(
        restore.order.movable_claims.as_slice(),
        order.movable_claims()
    );
    let order_candidates: Vec<_> = order
        .immutable_candidates()
        .iter()
        .map(|major| ImmutableOrderCandidateMajorRestore {
            transaction_order: major.transaction_order(),
            candidate_keys: major.candidate_keys().to_vec(),
        })
        .collect();
    assert_eq!(restore.order.immutable_candidates, order_candidates);
    assert_eq!(
        restore.order.recovery,
        order.recovery().map(|block| RecoveryOrderBlockRestore {
            active_binding: block.active_binding(),
            recovery_operation_order: block.recovery_operation_order(),
            replacement_terminal_order: block.replacement_terminal_order(),
        })
    );
    assert_eq!(description.order_ledger, order.ledger());
}

#[test]
fn a_restored_marker_frontier_describes_its_exact_restore_input() -> Result<(), &'static str> {
    for (marker_major, marker_above_high) in [(0, false), (1, true)] {
        let (restore, sequence, order) =
            single_bound_marker_fixture(marker_major, marker_above_high);
        let frontiers = ClaimFrontiers::restore(restore.clone(), sequence, order)
            .map_err(|_| "the bound marker fixture restores")?;

        let description = frontiers.describe(restore.retained_record_limit);
        assert_describes_live(&frontiers, &description, restore.retained_record_limit);
        assert_eq!(
            description.restore, restore,
            "the input comes back unchanged"
        );
        assert_eq!(description.sequence_ledger, sequence);
        assert_eq!(description.order_ledger, order);
        assert_eq!(description.fenced_marker_issued, None);

        let restored = restore_described(description)
            .map_err(|_| "the description of a restored frontier restores")?;
        assert_eq!(restored, frontiers);
    }
    Ok(())
}

#[test]
fn a_two_participant_product_frontier_round_trips() -> Result<(), &'static str> {
    let (restore, sequence, order) = two_participant_product_fixture();
    let frontiers = ClaimFrontiers::restore(restore.clone(), sequence, order)
        .map_err(|_| "the two-participant product fixture restores")?;

    let description = frontiers.describe(restore.retained_record_limit);
    assert_describes_live(&frontiers, &description, restore.retained_record_limit);
    assert_eq!(
        description.restore, restore,
        "the input comes back unchanged"
    );

    let restored =
        restore_described(description).map_err(|_| "the described product frontier restores")?;
    assert_eq!(restored, frontiers);
    Ok(())
}

#[test]
fn a_drained_marker_frontier_describes_its_new_retained_anchor() -> Result<(), &'static str> {
    let (restore, sequence, order) = single_bound_marker_fixture(0, false);
    let frontiers = ClaimFrontiers::restore(restore, sequence, order)
        .map_err(|_| "the bound marker fixture restores")?;
    let (drained, _candidate, record) = frontiers
        .drain_next_marker_core()
        .map_err(|_| "the exact next bound marker drains")?
        .into_parts();
    record.consume();

    let retained_record_limit = u64::try_from(drained.retained_records().len())
        .map_err(|_| "the retained corpus fits u64")?;
    let description = drained.describe(retained_record_limit);
    assert_describes_live(&drained, &description, retained_record_limit);
    assert_eq!(description.restore.active_marker_anchors, [1]);
    assert!(description.restore.historical_causal_facts.is_empty());

    let restored = restore_described(description)
        .map_err(|_| "the description of a live drained frontier restores")?;
    assert_eq!(restored, drained);
    Ok(())
}

#[test]
fn an_initial_enrollment_frontier_round_trips() -> Result<(), &'static str> {
    let committed = ClaimFrontiers::from_initial_enrollment(
        initial_enrollment_operation(ResourceVector::new(6, 24)),
        ResourceVector::new(1, 4),
    )
    .map_err(|_| "the clear initial frontier is exact")?;
    let frontiers = committed.frontiers();

    let retained_record_limit = u64::try_from(frontiers.retained_records().len())
        .map_err(|_| "the retained corpus fits u64")?;
    let description = frontiers.describe(retained_record_limit);
    assert_describes_live(frontiers, &description, retained_record_limit);
    assert!(description.restore.historical_marker_deliveries.is_empty());
    assert!(description.restore.historical_causal_facts.is_empty());
    assert_eq!(description.fenced_marker_issued, None);

    let restored = restore_described(description)
        .map_err(|_| "the description of a directly constructed frontier restores")?;
    assert_eq!(&restored, frontiers);
    Ok(())
}

#[test]
fn a_prefate_recovery_frontier_describes_its_blocks_without_provenance() -> Result<(), &'static str>
{
    let binding_epoch = epoch(1, 1);
    let (restore, sequence, order) =
        recovery_candidate_fixture(FrontierBinding::Bound(binding_epoch));
    let edge = Some(StoredEdge::PhysicalCompaction(
        PhysicalCompaction::new(0, 0).ok_or("single-record compaction range")?,
    ));
    let frontiers = ClaimFrontiers::prevalidate(restore.clone(), sequence, order)
        .map_err(|_| "the candidate recovery frontier prevalidates")?
        .finish(edge)
        .map_err(|_| "PC does not hide the candidate recovery quartet")?;

    let description = frontiers.describe(restore.retained_record_limit);
    assert_describes_live(&frontiers, &description, restore.retained_record_limit);
    assert_eq!(description.restore.recovery_marker_delivery_seq, Some(1));
    assert_eq!(
        description.restore, restore,
        "the input comes back unchanged"
    );

    let history = ValidatedConversationHistory::empty();
    let restored = ClaimFrontiers::prevalidate_description(description, &history)
        .map_err(|_| "the described recovery frontier prevalidates")?
        .finish(edge)
        .map_err(|_| "the same edge re-derives the same recovery provenance")?;
    assert_eq!(restored, frontiers);
    Ok(())
}

#[test]
fn the_fenced_marker_latch_survives_describe_and_restore() -> Result<(), &'static str> {
    let (mut restore, sequence, order, dcr, binding_epoch) = detached_dcr_fixture()?;
    // The fixture's recovery is minted for its own conversation; retarget the
    // frontier there so the fenced take can match it.
    restore.conversation_id = DCR_CONVERSATION_ID;
    for fact in &mut restore.historical_marker_deliveries {
        fact.conversation_id = DCR_CONVERSATION_ID;
    }
    let request = MarkerRecordRequest::delivered(0, 1, FrontierBinding::Detached(binding_epoch));
    let edge = Some(StoredEdge::DetachedCredentialRecovery(dcr));
    let mut prevalidated = ClaimFrontiers::prevalidate(restore.clone(), sequence, order)
        .map_err(|_| "the post-fate frontier prevalidates")?;
    prevalidated
        .take_marker_record(request)
        .ok_or("the exact retained DCR marker is selected once")?
        .consume();
    let mut frontiers = prevalidated
        .finish(edge)
        .map_err(|_| "the exact detached DCR proves the post-fate recovery pair")?;

    let unissued = frontiers.describe(restore.retained_record_limit);
    assert_eq!(unissued.fenced_marker_issued, None);
    assert_eq!(unissued.restore, restore, "the input comes back unchanged");

    frontiers
        .take_fenced_marker_record(dcr)
        .ok_or("the detached recovery takes its one fenced marker")?
        .consume();
    let issued = frontiers.describe(restore.retained_record_limit);
    assert_describes_live(&frontiers, &issued, restore.retained_record_limit);
    assert_eq!(issued.fenced_marker_issued, Some((0, 1, binding_epoch)));
    assert_eq!(
        issued.restore, restore,
        "the latch is not part of the input"
    );
    assert_eq!(
        issued.restore.historical_marker_deliveries,
        [HistoricalMarkerDeliveryFactRestore {
            conversation_id: DCR_CONVERSATION_ID,
            participant_index: 0,
            marker_delivery_seq: 1,
            delivered_binding_epoch: binding_epoch,
        }]
    );

    let history = ValidatedConversationHistory::empty();
    let mut described = ClaimFrontiers::prevalidate_description(issued.clone(), &history)
        .map_err(|_| "the described post-fate frontier prevalidates")?;
    described
        .take_marker_record(request)
        .ok_or("the described retained DCR marker is selected once")?
        .consume();
    let mut restored = described
        .finish(edge)
        .map_err(|_| "the described frontier finishes against the same edge")?;
    assert_eq!(
        restored, frontiers,
        "the latch is installed, not forced to None"
    );
    assert!(
        restored.take_fenced_marker_record(dcr).is_none(),
        "a restored latch still refuses a second take"
    );

    let mut public = ClaimFrontiers::prevalidate(issued.restore, sequence, order)
        .map_err(|_| "the public route prevalidates the same input")?;
    public
        .take_marker_record(request)
        .ok_or("the public route selects the same marker")?
        .consume();
    let public = public
        .finish(edge)
        .map_err(|_| "the public route finishes against the same edge")?;
    assert_ne!(public, frontiers, "the public route keeps its forced None");
    Ok(())
}