use super::FixedFileLimits;
const WRITER_COMPONENT_WORK_IDENTITY: [u8; 32] = [0x6f; 32];
#[derive(Debug, Eq, PartialEq)]
pub struct WriterComponentWorkProof {
identity: [u8; 32],
version: u8,
routed_files: u8,
reliability_domains: u8,
max_parallel_filesystem_ops: u8,
shutdown_barrier_files: u8,
write_interrupt_retries: u8,
rotation_publish_attempts: u8,
directory_syncs_per_rotation: u8,
hard_link_no_replace: bool,
rename_ops_per_rotation: u8,
bounded_retention_scan: bool,
shutdown_requires_zero_encoding_owners: bool,
requires_deployment_filesystem_proof: bool,
}
#[doc(hidden)]
pub const fn writer_component_work_proof() -> WriterComponentWorkProof {
WriterComponentWorkProof {
identity: WRITER_COMPONENT_WORK_IDENTITY,
version: 1,
routed_files: 4,
reliability_domains: 1,
max_parallel_filesystem_ops: 1,
shutdown_barrier_files: 4,
write_interrupt_retries: 8,
rotation_publish_attempts: 8,
directory_syncs_per_rotation: 4,
hard_link_no_replace: true,
rename_ops_per_rotation: 0,
bounded_retention_scan: true,
shutdown_requires_zero_encoding_owners: true,
requires_deployment_filesystem_proof: true,
}
}
impl WriterComponentWorkProof {
pub const fn identity(&self) -> [u8; 32] {
self.identity
}
pub const fn version(&self) -> u8 {
self.version
}
pub const fn routed_files(&self) -> u8 {
self.routed_files
}
pub const fn reliability_domains(&self) -> u8 {
self.reliability_domains
}
pub const fn max_parallel_filesystem_ops(&self) -> u8 {
self.max_parallel_filesystem_ops
}
pub const fn shutdown_barrier_files(&self) -> u8 {
self.shutdown_barrier_files
}
pub const fn write_interrupt_retries(&self) -> u8 {
self.write_interrupt_retries
}
pub const fn rotation_publish_attempts(&self) -> u8 {
self.rotation_publish_attempts
}
pub const fn directory_syncs_per_rotation(&self) -> u8 {
self.directory_syncs_per_rotation
}
pub const fn hard_link_no_replace(&self) -> bool {
self.hard_link_no_replace
}
pub const fn rename_ops_per_rotation(&self) -> u8 {
self.rename_ops_per_rotation
}
pub const fn bounded_retention_scan(&self) -> bool {
self.bounded_retention_scan
}
pub const fn shutdown_requires_zero_encoding_owners(&self) -> bool {
self.shutdown_requires_zero_encoding_owners
}
pub const fn requires_deployment_filesystem_proof(&self) -> bool {
self.requires_deployment_filesystem_proof
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum FilesystemTarget {
LinuxX86_64,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct FilesystemDeploymentIdentity {
pub target: FilesystemTarget,
pub environment: [u8; 32],
pub filesystem: [u8; 32],
pub mount: [u8; 32],
pub build: [u8; 32],
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct FilesystemWorkDomain {
pub max_write_ops: u64,
pub max_write_bytes: u64,
pub max_file_sync_ops: u64,
pub max_file_sync_bytes: u64,
pub max_directory_sync_ops: u64,
pub max_hard_link_ops: u64,
pub max_rename_ops: u64,
pub max_unlink_ops: u64,
pub max_create_ops: u64,
pub max_scan_ops: u64,
pub max_scan_entries: u64,
pub max_parallel_filesystem_ops: u64,
pub advisory_lock: bool,
pub hard_link_no_replace: bool,
pub directory_fsync: bool,
pub data_fsync: bool,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct FilesystemServiceRates {
pub write_op_nanos: u64,
pub write_byte_nanos: u64,
pub file_sync_op_nanos: u64,
pub file_sync_byte_nanos: u64,
pub directory_sync_op_nanos: u64,
pub hard_link_op_nanos: u64,
pub rename_op_nanos: u64,
pub unlink_op_nanos: u64,
pub create_op_nanos: u64,
pub scan_op_nanos: u64,
pub scan_entry_nanos: u64,
}
pub trait DeploymentFilesystemServiceAttestation: Sized {
fn target(&self) -> FilesystemTarget;
fn approved(&self) -> bool;
fn reproducible_measurement(&self) -> bool;
fn conservative_upper_bound(&self) -> bool;
fn work_domain(&self) -> FilesystemWorkDomain;
fn service_rates(&self) -> FilesystemServiceRates;
fn calibration_identity(&self) -> [u8; 32];
fn environment_identity(&self) -> [u8; 32];
fn filesystem_identity(&self) -> [u8; 32];
fn mount_identity(&self) -> [u8; 32];
fn service_attestation(&self) -> [u8; 32];
fn build_identity(&self) -> [u8; 32];
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum FilesystemProofError {
Unapproved,
ComponentMismatch,
InvalidIdentity,
InvalidDomain,
InvalidService,
DomainMismatch,
Overflow,
}
#[derive(Debug)]
pub struct VerifiedFilesystemServiceProof {
target: FilesystemTarget,
domain: FilesystemWorkDomain,
rates: FilesystemServiceRates,
environment_identity: [u8; 32],
filesystem_identity: [u8; 32],
mount_identity: [u8; 32],
calibration_identity: [u8; 32],
service_attestation: [u8; 32],
build_identity: [u8; 32],
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct WriterWorkProof {
schema_identity: [u8; 32],
work: FilesystemWorkDomain,
queued_records: u64,
queued_bytes: u64,
preexisting_dirty_bytes: u64,
rotations: u64,
serial_filesystem: bool,
shutdown_requires_zero_encoding_owners: bool,
}
impl WriterWorkProof {
pub const fn schema_identity(&self) -> [u8; 32] {
self.schema_identity
}
pub const fn filesystem_work(&self) -> FilesystemWorkDomain {
self.work
}
pub const fn queued_records(&self) -> u64 {
self.queued_records
}
pub const fn queued_bytes(&self) -> u64 {
self.queued_bytes
}
pub const fn preexisting_dirty_bytes(&self) -> u64 {
self.preexisting_dirty_bytes
}
pub const fn rotations(&self) -> u64 {
self.rotations
}
pub const fn serial_filesystem(&self) -> bool {
self.serial_filesystem
}
pub const fn shutdown_requires_zero_encoding_owners(&self) -> bool {
self.shutdown_requires_zero_encoding_owners
}
}
#[derive(Debug)]
pub struct WriterTerminationProof {
basis: WriterTerminationBasis,
work_identity: [u8; 32],
max_service_nanos: u64,
environment_identity: [u8; 32],
filesystem_identity: [u8; 32],
mount_identity: [u8; 32],
calibration_identity: [u8; 32],
service_attestation: [u8; 32],
build_identity: [u8; 32],
}
#[derive(Debug)]
enum WriterTerminationBasis {
Actual(WriterWorkProof),
ProviderDomain(FilesystemWorkDomain),
}
impl WriterTerminationProof {
pub const fn actual_work(&self) -> Option<&WriterWorkProof> {
match &self.basis {
WriterTerminationBasis::Actual(work) => Some(work),
WriterTerminationBasis::ProviderDomain(_) => None,
}
}
pub const fn provider_domain_upper_bound(&self) -> Option<FilesystemWorkDomain> {
match self.basis {
WriterTerminationBasis::Actual(_) => None,
WriterTerminationBasis::ProviderDomain(domain) => Some(domain),
}
}
pub const fn max_service_nanos(&self) -> u64 {
self.max_service_nanos
}
pub const fn environment_identity(&self) -> [u8; 32] {
self.environment_identity
}
pub const fn filesystem_identity(&self) -> [u8; 32] {
self.filesystem_identity
}
pub const fn mount_identity(&self) -> [u8; 32] {
self.mount_identity
}
pub const fn calibration_identity(&self) -> [u8; 32] {
self.calibration_identity
}
pub const fn service_attestation(&self) -> [u8; 32] {
self.service_attestation
}
pub const fn build_identity(&self) -> [u8; 32] {
self.build_identity
}
}
impl saddle_admission::VerifiedFilesystemTerminationServiceProofOwner for WriterTerminationProof {
fn work_identity(&self) -> [u8; 32] {
self.work_identity
}
fn service_attestation(&self) -> [u8; 32] {
self.service_attestation()
}
fn max_service_nanos(&self) -> u64 {
self.max_service_nanos()
}
}
pub fn verify_provider_writer_termination(
component: WriterComponentWorkProof,
service: VerifiedFilesystemServiceProof,
) -> Result<WriterTerminationProof, FilesystemProofError> {
if component != writer_component_work_proof() {
return Err(FilesystemProofError::ComponentMismatch);
}
derive_provider_domain_proof(component.identity(), service)
}
pub fn verify_filesystem_service<A: DeploymentFilesystemServiceAttestation>(
attestation: A,
expected: FilesystemDeploymentIdentity,
) -> Result<VerifiedFilesystemServiceProof, FilesystemProofError> {
if !attestation.approved()
|| !attestation.reproducible_measurement()
|| !attestation.conservative_upper_bound()
{
return Err(FilesystemProofError::Unapproved);
}
let target = attestation.target();
if target != FilesystemTarget::LinuxX86_64 || target != expected.target {
return Err(FilesystemProofError::InvalidDomain);
}
let identities = [
attestation.environment_identity(),
attestation.filesystem_identity(),
attestation.mount_identity(),
attestation.calibration_identity(),
attestation.service_attestation(),
attestation.build_identity(),
];
if identities.contains(&[0; 32])
|| [
expected.environment,
expected.filesystem,
expected.mount,
expected.build,
]
.contains(&[0; 32])
|| attestation.environment_identity() != expected.environment
|| attestation.filesystem_identity() != expected.filesystem
|| attestation.mount_identity() != expected.mount
|| attestation.build_identity() != expected.build
{
return Err(FilesystemProofError::InvalidIdentity);
}
let domain = attestation.work_domain();
if domain.max_write_ops == 0
|| domain.max_write_bytes == 0
|| domain.max_file_sync_ops == 0
|| domain.max_file_sync_bytes == 0
|| domain.max_directory_sync_ops == 0
|| domain.max_hard_link_ops == 0
|| domain.max_unlink_ops == 0
|| domain.max_create_ops == 0
|| domain.max_scan_ops == 0
|| domain.max_scan_entries == 0
|| domain.max_parallel_filesystem_ops != 1
|| !domain.advisory_lock
|| !domain.hard_link_no_replace
|| !domain.directory_fsync
|| !domain.data_fsync
{
return Err(FilesystemProofError::InvalidDomain);
}
let rates = attestation.service_rates();
if rates.write_op_nanos == 0
|| rates.write_byte_nanos == 0
|| rates.file_sync_op_nanos == 0
|| rates.file_sync_byte_nanos == 0
|| rates.directory_sync_op_nanos == 0
|| rates.hard_link_op_nanos == 0
|| rates.unlink_op_nanos == 0
|| rates.create_op_nanos == 0
|| rates.scan_op_nanos == 0
|| rates.scan_entry_nanos == 0
|| (domain.max_rename_ops != 0 && rates.rename_op_nanos == 0)
{
return Err(FilesystemProofError::InvalidService);
}
Ok(VerifiedFilesystemServiceProof {
target,
domain,
rates,
environment_identity: identities[0],
filesystem_identity: identities[1],
mount_identity: identities[2],
calibration_identity: identities[3],
service_attestation: identities[4],
build_identity: identities[5],
})
}
pub(super) fn writer_work_proof<const BLOCKS: usize, const BYTES: usize, const ENTRIES: usize>(
limits: FixedFileLimits,
rotation_retries: usize,
write_interrupt_retries: usize,
) -> Result<WriterWorkProof, FilesystemProofError> {
let records = u64::try_from(BLOCKS).map_err(|_| FilesystemProofError::Overflow)?;
let record_bytes = u64::try_from(BYTES).map_err(|_| FilesystemProofError::Overflow)?;
let entries = u64::try_from(ENTRIES).map_err(|_| FilesystemProofError::Overflow)?;
let retries = u64::try_from(rotation_retries).map_err(|_| FilesystemProofError::Overflow)?;
let write_retries =
u64::try_from(write_interrupt_retries).map_err(|_| FilesystemProofError::Overflow)?;
let queued_bytes = records
.checked_mul(record_bytes)
.ok_or(FilesystemProofError::Overflow)?;
let write_ops = queued_bytes
.checked_add(
records
.checked_mul(write_retries)
.ok_or(FilesystemProofError::Overflow)?,
)
.ok_or(FilesystemProofError::Overflow)?;
let dirty_per_stream = limits
.sync_bytes
.saturating_sub(1)
.min(limits.rotate_bytes.saturating_sub(1));
let preexisting_dirty_bytes = dirty_per_stream
.checked_mul(4)
.ok_or(FilesystemProofError::Overflow)?;
let file_sync_bytes = preexisting_dirty_bytes
.checked_add(queued_bytes)
.ok_or(FilesystemProofError::Overflow)?;
let file_sync_ops = records
.checked_add(4)
.ok_or(FilesystemProofError::Overflow)?;
let directory_sync_ops = records
.checked_mul(4)
.ok_or(FilesystemProofError::Overflow)?;
let hard_link_ops = records
.checked_mul(retries)
.ok_or(FilesystemProofError::Overflow)?;
let unlink_ops = records
.checked_mul(
entries
.checked_add(1)
.ok_or(FilesystemProofError::Overflow)?,
)
.ok_or(FilesystemProofError::Overflow)?;
let scan_entries = records
.checked_mul(entries)
.ok_or(FilesystemProofError::Overflow)?;
Ok(WriterWorkProof {
schema_identity: writer_component_work_proof().identity(),
work: FilesystemWorkDomain {
max_write_ops: write_ops,
max_write_bytes: queued_bytes,
max_file_sync_ops: file_sync_ops,
max_file_sync_bytes: file_sync_bytes,
max_directory_sync_ops: directory_sync_ops,
max_hard_link_ops: hard_link_ops,
max_rename_ops: 0,
max_unlink_ops: unlink_ops,
max_create_ops: records,
max_scan_ops: records,
max_scan_entries: scan_entries,
max_parallel_filesystem_ops: 1,
advisory_lock: true,
hard_link_no_replace: true,
directory_fsync: true,
data_fsync: true,
},
queued_records: records,
queued_bytes,
preexisting_dirty_bytes,
rotations: records,
serial_filesystem: true,
shutdown_requires_zero_encoding_owners: true,
})
}
pub(super) fn derive_termination_proof(
work: WriterWorkProof,
service: VerifiedFilesystemServiceProof,
) -> Result<WriterTerminationProof, FilesystemProofError> {
if service.target != FilesystemTarget::LinuxX86_64 || !covers(service.domain, work.work) {
return Err(FilesystemProofError::DomainMismatch);
}
let facts = work.work;
let max_service_nanos = service_nanos(facts, service.rates)?;
Ok(WriterTerminationProof {
work_identity: work.schema_identity(),
basis: WriterTerminationBasis::Actual(work),
max_service_nanos,
environment_identity: service.environment_identity,
filesystem_identity: service.filesystem_identity,
mount_identity: service.mount_identity,
calibration_identity: service.calibration_identity,
service_attestation: service.service_attestation,
build_identity: service.build_identity,
})
}
fn derive_provider_domain_proof(
work_identity: [u8; 32],
service: VerifiedFilesystemServiceProof,
) -> Result<WriterTerminationProof, FilesystemProofError> {
if service.target != FilesystemTarget::LinuxX86_64 || work_identity == [0; 32] {
return Err(FilesystemProofError::DomainMismatch);
}
let max_service_nanos = service_nanos(service.domain, service.rates)?;
Ok(WriterTerminationProof {
basis: WriterTerminationBasis::ProviderDomain(service.domain),
work_identity,
max_service_nanos,
environment_identity: service.environment_identity,
filesystem_identity: service.filesystem_identity,
mount_identity: service.mount_identity,
calibration_identity: service.calibration_identity,
service_attestation: service.service_attestation,
build_identity: service.build_identity,
})
}
fn service_nanos(
facts: FilesystemWorkDomain,
rates: FilesystemServiceRates,
) -> Result<u64, FilesystemProofError> {
let mut nanos = 0_u128;
add_product(&mut nanos, facts.max_write_ops, rates.write_op_nanos)?;
add_product(&mut nanos, facts.max_write_bytes, rates.write_byte_nanos)?;
add_product(
&mut nanos,
facts.max_file_sync_ops,
rates.file_sync_op_nanos,
)?;
add_product(
&mut nanos,
facts.max_file_sync_bytes,
rates.file_sync_byte_nanos,
)?;
add_product(
&mut nanos,
facts.max_directory_sync_ops,
rates.directory_sync_op_nanos,
)?;
add_product(
&mut nanos,
facts.max_hard_link_ops,
rates.hard_link_op_nanos,
)?;
add_product(&mut nanos, facts.max_rename_ops, rates.rename_op_nanos)?;
add_product(&mut nanos, facts.max_unlink_ops, rates.unlink_op_nanos)?;
add_product(&mut nanos, facts.max_create_ops, rates.create_op_nanos)?;
add_product(&mut nanos, facts.max_scan_ops, rates.scan_op_nanos)?;
add_product(&mut nanos, facts.max_scan_entries, rates.scan_entry_nanos)?;
u64::try_from(nanos).map_err(|_| FilesystemProofError::Overflow)
}
fn add_product(total: &mut u128, count: u64, nanos: u64) -> Result<(), FilesystemProofError> {
let cost = u128::from(count)
.checked_mul(u128::from(nanos))
.ok_or(FilesystemProofError::Overflow)?;
*total = total
.checked_add(cost)
.ok_or(FilesystemProofError::Overflow)?;
Ok(())
}
const fn covers(service: FilesystemWorkDomain, work: FilesystemWorkDomain) -> bool {
service.max_write_ops >= work.max_write_ops
&& service.max_write_bytes >= work.max_write_bytes
&& service.max_file_sync_ops >= work.max_file_sync_ops
&& service.max_file_sync_bytes >= work.max_file_sync_bytes
&& service.max_directory_sync_ops >= work.max_directory_sync_ops
&& service.max_hard_link_ops >= work.max_hard_link_ops
&& service.max_rename_ops >= work.max_rename_ops
&& service.max_unlink_ops >= work.max_unlink_ops
&& service.max_create_ops >= work.max_create_ops
&& service.max_scan_ops >= work.max_scan_ops
&& service.max_scan_entries >= work.max_scan_entries
&& service.max_parallel_filesystem_ops == work.max_parallel_filesystem_ops
&& (!work.advisory_lock || service.advisory_lock)
&& (!work.hard_link_no_replace || service.hard_link_no_replace)
&& (!work.directory_fsync || service.directory_fsync)
&& (!work.data_fsync || service.data_fsync)
}
#[cfg(test)]
mod tests {
use std::time::Duration;
use super::*;
const BUILD: [u8; 32] = [7; 32];
struct TestAttestation {
domain: FilesystemWorkDomain,
rates: FilesystemServiceRates,
approved: bool,
reproducible: bool,
build: [u8; 32],
}
impl DeploymentFilesystemServiceAttestation for TestAttestation {
fn target(&self) -> FilesystemTarget {
FilesystemTarget::LinuxX86_64
}
fn approved(&self) -> bool {
self.approved
}
fn reproducible_measurement(&self) -> bool {
self.reproducible
}
fn conservative_upper_bound(&self) -> bool {
true
}
fn work_domain(&self) -> FilesystemWorkDomain {
self.domain
}
fn service_rates(&self) -> FilesystemServiceRates {
self.rates
}
fn calibration_identity(&self) -> [u8; 32] {
[1; 32]
}
fn environment_identity(&self) -> [u8; 32] {
[2; 32]
}
fn filesystem_identity(&self) -> [u8; 32] {
[3; 32]
}
fn mount_identity(&self) -> [u8; 32] {
[4; 32]
}
fn service_attestation(&self) -> [u8; 32] {
[5; 32]
}
fn build_identity(&self) -> [u8; 32] {
self.build
}
}
fn limits() -> FixedFileLimits {
FixedFileLimits {
rotate_bytes: 1_000,
retained_files: 2,
retention_age: Duration::from_secs(60),
sync_bytes: 100,
sync_interval: Duration::from_secs(1),
fail: None,
}
}
const fn rates(multiplier: u64) -> FilesystemServiceRates {
FilesystemServiceRates {
write_op_nanos: multiplier,
write_byte_nanos: multiplier,
file_sync_op_nanos: multiplier,
file_sync_byte_nanos: multiplier,
directory_sync_op_nanos: multiplier,
hard_link_op_nanos: multiplier,
rename_op_nanos: 0,
unlink_op_nanos: multiplier,
create_op_nanos: multiplier,
scan_op_nanos: multiplier,
scan_entry_nanos: multiplier,
}
}
fn attestation(
domain: FilesystemWorkDomain,
multiplier: u64,
build: [u8; 32],
) -> TestAttestation {
TestAttestation {
domain,
rates: rates(multiplier),
approved: true,
reproducible: true,
build,
}
}
#[test]
fn component_work_proof_is_build_static_sealed_and_matches_derived_work() {
const STATIC: WriterComponentWorkProof = writer_component_work_proof();
assert_ne!(STATIC.identity(), [0; 32]);
assert_eq!(STATIC.version(), 1);
assert_eq!(
STATIC.routed_files(),
crate::file::FileStream::ALL.len() as u8
);
assert_eq!(STATIC.reliability_domains(), 1);
assert_eq!(STATIC.max_parallel_filesystem_ops(), 1);
assert_eq!(STATIC.shutdown_barrier_files(), 4);
assert_eq!(
u64::from(STATIC.write_interrupt_retries()),
crate::file::linux_backend::WRITE_INTERRUPT_RETRIES
);
assert_eq!(
u64::from(STATIC.rotation_publish_attempts()),
crate::file::linux_backend::ROTATION_RETRIES
);
assert_eq!(STATIC.directory_syncs_per_rotation(), 4);
assert!(STATIC.hard_link_no_replace());
assert_eq!(STATIC.rename_ops_per_rotation(), 0);
assert!(STATIC.bounded_retention_scan());
assert!(STATIC.shutdown_requires_zero_encoding_owners());
assert!(STATIC.requires_deployment_filesystem_proof());
let derived = writer_work_proof::<2, 64, 5>(limits(), 8, 8).unwrap();
assert_eq!(derived.schema_identity(), STATIC.identity());
let mut drifted = STATIC.identity();
drifted[31] ^= 1;
assert_ne!(drifted, derived.schema_identity());
}
const fn expected() -> FilesystemDeploymentIdentity {
FilesystemDeploymentIdentity {
target: FilesystemTarget::LinuxX86_64,
environment: [2; 32],
filesystem: [3; 32],
mount: [4; 32],
build: BUILD,
}
}
#[test]
fn work_proof_seals_every_serial_backend_upper_bound() {
let proof = writer_work_proof::<2, 64, 5>(limits(), 8, 8).unwrap();
let work = proof.filesystem_work();
assert_eq!(proof.queued_records(), 2);
assert_eq!(proof.queued_bytes(), 128);
assert_eq!(proof.preexisting_dirty_bytes(), 396);
assert_eq!(proof.rotations(), 2);
assert!(proof.serial_filesystem());
assert!(proof.shutdown_requires_zero_encoding_owners());
assert_eq!(work.max_write_ops, 144);
assert_eq!(work.max_write_bytes, 128);
assert_eq!(work.max_file_sync_ops, 6);
assert_eq!(work.max_file_sync_bytes, 524);
assert_eq!(work.max_directory_sync_ops, 8);
assert_eq!(work.max_hard_link_ops, 16);
assert_eq!(work.max_rename_ops, 0);
assert_eq!(work.max_unlink_ops, 12);
assert_eq!(work.max_create_ops, 2);
assert_eq!(work.max_scan_ops, 2);
assert_eq!(work.max_scan_entries, 10);
assert_eq!(work.max_parallel_filesystem_ops, 1);
}
#[test]
fn slow_reproducible_service_derives_a_larger_budget_without_runtime_adaptation() {
let work = writer_work_proof::<2, 64, 5>(limits(), 8, 8).unwrap();
let domain = work.filesystem_work();
let normal = verify_filesystem_service(attestation(domain, 1, BUILD), expected()).unwrap();
let slow = verify_filesystem_service(attestation(domain, 9, BUILD), expected()).unwrap();
let normal = derive_termination_proof(work, normal).unwrap();
let slow =
derive_termination_proof(writer_work_proof::<2, 64, 5>(limits(), 8, 8).unwrap(), slow)
.unwrap();
assert_eq!(normal.max_service_nanos(), 852);
assert_eq!(slow.max_service_nanos(), 7_668);
assert_eq!(
normal
.actual_work()
.unwrap()
.filesystem_work()
.max_rename_ops,
0
);
assert!(normal.provider_domain_upper_bound().is_none());
}
#[test]
fn provider_owner_consumes_static_component_and_verified_service_without_writer() {
let domain = writer_work_proof::<2, 64, 5>(limits(), 8, 8)
.unwrap()
.filesystem_work();
let service = verify_filesystem_service(attestation(domain, 1, BUILD), expected()).unwrap();
let proof =
verify_provider_writer_termination(writer_component_work_proof(), service).unwrap();
assert!(proof.actual_work().is_none());
assert_eq!(proof.provider_domain_upper_bound(), Some(domain));
assert_eq!(proof.max_service_nanos(), 852);
assert_eq!(proof.environment_identity(), expected().environment);
assert_eq!(proof.filesystem_identity(), expected().filesystem);
assert_eq!(proof.mount_identity(), expected().mount);
assert_eq!(proof.calibration_identity(), [1; 32]);
assert_eq!(proof.service_attestation(), [5; 32]);
assert_eq!(proof.build_identity(), BUILD);
assert_eq!(
saddle_admission::VerifiedFilesystemTerminationServiceProofOwner::work_identity(&proof),
writer_component_work_proof().identity()
);
}
#[test]
fn provider_owner_rejects_foreign_component_drift_and_overflow() {
let domain = writer_work_proof::<2, 64, 5>(limits(), 8, 8)
.unwrap()
.filesystem_work();
let service = verify_filesystem_service(attestation(domain, 1, BUILD), expected()).unwrap();
let mut foreign = writer_component_work_proof();
foreign.identity[0] ^= 1;
assert_eq!(
verify_provider_writer_termination(foreign, service).unwrap_err(),
FilesystemProofError::ComponentMismatch
);
let drifted = attestation(domain, 1, [8; 32]);
assert_eq!(
verify_filesystem_service(drifted, expected()).unwrap_err(),
FilesystemProofError::InvalidIdentity
);
let huge =
verify_filesystem_service(attestation(domain, u64::MAX, BUILD), expected()).unwrap();
assert_eq!(
verify_provider_writer_termination(writer_component_work_proof(), huge).unwrap_err(),
FilesystemProofError::Overflow
);
}
#[test]
fn startup_rejects_unmeasured_domain_shortfall_and_build_identity_drift() {
let work = writer_work_proof::<2, 64, 5>(limits(), 8, 8).unwrap();
let mut unmeasured = attestation(work.filesystem_work(), 1, BUILD);
unmeasured.reproducible = false;
assert_eq!(
verify_filesystem_service(unmeasured, expected()).unwrap_err(),
FilesystemProofError::Unapproved
);
let drifted = attestation(work.filesystem_work(), 1, [8; 32]);
assert_eq!(
verify_filesystem_service(drifted, expected()).unwrap_err(),
FilesystemProofError::InvalidIdentity
);
let mut mount_drift = expected();
mount_drift.mount = [9; 32];
assert_eq!(
verify_filesystem_service(attestation(work.filesystem_work(), 1, BUILD), mount_drift)
.unwrap_err(),
FilesystemProofError::InvalidIdentity
);
let mut short = work.filesystem_work();
short.max_file_sync_ops -= 1;
let service = verify_filesystem_service(attestation(short, 1, BUILD), expected()).unwrap();
assert_eq!(
derive_termination_proof(work, service).unwrap_err(),
FilesystemProofError::DomainMismatch
);
}
}