sc_proof_of_time/source/
timekeeper.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
use crate::source::state::PotState;
use crate::verifier::PotVerifier;
use futures::channel::mpsc;
use futures::executor::block_on;
use futures::SinkExt;
use sp_consensus_slots::Slot;
use std::num::NonZeroU32;
use std::sync::Arc;
use subspace_core_primitives::pot::{PotCheckpoints, PotSeed};
use subspace_proof_of_time::PotError;
use tracing::{debug, trace};

/// Proof of time slot information
pub(super) struct TimekeeperProof {
    /// Slot number
    pub(super) slot: Slot,
    /// Proof of time seed
    pub(super) seed: PotSeed,
    /// Iterations per slot
    pub(super) slot_iterations: NonZeroU32,
    /// Proof of time checkpoints
    pub(super) checkpoints: PotCheckpoints,
}

/// Runs timekeeper, must be running on a fast dedicated CPU core
pub(super) fn run_timekeeper(
    state: Arc<PotState>,
    pot_verifier: PotVerifier,
    mut proofs_sender: mpsc::Sender<TimekeeperProof>,
) -> Result<(), PotError> {
    let mut next_slot_input = state.next_slot_input();

    loop {
        trace!(
            "Proving for slot {} with {} iterations",
            next_slot_input.slot,
            next_slot_input.slot_iterations
        );
        let checkpoints =
            subspace_proof_of_time::prove(next_slot_input.seed, next_slot_input.slot_iterations)?;

        let proof = TimekeeperProof {
            seed: next_slot_input.seed,
            slot_iterations: next_slot_input.slot_iterations,
            slot: next_slot_input.slot,
            checkpoints,
        };

        pot_verifier.inject_verified_checkpoints(
            next_slot_input.seed,
            next_slot_input.slot_iterations,
            checkpoints,
        );

        next_slot_input = state
            .try_extend(
                next_slot_input,
                next_slot_input.slot,
                checkpoints.output(),
                None,
            )
            .unwrap_or_else(|next_slot_input| next_slot_input);

        if let Err(error) = proofs_sender.try_send(proof) {
            if let Err(error) = block_on(proofs_sender.send(error.into_inner())) {
                debug!(%error, "Couldn't send checkpoints, channel is closed");
                return Ok(());
            }
        }
    }
}