Skip to main content

commonware_glue/dkg/probe/actor/
mod.rs

1use super::mailbox::{Mailbox, Message};
2use crate::{
3    dkg::{ReshareBlock, network::Manager, probe::Bootstrap, types::EpochInfo},
4    stateful::probe::sample::Sample,
5};
6use commonware_actor::mailbox::{self as actor_mailbox, Receiver as ActorReceiver};
7use commonware_codec::Read;
8use commonware_consensus::{marshal::core::Variant, simplex::scheme::Scheme, types::FixedEpocher};
9use commonware_cryptography::Signer;
10use commonware_p2p::{Blocker, Receiver, Sender};
11use commonware_parallel::Strategy;
12use commonware_runtime::{Clock, ContextCell, Handle, Metrics, Spawner, spawn_cell};
13use commonware_utils::NonZeroDuration;
14use discovery::Discovery;
15use rand_core::CryptoRng;
16use std::num::{NonZeroU64, NonZeroUsize};
17
18mod discovery;
19mod service;
20
21/// Configuration for the DKG probe actor.
22pub struct Config<E, M, S, V, T, B>
23where
24    E: Spawner + CryptoRng + Clock + Metrics,
25    M: Manager<
26            PublicKey = S::PublicKey,
27            Directory = <V::ApplicationBlock as ReshareBlock>::Directory,
28        >,
29    S: Scheme<V::Commitment>,
30    V: Variant,
31    V::ApplicationBlock: ReshareBlock,
32    <V::ApplicationBlock as ReshareBlock>::Signer: Signer<PublicKey = S::PublicKey>,
33    T: Strategy,
34    B: Blocker<PublicKey = S::PublicKey>,
35{
36    /// Runtime context.
37    pub context: E,
38    /// P2P manager used to track the bootstrap participants when discovery
39    /// begins.
40    pub manager: M,
41    /// The weakly subjective checkpoint to bootstrap from.
42    pub bootstrap: Bootstrap<S::PublicKey, <V::ApplicationBlock as ReshareBlock>::Directory>,
43    /// All-epoch certificate verifier built from the constant BLS identity.
44    pub verifier: S,
45    /// Public epoch information carried by genesis.
46    pub genesis: EpochInfo<
47        <V::ApplicationBlock as ReshareBlock>::Variant,
48        S::PublicKey,
49        <V::ApplicationBlock as ReshareBlock>::Directory,
50    >,
51    /// Strategy for certificate verification.
52    pub strategy: T,
53    /// Blocker used to block peers that send invalid bootstrap data.
54    pub blocker: B,
55    /// Number of blocks in each epoch.
56    pub blocks_per_epoch: NonZeroU64,
57    /// How long to wait before trying another boundary responder or re-broadcasting discovery.
58    pub retry_timeout: NonZeroDuration,
59    /// Mailbox capacity.
60    pub mailbox_size: NonZeroUsize,
61    /// Codec configuration for application blocks received in boundary responses.
62    pub block_codec_config: <V::ApplicationBlock as Read>::Cfg,
63}
64
65/// DKG probe actor.
66pub struct Actor<E, M, S, V, T, B>
67where
68    E: Spawner + CryptoRng + Clock + Metrics,
69    M: Manager<
70            PublicKey = S::PublicKey,
71            Directory = <V::ApplicationBlock as ReshareBlock>::Directory,
72        >,
73    S: Scheme<V::Commitment>,
74    V: Variant,
75    V::ApplicationBlock: ReshareBlock,
76    <V::ApplicationBlock as ReshareBlock>::Signer: Signer<PublicKey = S::PublicKey>,
77    T: Strategy,
78    B: Blocker<PublicKey = S::PublicKey>,
79{
80    context: ContextCell<E>,
81    mailbox: ActorReceiver<Message<S, V>>,
82    manager: M,
83    bootstrap: Bootstrap<S::PublicKey, <V::ApplicationBlock as ReshareBlock>::Directory>,
84    verifier: S,
85    genesis: EpochInfo<
86        <V::ApplicationBlock as ReshareBlock>::Variant,
87        S::PublicKey,
88        <V::ApplicationBlock as ReshareBlock>::Directory,
89    >,
90    strategy: T,
91    blocker: B,
92    blocks_per_epoch: NonZeroU64,
93    retry_timeout: NonZeroDuration,
94    block_codec_config: <V::ApplicationBlock as Read>::Cfg,
95}
96
97impl<E, M, S, V, T, B> Actor<E, M, S, V, T, B>
98where
99    E: Spawner + CryptoRng + Clock + Metrics,
100    M: Manager<
101            PublicKey = S::PublicKey,
102            Directory = <V::ApplicationBlock as ReshareBlock>::Directory,
103        >,
104    S: Scheme<V::Commitment>,
105    V: Variant,
106    V::ApplicationBlock: ReshareBlock,
107    <V::ApplicationBlock as ReshareBlock>::Signer: Signer<PublicKey = S::PublicKey>,
108    T: Strategy,
109    B: Blocker<PublicKey = S::PublicKey>,
110{
111    /// Create a probe actor and mailbox.
112    pub fn new(config: Config<E, M, S, V, T, B>) -> (Self, Mailbox<S, V>) {
113        let (sender, mailbox) =
114            actor_mailbox::new(config.context.child("mailbox"), config.mailbox_size);
115        let mailbox_handle = Mailbox::new(sender);
116        (
117            Self {
118                context: ContextCell::new(config.context),
119                mailbox,
120                manager: config.manager,
121                bootstrap: config.bootstrap,
122                verifier: config.verifier,
123                genesis: config.genesis,
124                strategy: config.strategy,
125                blocker: config.blocker,
126                blocks_per_epoch: config.blocks_per_epoch,
127                retry_timeout: config.retry_timeout,
128                block_codec_config: config.block_codec_config,
129            },
130            mailbox_handle,
131        )
132    }
133
134    /// Start the probe actor.
135    ///
136    /// The boundary network is the probe request channel used to sample the
137    /// configured committee's latest finalizations, fetch the target epoch's
138    /// boundary finalization and block, and later serve the same requests to
139    /// other joining peers.
140    pub fn start<BSE, BRE>(mut self, boundaries: (BSE, BRE)) -> Handle<()>
141    where
142        BSE: Sender<PublicKey = S::PublicKey>,
143        BRE: Receiver<PublicKey = S::PublicKey>,
144    {
145        spawn_cell!(self.context, self.run(boundaries,))
146    }
147
148    async fn run<BSE, BRE>(self, (boundary_sender, boundary_receiver): (BSE, BRE))
149    where
150        BSE: Sender<PublicKey = S::PublicKey>,
151        BRE: Receiver<PublicKey = S::PublicKey>,
152    {
153        Discovery {
154            context: self.context,
155            mailbox: self.mailbox,
156            manager: self.manager,
157            sample: Sample::new(self.bootstrap.epoch),
158            bootstrap_participants: self.bootstrap.participants,
159            bootstrap_directory: self.bootstrap.directory,
160            verifier: self.verifier,
161            genesis: self.genesis,
162            strategy: self.strategy,
163            blocker: self.blocker,
164            epocher: FixedEpocher::new(self.blocks_per_epoch),
165            block_codec_config: self.block_codec_config,
166            retry_timeout: self.retry_timeout,
167            artifact: None,
168            subscribers: Vec::new(),
169            pending: None,
170        }
171        .run(boundary_sender, boundary_receiver)
172        .await;
173    }
174}