amareleo_node/validator/
mod.rs

1// Copyright 2024 Aleo Network Foundation
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 amareleo_chain_account::Account;
17use amareleo_chain_tracing::{TracingHandler, TracingHandlerGuard};
18use amareleo_node_bft::{helpers::init_primary_channels, ledger_service::CoreLedgerService};
19use amareleo_node_consensus::Consensus;
20use amareleo_node_rest::Rest;
21
22use snarkvm::prelude::{Ledger, Network, block::Block, store::ConsensusStorage};
23
24use aleo_std::StorageMode;
25use anyhow::Result;
26use std::{
27    net::SocketAddr,
28    sync::{Arc, atomic::AtomicBool},
29};
30use tracing::subscriber::DefaultGuard;
31
32/// A validator is a full node, capable of validating blocks.
33#[derive(Clone)]
34pub struct Validator<N: Network, C: ConsensusStorage<N>> {
35    /// The ledger of the node.
36    ledger: Ledger<N, C>,
37    /// The consensus module of the node.
38    consensus: Consensus<N>,
39    /// The REST server of the node.
40    rest: Option<Rest<N, C>>,
41    /// Tracing handle
42    tracing: Option<TracingHandler>,
43    /// The shutdown signal.
44    shutdown: Arc<AtomicBool>,
45}
46
47impl<N: Network, C: ConsensusStorage<N>> TracingHandlerGuard for Validator<N, C> {
48    /// Retruns tracing guard
49    fn get_tracing_guard(&self) -> Option<DefaultGuard> {
50        self.tracing.as_ref().and_then(|trace_handle| trace_handle.get_tracing_guard())
51    }
52}
53
54impl<N: Network, C: ConsensusStorage<N>> Validator<N, C> {
55    /// Initializes a new validator node.
56    pub async fn new(
57        rest_ip: SocketAddr,
58        rest_rps: u32,
59        account: Account<N>,
60        genesis: Block<N>,
61        keep_state: bool,
62        storage_mode: StorageMode,
63        tracing: Option<TracingHandler>,
64        shutdown: Arc<AtomicBool>,
65    ) -> Result<Self> {
66        // Initialize the ledger.
67        let ledger = Ledger::load(genesis, storage_mode.clone())?;
68        let tracing_: TracingHandler = tracing.clone().into();
69
70        // Initialize and start the Consensus
71        guard_info!(tracing_, "Starting Consensus...");
72        let ledger_service = Arc::new(CoreLedgerService::new(ledger.clone(), tracing.clone(), shutdown.clone()));
73        let mut consensus =
74            Consensus::new(account.clone(), ledger_service.clone(), keep_state, storage_mode.clone(), tracing.clone())?;
75
76        let (primary_sender, primary_receiver) = init_primary_channels::<N>();
77        consensus.run(primary_sender, primary_receiver).await?;
78
79        // Initialize the REST server.
80        guard_info!(tracing_, "Starting the REST server...");
81        let rest_srv = Rest::start(rest_ip, rest_rps, Some(consensus.clone()), ledger.clone(), tracing.clone()).await;
82        if let Err(err) = rest_srv {
83            guard_error!(tracing_, "Failed to start REST server: {:?}", err);
84            consensus.shut_down().await;
85            return Err(err);
86        }
87
88        // Return the node.
89        Ok(Self { ledger, consensus, rest: Some(rest_srv.unwrap()), tracing, shutdown })
90    }
91
92    /// Returns the ledger.
93    pub fn ledger(&self) -> &Ledger<N, C> {
94        &self.ledger
95    }
96
97    /// Returns the REST server.
98    pub fn rest(&self) -> &Option<Rest<N, C>> {
99        &self.rest
100    }
101}
102
103impl<N: Network, C: ConsensusStorage<N>> Validator<N, C> {
104    /// Shuts down the node.
105    pub async fn shut_down(&self) {
106        // Flag that we are shutting down.
107        // This will prevent adding further blocks to the ledger.
108        guard_info!(self, "Shutting down...");
109        self.shutdown.store(true, std::sync::atomic::Ordering::Release);
110
111        // Shut down rest server.
112        if let Some(rest) = &self.rest {
113            guard_trace!(self, "Shutting down the REST server...");
114            rest.shut_down().await;
115        }
116
117        // Shut down consensus.
118        guard_trace!(self, "Shutting down consensus...");
119        self.consensus.shut_down().await;
120
121        guard_info!(self, "Node has shut down.");
122        guard_info!(self, "");
123    }
124}
125
126#[cfg(test)]
127mod tests {
128    use super::*;
129    use amareleo_node_bft::DEVELOPMENT_MODE_RNG_SEED;
130
131    use snarkvm::prelude::{
132        MainnetV0,
133        VM,
134        store::{ConsensusStore, helpers::memory::ConsensusMemory},
135    };
136
137    use anyhow::bail;
138    use rand::SeedableRng;
139    use rand_chacha::ChaChaRng;
140    use std::str::FromStr;
141
142    type CurrentNetwork = MainnetV0;
143
144    /// Use `RUST_MIN_STACK=67108864 cargo test --release profiler --features timer` to run this test.
145    #[ignore]
146    #[tokio::test]
147    async fn test_profiler() -> Result<()> {
148        // Specify the node attributes.
149        let rest = SocketAddr::from_str("0.0.0.0:3030").unwrap();
150        let storage_mode = StorageMode::Development(0);
151
152        // Initialize an (insecure) fixed RNG.
153        let mut rng = ChaChaRng::seed_from_u64(DEVELOPMENT_MODE_RNG_SEED);
154        // Initialize the account.
155        let account = Account::<CurrentNetwork>::new(&mut rng).unwrap();
156        // Initialize a new VM.
157        let vm = VM::from(ConsensusStore::<CurrentNetwork, ConsensusMemory<CurrentNetwork>>::open(
158            StorageMode::new_test(None),
159        )?)?;
160        // Initialize the genesis block.
161        let genesis = vm.genesis_beacon(account.private_key(), &mut rng)?;
162
163        println!("Initializing validator node...");
164
165        let validator = Validator::<CurrentNetwork, ConsensusMemory<CurrentNetwork>>::new(
166            rest,
167            10,
168            account,
169            genesis,
170            false,
171            storage_mode,
172            None,
173            Default::default(),
174        )
175        .await
176        .unwrap();
177
178        println!("Loaded validator node with {} blocks", validator.ledger.latest_height(),);
179
180        bail!("\n\nRemember to #[ignore] this test!\n\n")
181    }
182}