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