Skip to main content

bsv_overlay_engine/
proof_window.rs

1//! Serving policy for admitted transactions waiting for their own proof.
2
3/// Shared with the Worker watch and SQL lookup predicates.
4pub const PROOFLESS_FLAG_MS: i64 = 24 * 60 * 60 * 1000;
5/// Bounded rows considered for peer proof recovery during one tick.
6pub const PEER_PROOF_ROW_LIMIT: usize = 20;
7/// A silent peer must leave time for other peers in the pass.
8pub const PEER_PROOF_REQUEST_MS: u64 = 5_000;
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11pub enum Verdict {
12    Served,
13    Held,
14}
15
16pub fn verdict(has_proof: bool, observed_ms: Option<i64>, now_ms: i64) -> Verdict {
17    if has_proof || observed_ms.is_some_and(|seen| seen >= now_ms.saturating_sub(PROOFLESS_FLAG_MS))
18    {
19        Verdict::Served
20    } else {
21        Verdict::Held
22    }
23}
24
25#[derive(Debug, Clone)]
26pub struct HeldOutput {
27    pub txid: String,
28    pub output_index: u32,
29    pub topic: String,
30}
31
32/// Kept outside the pass future so a deadline preserves completed work.
33#[derive(Debug, Default, Clone, Copy)]
34pub struct PeerProofSummary {
35    pub requests: u64,
36    pub landed: u64,
37    pub refused: u64,
38    pub faults: u64,
39}
40
41#[cfg(test)]
42mod tests {
43    use super::*;
44
45    #[test]
46    fn proof_window_boundary_unknown_age_and_proof() {
47        let now = 3 * PROOFLESS_FLAG_MS;
48        assert_eq!(
49            verdict(false, Some(now - PROOFLESS_FLAG_MS), now),
50            Verdict::Served
51        );
52        assert_eq!(
53            verdict(false, Some(now - PROOFLESS_FLAG_MS - 1), now),
54            Verdict::Held
55        );
56        assert_eq!(verdict(false, None, now), Verdict::Held);
57        assert_eq!(verdict(true, None, now), Verdict::Served);
58        assert_eq!(verdict(false, Some(now + 1), now), Verdict::Served);
59    }
60}