liminal-server 0.3.3

Standalone server for the liminal messaging bus
Documentation
use std::error::Error;

use liminal_protocol::wire::{DetachedCause, DiedCause, ParticipantRecord};

use super::log::{
    StoredAttachAllocation, StoredAttachModeV3, StoredBindingEpoch, StoredComposedTerminal,
    StoredComposedTerminalCause, StoredComposedTerminalKind, StoredFencedAttachProof,
    StoredFinalizerPresentation, StoredU128,
};
use super::outbox_projection::project_attached_records;

const PARTICIPANT: u64 = 7;
const PRIOR: StoredBindingEpoch = StoredBindingEpoch {
    server_incarnation: 2,
    connection_ordinal: 3,
    capability_generation: 4,
};
const NEXT: StoredBindingEpoch = StoredBindingEpoch {
    server_incarnation: 2,
    connection_ordinal: 5,
    capability_generation: 5,
};

const fn allocation() -> StoredAttachAllocation {
    StoredAttachAllocation {
        binding_epoch: NEXT,
        attach_secret: [1; 32],
        attached_order: 20,
        attached_seq: 22,
        receipt_expires_at: StoredU128(23_u128.to_be_bytes()),
        provenance_expires_at: StoredU128(24_u128.to_be_bytes()),
        admitted_now_ms: 25,
    }
}

fn mode(
    kind: StoredComposedTerminalKind,
    cause: StoredComposedTerminalCause,
    presentation: StoredFinalizerPresentation,
) -> StoredAttachModeV3 {
    StoredAttachModeV3::Fenced {
        prior_binding_epoch: PRIOR,
        marker_delivery_seq: 11,
        marker_source_sequence: 2,
        proof: StoredFencedAttachProof {
            detached_credential_recovery: Vec::new(),
            predecessor_debt: Vec::new(),
            fenced_resulting_floor: 12,
            successor: Vec::new(),
        },
        composed_terminal: Some(StoredComposedTerminal {
            kind,
            cause,
            transaction_order: 20,
            delivery_seq: 21,
            pending_source_sequence: 3,
            presentation,
        }),
    }
}

#[test]
fn fenced_attached_projects_exact_presenting_terminal_then_attached() -> Result<(), Box<dyn Error>>
{
    let died = project_attached_records(
        PARTICIPANT,
        &allocation(),
        &mode(
            StoredComposedTerminalKind::Died,
            StoredComposedTerminalCause::ConnectionLost,
            StoredFinalizerPresentation::PresentEnclosing,
        ),
        None,
    )?;
    assert_eq!(died.len(), 2);
    assert_eq!(died[0].0, 21);
    assert!(matches!(
        &died[0].1,
        ParticipantRecord::Died {
            affected_participant_id: PARTICIPANT,
            cause: DiedCause::ConnectionLost,
            ..
        }
    ));
    assert_eq!(died[1].0, allocation().attached_seq);
    assert!(matches!(
        &died[1].1,
        ParticipantRecord::Attached {
            affected_participant_id: PARTICIPANT,
            ..
        }
    ));

    let detached = project_attached_records(
        PARTICIPANT,
        &allocation(),
        &mode(
            StoredComposedTerminalKind::Detached,
            StoredComposedTerminalCause::ServerShutdown,
            StoredFinalizerPresentation::PresentEnclosing,
        ),
        None,
    )?;
    assert!(matches!(
        &detached[0].1,
        ParticipantRecord::Detached {
            affected_participant_id: PARTICIPANT,
            cause: DetachedCause::ServerShutdown,
            ..
        }
    ));
    Ok(())
}

#[test]
fn recovered_reservation_consumer_projects_attached_without_terminal_witness()
-> Result<(), Box<dyn Error>> {
    let records = project_attached_records(
        PARTICIPANT,
        &allocation(),
        &mode(
            StoredComposedTerminalKind::Died,
            StoredComposedTerminalCause::ProtocolError,
            StoredFinalizerPresentation::ConsumeRecoveredReservation {
                recovered_source_sequence: 4,
            },
        ),
        None,
    )?;
    let [
        (
            delivery_seq,
            ParticipantRecord::Attached {
                affected_participant_id,
                ..
            },
        ),
    ] = records.as_slice()
    else {
        return Err("reservation consumer projected a terminal witness".into());
    };
    assert_eq!(*delivery_seq, allocation().attached_seq);
    assert_eq!(*affected_participant_id, PARTICIPANT);
    Ok(())
}