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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
// Copyright (c) 2022 MASSA LABS <info@massa.net>

//! This module exports generic traits representing interfaces for interacting
//! with the PoS selector worker.

use std::collections::BTreeMap;

use crate::PosResult;
use massa_hash::Hash;
use massa_models::{address::Address, prehash::PreHashSet, slot::Slot};

#[cfg(feature = "test-exports")]
use std::collections::{HashMap, VecDeque};

/// Selections of endorsements and producer
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Selection {
    /// Chosen endorsements
    pub endorsements: Vec<Address>,
    /// Chosen block producer
    pub producer: Address,
}

#[cfg(feature = "test-exports")]
use std::sync::Arc;

#[cfg_attr(feature = "test-exports", mockall_wrap::wrap, mockall::automock)]
/// interface that communicates with the selector worker thread
pub trait SelectorController: Send + Sync {
    /// Waits for draws to reach at least a given cycle number.
    /// Returns the latest cycle number reached (can be higher than `cycle`).
    /// Errors can occur if the thread stopped.
    fn wait_for_draws(&self, cycle: u64) -> PosResult<u64>;

    /// Feed cycle to the selector
    ///
    /// # Arguments
    /// * `cycle`: cycle number to be drawn
    /// * `lookback_rolls`: look back rolls used for the draw (cycle - 3)
    /// * `lookback_seed`: look back seed hash for the draw (cycle - 2)
    fn feed_cycle(
        &self,
        cycle: u64,
        lookback_rolls: BTreeMap<Address, u64>,
        lookback_seed: Hash,
    ) -> PosResult<()>;

    /// Get [Selection] computed for a slot
    fn get_selection(&self, slot: Slot) -> PosResult<Selection>;

    /// Get [Address] of the selected block producer for a given slot
    fn get_producer(&self, slot: Slot) -> PosResult<Address>;

    /// Get selections computed for a slot range (only returns available selections):
    /// # Arguments
    /// * `slot_range`: range of slots to get the selection for
    /// * `restrict_to_addresses`: optionally restrict only to slots involving a given address
    #[allow(clippy::needless_lifetimes)] // lifetime elision conflicts with Mockall
    fn get_available_selections_in_range<'a>(
        &self,
        slot_range: std::ops::RangeInclusive<Slot>,
        restrict_to_addresses: Option<&'a PreHashSet<Address>>,
    ) -> PosResult<BTreeMap<Slot, Selection>>;

    /// Returns a boxed clone of self.
    /// Useful to allow cloning `Box<dyn SelectorController>`.
    fn clone_box(&self) -> Box<dyn SelectorController>;

    /// Get every [Selection]
    ///
    /// Only used in tests for post-bootstrap selection matching.
    #[cfg(feature = "test-exports")]
    fn get_entire_selection(&self) -> VecDeque<(u64, HashMap<Slot, Selection>)> {
        unimplemented!("mock implementation only")
    }
}

/// Allow cloning `Box<dyn SelectorController>`
/// Uses `ExecutionController::clone_box` internally
impl Clone for Box<dyn SelectorController> {
    fn clone(&self) -> Box<dyn SelectorController> {
        self.clone_box()
    }
}

/// Selector manager used to stop the selector thread
pub trait SelectorManager {
    /// Stop the selector thread
    /// Note that we do not take self by value to consume it
    /// because it is not allowed to move out of `Box<dyn SelectorManager>`
    /// This will improve if the `unsized_fn_params` feature stabilizes enough to be safely usable.
    fn stop(&mut self);
}