Skip to main content

mina_node_common/service/
builder.rs

1use ledger::proofs::provers::BlockProver;
2use mina_node::{
3    account::AccountSecretKey,
4    core::channels::mpsc,
5    ledger::{LedgerCtx, LedgerManager},
6    p2p::{
7        identity::SecretKey as P2pSecretKey,
8        service_impl::{
9            webrtc_with_libp2p::{P2pServiceCtx, P2pServiceWebrtcWithLibp2p},
10            TaskSpawner,
11        },
12    },
13    stats::Stats,
14};
15use rand::{rngs::StdRng, SeedableRng};
16use sha3::{
17    digest::{ExtendableOutput, Update},
18    Shake256,
19};
20
21use crate::{
22    rpc::{RpcSender, RpcService},
23    EventReceiver, EventSender, NodeService,
24};
25
26use super::{
27    archive::{config::ArchiveStorageOptions, ArchiveService},
28    block_producer::BlockProducerService,
29};
30
31pub struct NodeServiceCommonBuilder {
32    rng_seed: [u8; 32],
33    rng: StdRng,
34    /// Events sent on this channel are retrieved and processed in the
35    /// `event_source` state machine defined in the `mina-node` crate.
36    event_sender: EventSender,
37    event_receiver: EventReceiver,
38    ledger_manager: Option<LedgerManager>,
39    block_producer: Option<BlockProducerService>,
40    archive: Option<ArchiveService>,
41    p2p: Option<P2pServiceCtx>,
42    gather_stats: bool,
43    rpc: RpcService,
44    skip_proof_verification: bool,
45}
46
47#[derive(thiserror::Error, Debug, Clone)]
48pub enum NodeServiceCommonBuildError {
49    #[error("ledger was never initialized! Please call: NodeServiceBuilder::ledger_init")]
50    LedgerNotInit,
51    #[error("p2p was never initialized! Please call: NodeServiceBuilder::p2p_init")]
52    P2pNotInit,
53}
54
55impl NodeServiceCommonBuilder {
56    pub fn new(rng_seed: [u8; 32]) -> Self {
57        let (event_sender, event_receiver) = mpsc::unbounded_channel();
58        Self {
59            rng_seed,
60            rng: StdRng::from_seed(rng_seed),
61            event_sender,
62            event_receiver: event_receiver.into(),
63            ledger_manager: None,
64            block_producer: None,
65            archive: None,
66            p2p: None,
67            rpc: RpcService::new(),
68            gather_stats: false,
69            skip_proof_verification: false,
70        }
71    }
72
73    pub fn event_sender(&self) -> &EventSender {
74        &self.event_sender
75    }
76
77    pub fn rpc_sender(&self) -> RpcSender {
78        self.rpc.req_sender()
79    }
80
81    pub fn ledger_init(&mut self) -> &mut Self {
82        let mut ctx = LedgerCtx::default();
83        ctx.set_event_sender(self.event_sender.clone());
84        if self.archive.is_some() {
85            ctx.set_archive_mode();
86        };
87        self.ledger_manager = Some(LedgerManager::spawn(ctx));
88        self
89    }
90
91    pub fn block_producer_init(
92        &mut self,
93        keypair: AccountSecretKey,
94        provers: Option<BlockProver>,
95    ) -> &mut Self {
96        self.block_producer = Some(BlockProducerService::start(
97            self.event_sender.clone(),
98            keypair,
99            provers,
100        ));
101        self
102    }
103
104    pub fn archive_init(&mut self, options: ArchiveStorageOptions, work_dir: String) -> &mut Self {
105        self.archive = Some(ArchiveService::start(options, work_dir));
106        self
107    }
108
109    pub fn p2p_init<S: TaskSpawner>(
110        &mut self,
111        secret_key: P2pSecretKey,
112        task_spawner: S,
113    ) -> &mut Self {
114        self.p2p = Some(<NodeService as P2pServiceWebrtcWithLibp2p>::init(
115            secret_key.clone(),
116            task_spawner,
117            self.rng_seed,
118        ));
119        self
120    }
121
122    pub fn gather_stats(&mut self) -> &mut Self {
123        self.gather_stats = true;
124        self
125    }
126
127    pub fn skip_proof_verification(&mut self, skip: bool) -> &mut Self {
128        self.skip_proof_verification = skip;
129        self
130    }
131
132    pub fn build(self) -> Result<NodeService, NodeServiceCommonBuildError> {
133        let ledger_manager = self
134            .ledger_manager
135            .ok_or(NodeServiceCommonBuildError::LedgerNotInit)?;
136        let p2p = self.p2p.ok_or(NodeServiceCommonBuildError::P2pNotInit)?;
137
138        Ok(NodeService {
139            rng_seed: self.rng_seed,
140            rng_ephemeral: Shake256::default()
141                .chain(self.rng_seed)
142                .chain(b"ephemeral")
143                .finalize_xof(),
144            rng_static: Shake256::default()
145                .chain(self.rng_seed)
146                .chain(b"static")
147                .finalize_xof(),
148            rng: self.rng,
149            event_sender: self.event_sender.clone(),
150            event_receiver: self.event_receiver,
151            snark_block_proof_verify: NodeService::snark_block_proof_verifier_spawn(
152                self.event_sender,
153                self.skip_proof_verification,
154            ),
155            ledger_manager,
156            block_producer: self.block_producer,
157            // initialized in state machine.
158            snark_worker: None,
159            archive: self.archive,
160            p2p,
161            stats: self.gather_stats.then(Stats::new),
162            rpc: self.rpc,
163            recorder: Default::default(),
164            replayer: None,
165            invariants_state: Default::default(),
166        })
167    }
168}