ab_client_proof_of_time/source/
timekeeper.rs

1use crate::source::state::PotState;
2use crate::verifier::PotVerifier;
3use ab_core_primitives::pot::{PotCheckpoints, PotSeed, SlotNumber};
4use ab_proof_of_time::PotError;
5use futures::SinkExt;
6use futures::channel::mpsc;
7use futures::executor::block_on;
8use std::num::NonZeroU32;
9use std::sync::Arc;
10use tracing::{debug, trace};
11
12/// Poof generated by timekeeper
13#[derive(Debug, Copy, Clone)]
14pub struct TimekeeperProof {
15    /// Slot number
16    pub slot: SlotNumber,
17    /// Proof of time seed
18    pub seed: PotSeed,
19    /// Iterations per slot
20    pub slot_iterations: NonZeroU32,
21    /// Proof of time checkpoints
22    pub checkpoints: PotCheckpoints,
23}
24
25/// Timekeeper source
26#[derive(Debug)]
27#[must_use = "Doesn't do anything unless run() method is called"]
28pub struct Timekeeper {
29    state: Arc<PotState>,
30    pot_verifier: PotVerifier,
31    proof_sender: mpsc::Sender<TimekeeperProof>,
32}
33
34impl Timekeeper {
35    /// Create a new timekeeper source
36    pub fn new(
37        state: Arc<PotState>,
38        pot_verifier: PotVerifier,
39    ) -> (Self, mpsc::Receiver<TimekeeperProof>) {
40        let (proof_sender, proof_receiver) = mpsc::channel(1);
41
42        (
43            Self {
44                state,
45                pot_verifier,
46                proof_sender,
47            },
48            proof_receiver,
49        )
50    }
51
52    /// Run timekeeper until receiver returned from constructor is dropped.
53    ///
54    /// Must be running on a dedicated high-frequency CPU core.
55    pub fn run(self) -> Result<(), PotError> {
56        let Self {
57            state,
58            pot_verifier,
59            mut proof_sender,
60        } = self;
61
62        let mut next_slot_input = state.next_slot_input();
63
64        loop {
65            trace!(
66                "Proving for slot {} with {} iterations",
67                next_slot_input.slot, next_slot_input.slot_iterations
68            );
69            let checkpoints =
70                ab_proof_of_time::prove(next_slot_input.seed, next_slot_input.slot_iterations)?;
71
72            let proof = TimekeeperProof {
73                seed: next_slot_input.seed,
74                slot_iterations: next_slot_input.slot_iterations,
75                slot: next_slot_input.slot,
76                checkpoints,
77            };
78
79            pot_verifier.inject_verified_checkpoints(
80                next_slot_input.seed,
81                next_slot_input.slot_iterations,
82                checkpoints,
83            );
84
85            next_slot_input = state
86                .try_extend(
87                    next_slot_input,
88                    next_slot_input.slot,
89                    checkpoints.output(),
90                    None,
91                )
92                .unwrap_or_else(|next_slot_input| next_slot_input);
93
94            if let Err(error) = proof_sender.try_send(proof)
95                && let Err(error) = block_on(proof_sender.send(error.into_inner()))
96            {
97                debug!(%error, "Couldn't send proof, the channel is closed");
98                return Ok(());
99            }
100        }
101    }
102}