use std::error::Error;
use liminal_protocol::wire::{
AttachSecret, ClientRequest, ConnectionIncarnation, EnrollmentRequest, EnrollmentToken,
ServerValue, StaleAuthority,
};
use super::ProductionParticipantHandler;
use super::tests::{dispatch, open_disk_store_for_tests, test_participant_config};
use super::tests_capacity::capacity_config;
use super::tests_receipts::{GEN_ONE, attach, attach_request, detach, enroll, generation};
fn enrollment_fingerprint_retained(
handler: &ProductionParticipantHandler,
incarnation: ConnectionIncarnation,
conversation_id: u64,
token: [u8; 16],
) -> Result<bool, Box<dyn Error>> {
let replayed = dispatch(
handler,
incarnation,
ClientRequest::Enrollment(EnrollmentRequest {
conversation_id,
enrollment_token: EnrollmentToken::new(token),
}),
)?;
match replayed {
ServerValue::ReceiptExpired(_) => Ok(true),
ServerValue::EnrollmentKnown(_) => Ok(false),
other => Err(format!(
"an enrolled token past its receipt window must answer ReceiptExpired (retained) or \
EnrollmentKnown (gone), got: {other:?}"
)
.into()),
}
}
#[test]
fn unproven_receipts_occupy_no_provenance_slot_and_proof_promotes_exactly_one()
-> Result<(), Box<dyn Error>> {
let home = tempfile::tempdir()?;
let data_dir = home.path().join("durability");
let incarnation = ConnectionIncarnation::new(137, 1);
let store = open_disk_store_for_tests(&data_dir)?;
let config = capacity_config(|c| c.max_receipt_provenance_per_participant = 1);
let handler = ProductionParticipantHandler::new(store, config)?;
let conversation_id = 801;
let enrollment_token = [0x71; 16];
let receipt = enroll(&handler, incarnation, conversation_id, enrollment_token)?;
let participant_id = receipt.participant_id();
enroll(&handler, incarnation, 802, [0x72; 16])?;
detach(
&handler,
incarnation,
conversation_id,
participant_id,
GEN_ONE,
[0x73; 16],
)?;
let first = attach(
&handler,
incarnation,
attach_request(
conversation_id,
participant_id,
GEN_ONE,
receipt.attach_secret(),
[0x74; 16],
),
)?;
assert_eq!(first.capability_generation(), generation(2)?);
assert!(
enrollment_fingerprint_retained(&handler, incarnation, conversation_id, enrollment_token)?,
"the proving rotation must promote the ENROLLMENT fingerprint and nothing else; a \
just-minted attach receipt that also occupied would have displaced it out of the \
participant's single slot"
);
detach(
&handler,
incarnation,
conversation_id,
participant_id,
generation(2)?,
[0x75; 16],
)?;
let second = attach(
&handler,
incarnation,
attach_request(
conversation_id,
participant_id,
generation(2)?,
first.attach_secret(),
[0x76; 16],
),
)?;
assert_eq!(second.capability_generation(), generation(3)?);
assert!(
!enrollment_fingerprint_retained(&handler, incarnation, conversation_id, enrollment_token)?,
"a full window must displace its oldest member for the newer fingerprint of the same \
participant"
);
Ok(())
}
#[test]
fn the_just_minted_attach_receipt_holds_no_provenance_slot() -> Result<(), Box<dyn Error>> {
let home = tempfile::tempdir()?;
let data_dir = home.path().join("durability");
let incarnation = ConnectionIncarnation::new(138, 1);
let store = open_disk_store_for_tests(&data_dir)?;
let config = capacity_config(|c| c.max_receipt_provenance_per_participant = 1);
let handler = ProductionParticipantHandler::new(store, config)?;
let conversation_id = 803;
let enrollment_token = [0x77; 16];
let receipt = enroll(&handler, incarnation, conversation_id, enrollment_token)?;
let participant_id = receipt.participant_id();
detach(
&handler,
incarnation,
conversation_id,
participant_id,
GEN_ONE,
[0x78; 16],
)?;
let first_token = [0x79; 16];
let first = attach(
&handler,
incarnation,
attach_request(
conversation_id,
participant_id,
GEN_ONE,
receipt.attach_secret(),
first_token,
),
)?;
assert!(
enrollment_fingerprint_retained(&handler, incarnation, conversation_id, enrollment_token)?,
"an unproven just-minted receipt must not take the participant's only provenance slot"
);
detach(
&handler,
incarnation,
conversation_id,
participant_id,
generation(2)?,
[0x7A; 16],
)?;
let second = attach(
&handler,
incarnation,
attach_request(
conversation_id,
participant_id,
generation(2)?,
first.attach_secret(),
[0x7B; 16],
),
)?;
assert_eq!(second.capability_generation(), generation(3)?);
assert!(
!enrollment_fingerprint_retained(&handler, incarnation, conversation_id, enrollment_token)?,
"the newly PROVEN generation-2 fingerprint must take the single slot"
);
let retired = dispatch(
&handler,
incarnation,
attach_request(
conversation_id,
participant_id,
GEN_ONE,
receipt.attach_secret(),
first_token,
),
)?;
assert!(
matches!(retired, ServerValue::ReceiptExpired(_)),
"the newly proven fingerprint must be the one the window retained, got: {retired:?}"
);
Ok(())
}
#[test]
fn r_c0_token_phase_classification_is_unchanged_by_observed_provenance_retention()
-> Result<(), Box<dyn Error>> {
let home = tempfile::tempdir()?;
let data_dir = home.path().join("durability");
let incarnation = ConnectionIncarnation::new(139, 1);
let store = open_disk_store_for_tests(&data_dir)?;
let handler = ProductionParticipantHandler::new(store, test_participant_config())?;
let conversation_id = 804;
let receipt = enroll(&handler, incarnation, conversation_id, [0x7C; 16])?;
let participant_id = receipt.participant_id();
detach(
&handler,
incarnation,
conversation_id,
participant_id,
GEN_ONE,
[0x7D; 16],
)?;
let first = attach(
&handler,
incarnation,
attach_request(
conversation_id,
participant_id,
GEN_ONE,
receipt.attach_secret(),
[0x7E; 16],
),
)?;
detach(
&handler,
incarnation,
conversation_id,
participant_id,
generation(2)?,
[0x7F; 16],
)?;
let second = attach(
&handler,
incarnation,
attach_request(
conversation_id,
participant_id,
generation(2)?,
first.attach_secret(),
[0x80; 16],
),
)?;
assert_eq!(second.capability_generation(), generation(3)?);
let exact_old = dispatch(
&handler,
incarnation,
attach_request(
conversation_id,
participant_id,
GEN_ONE,
second.attach_secret(),
[0x7E; 16],
),
)?;
assert!(
matches!(exact_old, ServerValue::ReceiptExpired(_)),
"an exact retired attempt token inside its provenance window must answer the \
ReceiptExpired row from its retained fingerprint; retention stopped feeding \
classification: {exact_old:?}"
);
let unknown_in_window = dispatch(
&handler,
incarnation,
attach_request(
conversation_id,
participant_id,
GEN_ONE,
AttachSecret::new([0xAB; 32]),
[0x81; 16],
),
)?;
let ServerValue::StaleAuthority(StaleAuthority::Live {
current_generation, ..
}) = unknown_in_window
else {
return Err(format!(
"an unknown token at the superseded generation must keep the StaleAuthority \
no-commit proof; the in-window fingerprint set is no longer complete: \
{unknown_in_window:?}"
)
.into());
};
assert_eq!(current_generation, generation(3)?);
Ok(())
}