pipecircuit 0.0.23

Correct. Robust. Fast. Portable. Pick four.
Documentation
use super::*;
use core::num::NonZeroU64;

fn guarantee(value: u8) -> Guarantee {
    match value {
        0 => Guarantee::Accepted,
        1 => Guarantee::LocallyDurable,
        _ => Guarantee::ReplicatedDurable,
    }
}
fn receipt(sequence: u64) -> Receipt {
    Receipt::from_operation(OperationId {
        history: HistoryId([7; 16]),
        epoch: 1,
        session: SessionId(1),
        sequence,
    })
}
fn invariant(command: &PendingMutation<u8>) -> bool {
    (command.status == MutationStatus::AwaitingReply) == command.request.is_some()
}
#[kani::proof]
fn initialization_retains_exact_operation() {
    let receipt = receipt(kani::any());
    let command: u8 = kani::any();
    let guarantee = guarantee(kani::any());
    let result = PendingMutation::new(TableRequest::<(), _>::Mutate {
        receipt,
        command,
        guarantee,
    });
    assert!(result.is_ok());
    if let Ok(pending) = result {
        assert!(invariant(&pending));
        assert_eq!(pending.status(), MutationStatus::Ready);
        assert_eq!(pending.receipt(), receipt);
        assert_eq!(*pending.command(), command);
        assert_eq!(pending.guarantee(), guarantee);
        kani::cover!(
            pending.status() == MutationStatus::Ready,
            "pending.initialized"
        );
    }
}
#[kani::proof]
fn arbitrary_step_preserves_receipt_and_confirmation() {
    let status = match kani::any::<u8>() {
        0 => MutationStatus::Ready,
        1 => MutationStatus::AwaitingReply,
        2 => MutationStatus::Uncertain,
        _ => MutationStatus::Confirmed,
    };
    let required = guarantee(kani::any());
    let established = guarantee(kani::any());
    let id = RequestId(NonZeroU64::MIN);
    let command: u8 = kani::any();
    let mut pending = PendingMutation {
        receipt: receipt(1),
        command,
        guarantee: required,
        request: if status == MutationStatus::AwaitingReply {
            Some(id)
        } else {
            None
        },
        status,
    };
    assert!(invariant(&pending));
    let action: u8 = kani::any();
    let tag: u8 = kani::any();
    let matching_receipt: bool = kani::any();
    let matching_id: bool = kani::any();
    let reply_receipt = receipt(if matching_receipt { 1 } else { 2 });
    let reply: Result<TableReply<(), (), ()>, StorageFailure> = match tag {
        0 => Ok(TableReply::Mutation(MutationAnswer::Pending {
            receipt: reply_receipt,
            outcome: Ok(()),
            established,
        })),
        1 => Ok(TableReply::Mutation(MutationAnswer::Confirmed {
            receipt: reply_receipt,
            outcome: Ok(()),
            established,
        })),
        2 => Ok(TableReply::Mutation(MutationAnswer::Unknown)),
        3 => Ok(TableReply::Mutation(MutationAnswer::Unavailable(
            Error::ExpiredOperation,
        ))),
        4 => Err(StorageFailure::WorkerClosed),
        5 => Ok(TableReply::Read(Answer::Pending)),
        _ => Ok(TableReply::Retired(Ok(()))),
    };
    match action {
        0 => {
            let _request = pending.retry::<(), ()>(id);
        }
        1 => {
            let _request = pending.inquire::<(), ()>(id);
        }
        2 => {
            pending.disconnect();
        }
        _ => {
            let received = pending.step(ReceiveMutation {
                id: if matching_id {
                    id
                } else {
                    RequestId(id.0.saturating_add(1))
                },
                reply: &reply,
            });
            kani::cover!(
                received == Err(MutationReceiveError::WrongReceipt),
                "pending.wrong_receipt"
            );
            kani::cover!(
                received == Err(MutationReceiveError::InsufficientGuarantee),
                "pending.insufficient"
            );
            kani::cover!(
                tag == 2 && received == Ok(MutationStatus::Uncertain),
                "pending.unknown"
            );
        }
    }
    assert!(invariant(&pending));
    assert_eq!(pending.receipt(), receipt(1));
    assert_eq!(*pending.command(), command);
    assert_eq!(pending.guarantee(), required);
    if status == MutationStatus::Confirmed {
        assert_eq!(pending.status(), MutationStatus::Confirmed);
    }
    if status != MutationStatus::Confirmed && pending.status() == MutationStatus::Confirmed {
        assert!(action > 2 && tag == 1 && matching_id && matching_receipt);
        // Independent truth table for the three durability levels.
        assert!(
            required == Guarantee::Accepted
                || established == Guarantee::ReplicatedDurable
                || (required == Guarantee::LocallyDurable
                    && established == Guarantee::LocallyDurable)
        );
        kani::cover!(true, "pending.confirmed");
    }
    kani::cover!(
        action == 2
            && status == MutationStatus::AwaitingReply
            && pending.status() == MutationStatus::Uncertain,
        "pending.disconnected"
    );
}