use crate::c1_normal_return::{DbNormalReturnWorkProof, db_normal_return_work_proof};
const OWNER_DOMAIN: &[u8] = b"saddle.db.termination-work-owner.v1";
#[doc(hidden)]
pub struct VerifiedDbTerminationWorkOwner {
work: DbNormalReturnWorkProof,
seal: [u8; 32],
}
#[doc(hidden)]
pub fn issue_verified_db_termination_work_owner() -> VerifiedDbTerminationWorkOwner {
let work = db_normal_return_work_proof();
VerifiedDbTerminationWorkOwner {
seal: seal(work),
work,
}
}
#[doc(hidden)]
pub fn validate_verified_db_termination_work_owner(
owner: VerifiedDbTerminationWorkOwner,
) -> Result<VerifiedDbTerminationWorkOwner, VerifiedDbTerminationWorkOwner> {
if owner.seal == seal(owner.work) {
Ok(owner)
} else {
Err(owner)
}
}
fn seal(work: DbNormalReturnWorkProof) -> [u8; 32] {
let mut output = work.identity();
for (index, byte) in OWNER_DOMAIN.iter().enumerate() {
let slot = index % output.len();
output[slot] = output[slot]
.wrapping_add(*byte)
.rotate_left((index % 7) as u32);
}
output
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn database_issues_and_consumes_the_only_concrete_work_shape() {
let owner = issue_verified_db_termination_work_owner();
let _owner = validate_verified_db_termination_work_owner(owner)
.unwrap_or_else(|_| panic!("Database-issued termination work owner must validate"));
}
#[test]
fn validation_failure_restores_the_same_owner() {
let mut owner = issue_verified_db_termination_work_owner();
let original_work = owner.work.identity();
owner.seal[0] ^= 1;
let restored = validate_verified_db_termination_work_owner(owner)
.err()
.expect("foreign seal must be recoverable");
assert_eq!(restored.work.identity(), original_work);
assert_ne!(restored.seal, seal(restored.work));
}
}