snarkos_node/
node.rs

1// Copyright (c) 2019-2025 Provable Inc.
2// This file is part of the snarkOS library.
3
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at:
7
8// http://www.apache.org/licenses/LICENSE-2.0
9
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16use crate::{BootstrapClient, Client, Prover, Validator, traits::NodeInterface};
17use snarkos_account::Account;
18use snarkos_node_router::{Outbound, Peer, PeerPoolHandling, messages::NodeType};
19use snarkvm::prelude::{
20    Address,
21    Header,
22    Ledger,
23    Network,
24    PrivateKey,
25    ViewKey,
26    block::Block,
27    store::helpers::{memory::ConsensusMemory, rocksdb::ConsensusDB},
28};
29
30use aleo_std::StorageMode;
31use anyhow::Result;
32#[cfg(feature = "locktick")]
33use locktick::parking_lot::RwLock;
34#[cfg(not(feature = "locktick"))]
35use parking_lot::RwLock;
36use std::{
37    collections::HashMap,
38    net::SocketAddr,
39    sync::{Arc, atomic::AtomicBool},
40};
41
42#[derive(Clone)]
43pub enum Node<N: Network> {
44    /// A validator is a full node, capable of validating blocks.
45    Validator(Arc<Validator<N, ConsensusDB<N>>>),
46    /// A prover is a light node, capable of producing proofs for consensus.
47    Prover(Arc<Prover<N, ConsensusMemory<N>>>),
48    /// A client node is a full node, capable of querying with the network.
49    Client(Arc<Client<N, ConsensusDB<N>>>),
50    /// A bootstrap client node is a light node dedicated to serving lists of peers.
51    BootstrapClient(BootstrapClient<N>),
52}
53
54impl<N: Network> Node<N> {
55    /// Initializes a new validator node.
56    pub async fn new_validator(
57        node_ip: SocketAddr,
58        bft_ip: Option<SocketAddr>,
59        rest_ip: Option<SocketAddr>,
60        rest_rps: u32,
61        account: Account<N>,
62        trusted_peers: &[SocketAddr],
63        trusted_validators: &[SocketAddr],
64        genesis: Block<N>,
65        cdn: Option<http::Uri>,
66        storage_mode: StorageMode,
67        allow_external_peers: bool,
68        dev_txs: bool,
69        dev: Option<u16>,
70        shutdown: Arc<AtomicBool>,
71    ) -> Result<Self> {
72        Ok(Self::Validator(Arc::new(
73            Validator::new(
74                node_ip,
75                bft_ip,
76                rest_ip,
77                rest_rps,
78                account,
79                trusted_peers,
80                trusted_validators,
81                genesis,
82                cdn,
83                storage_mode,
84                allow_external_peers,
85                dev_txs,
86                dev,
87                shutdown,
88            )
89            .await?,
90        )))
91    }
92
93    /// Initializes a new prover node.
94    pub async fn new_prover(
95        node_ip: SocketAddr,
96        account: Account<N>,
97        trusted_peers: &[SocketAddr],
98        genesis: Block<N>,
99        storage_mode: StorageMode,
100        dev: Option<u16>,
101        shutdown: Arc<AtomicBool>,
102    ) -> Result<Self> {
103        Ok(Self::Prover(Arc::new(
104            Prover::new(node_ip, account, trusted_peers, genesis, storage_mode, dev, shutdown).await?,
105        )))
106    }
107
108    /// Initializes a new client node.
109    pub async fn new_client(
110        node_ip: SocketAddr,
111        rest_ip: Option<SocketAddr>,
112        rest_rps: u32,
113        account: Account<N>,
114        trusted_peers: &[SocketAddr],
115        genesis: Block<N>,
116        cdn: Option<http::Uri>,
117        storage_mode: StorageMode,
118        rotate_external_peers: bool,
119        dev: Option<u16>,
120        shutdown: Arc<AtomicBool>,
121    ) -> Result<Self> {
122        Ok(Self::Client(Arc::new(
123            Client::new(
124                node_ip,
125                rest_ip,
126                rest_rps,
127                account,
128                trusted_peers,
129                genesis,
130                cdn,
131                storage_mode,
132                rotate_external_peers,
133                dev,
134                shutdown,
135            )
136            .await?,
137        )))
138    }
139
140    /// Initializes a new bootstrap client node.
141    pub async fn new_bootstrap_client(
142        listener_addr: SocketAddr,
143        account: Account<N>,
144        genesis_header: Header<N>,
145        dev: Option<u16>,
146    ) -> Result<Self> {
147        Ok(Self::BootstrapClient(BootstrapClient::new(listener_addr, account, genesis_header, dev).await?))
148    }
149
150    /// Returns the node type.
151    pub fn node_type(&self) -> NodeType {
152        match self {
153            Self::Validator(validator) => validator.node_type(),
154            Self::Prover(prover) => prover.node_type(),
155            Self::Client(client) => client.node_type(),
156            Self::BootstrapClient(_) => NodeType::BootstrapClient,
157        }
158    }
159
160    /// Returns the account private key of the node.
161    pub fn private_key(&self) -> &PrivateKey<N> {
162        match self {
163            Self::Validator(node) => node.private_key(),
164            Self::Prover(node) => node.private_key(),
165            Self::Client(node) => node.private_key(),
166            Self::BootstrapClient(node) => node.private_key(),
167        }
168    }
169
170    /// Returns the account view key of the node.
171    pub fn view_key(&self) -> &ViewKey<N> {
172        match self {
173            Self::Validator(node) => node.view_key(),
174            Self::Prover(node) => node.view_key(),
175            Self::Client(node) => node.view_key(),
176            Self::BootstrapClient(node) => node.view_key(),
177        }
178    }
179
180    /// Returns the account address of the node.
181    pub fn address(&self) -> Address<N> {
182        match self {
183            Self::Validator(node) => node.address(),
184            Self::Prover(node) => node.address(),
185            Self::Client(node) => node.address(),
186            Self::BootstrapClient(node) => node.address(),
187        }
188    }
189
190    /// Returns `true` if the node is in development mode.
191    pub fn is_dev(&self) -> bool {
192        match self {
193            Self::Validator(node) => node.is_dev(),
194            Self::Prover(node) => node.is_dev(),
195            Self::Client(node) => node.is_dev(),
196            Self::BootstrapClient(node) => node.is_dev(),
197        }
198    }
199
200    /// Returns a reference to the underlying peer pool.
201    pub fn peer_pool(&self) -> &RwLock<HashMap<SocketAddr, Peer<N>>> {
202        match self {
203            Self::Validator(validator) => validator.router().peer_pool(),
204            Self::Prover(prover) => prover.router().peer_pool(),
205            Self::Client(client) => client.router().peer_pool(),
206            Self::BootstrapClient(client) => client.peer_pool(),
207        }
208    }
209
210    /// Get the underlying ledger (if any).
211    pub fn ledger(&self) -> Option<&Ledger<N, ConsensusDB<N>>> {
212        match self {
213            Self::Validator(node) => Some(node.ledger()),
214            Self::Prover(_) => None,
215            Self::Client(node) => Some(node.ledger()),
216            Self::BootstrapClient(_) => None,
217        }
218    }
219
220    /// Returns `true` if the node is synced up to the latest block (within the given tolerance).
221    pub fn is_block_synced(&self) -> bool {
222        match self {
223            Self::Validator(node) => node.is_block_synced(),
224            Self::Prover(node) => node.is_block_synced(),
225            Self::Client(node) => node.is_block_synced(),
226            Self::BootstrapClient(_) => true,
227        }
228    }
229
230    /// Returns the number of blocks this node is behind the greatest peer height,
231    /// or `None` if not connected to peers yet.
232    pub fn num_blocks_behind(&self) -> Option<u32> {
233        match self {
234            Self::Validator(node) => node.num_blocks_behind(),
235            Self::Prover(node) => node.num_blocks_behind(),
236            Self::Client(node) => node.num_blocks_behind(),
237            Self::BootstrapClient(_) => Some(0),
238        }
239    }
240
241    /// Calculates the current sync speed in blocks per second.
242    /// Returns None if sync speed cannot be calculated (e.g., not syncing or insufficient data).
243    pub fn get_sync_speed(&self) -> f64 {
244        match self {
245            Self::Validator(node) => node.get_sync_speed(),
246            Self::Prover(node) => node.get_sync_speed(),
247            Self::Client(node) => node.get_sync_speed(),
248            Self::BootstrapClient(_) => 0.0,
249        }
250    }
251
252    /// Shuts down the node.
253    pub async fn shut_down(&self) {
254        match self {
255            Self::Validator(node) => node.shut_down().await,
256            Self::Prover(node) => node.shut_down().await,
257            Self::Client(node) => node.shut_down().await,
258            Self::BootstrapClient(node) => node.shut_down().await,
259        }
260    }
261}