utils.rs
1 // Copyright (c) 2025-2026 ACDC Network 2 // This file is part of the alphaos library. 3 // 4 // Alpha Chain | Delta Chain Protocol 5 // International Monetary Graphite. 6 // 7 // Derived from Aleo (https://aleo.org) and ProvableHQ (https://provable.com). 8 // They built world-class ZK infrastructure. We installed the EASY button. 9 // Their cryptography: elegant. Our modifications: bureaucracy-compatible. 10 // Original brilliance: theirs. Robert's Rules: ours. Bugs: definitely ours. 11 // 12 // Original Aleo/ProvableHQ code subject to Apache 2.0 https://www.apache.org/licenses/LICENSE-2.0 13 // All modifications and new work: CC0 1.0 Universal Public Domain Dedication. 14 // No rights reserved. No permission required. No warranty. No refunds. 15 // 16 // https://creativecommons.org/publicdomain/zero/1.0/ 17 // SPDX-License-Identifier: CC0-1.0 18 19 use crate::common::{primary, CurrentNetwork, TranslucentLedgerService}; 20 use alphaos_account::Account; 21 use alphaos_node_bft::{ 22 helpers::{PrimarySender, Storage}, 23 Gateway, 24 Worker, 25 }; 26 27 use alphaos_node_bft::storage_service::BFTMemoryService; 28 use alphaos_utilities::SimpleStoppable; 29 use alphastd::StorageMode; 30 31 use alphavm::{ 32 console::account::Address, 33 ledger::{ 34 committee::Committee, 35 narwhal::{BatchHeader, Data}, 36 store::helpers::memory::ConsensusMemory, 37 }, 38 prelude::{ 39 block::Transaction, 40 committee::MIN_VALIDATOR_STAKE, 41 puzzle::{Solution, SolutionID}, 42 Field, 43 Network, 44 TestRng, 45 Uniform, 46 }, 47 }; 48 49 use std::{str::FromStr, sync::Arc, time::Duration}; 50 51 use ::bytes::Bytes; 52 use indexmap::IndexMap; 53 #[cfg(feature = "locktick")] 54 use locktick::parking_lot::RwLock; 55 #[cfg(not(feature = "locktick"))] 56 use parking_lot::RwLock; 57 use rand::Rng; 58 use tokio::{sync::oneshot, task::JoinHandle, time::sleep}; 59 use tracing::*; 60 use tracing_subscriber::{ 61 layer::{Layer, SubscriberExt}, 62 util::SubscriberInitExt, 63 }; 64 65 /// Initializes the logger. 66 pub fn initialize_logger(verbosity: u8) { 67 let verbosity_str = match verbosity { 68 0 => "info", 69 1 => "debug", 70 2..=4 => "trace", 71 _ => "info", 72 }; 73 74 // Filter out undesirable logs. (unfortunately EnvFilter cannot be cloned) 75 let filter = tracing_subscriber::EnvFilter::from_str(verbosity_str) 76 .unwrap() 77 .add_directive("mio=off".parse().unwrap()) 78 .add_directive("tokio_util=off".parse().unwrap()) 79 .add_directive("hyper=off".parse().unwrap()) 80 .add_directive("reqwest=off".parse().unwrap()) 81 .add_directive("want=off".parse().unwrap()) 82 .add_directive("h2=off".parse().unwrap()); 83 84 let filter = if verbosity > 3 { 85 filter.add_directive("alphaos_node_tcp=trace".parse().unwrap()) 86 } else { 87 filter.add_directive("alphaos_node_tcp=off".parse().unwrap()) 88 }; 89 90 // Initialize tracing. 91 let _ = tracing_subscriber::registry() 92 .with(tracing_subscriber::fmt::Layer::default().with_target(verbosity > 2).with_filter(filter)) 93 .try_init(); 94 } 95 96 /// Fires *fake* unconfirmed solutions at the node. 97 pub fn fire_unconfirmed_solutions( 98 sender: &PrimarySender<CurrentNetwork>, 99 node_id: u16, 100 interval_ms: u64, 101 ) -> JoinHandle<()> { 102 let tx_unconfirmed_solution = sender.tx_unconfirmed_solution.clone(); 103 tokio::task::spawn(async move { 104 // This RNG samples the *same* fake solutions for all nodes. 105 let mut shared_rng = TestRng::fixed(123456789); 106 // This RNG samples *different* fake solutions for each node. 107 let mut unique_rng = TestRng::fixed(node_id as u64); 108 109 // A closure to generate a solution ID and solution. 110 async fn sample(mut rng: impl Rng) -> (SolutionID<CurrentNetwork>, Data<Solution<CurrentNetwork>>) { 111 // Sample a random fake solution ID. 112 let solution_id = rng.r#gen::<u64>().into(); 113 // Sample random fake solution bytes. 114 let mut vec = vec![0u8; 1024]; 115 rng.fill_bytes(&mut vec); 116 let solution = Data::Buffer(Bytes::from(vec)); 117 // Return the solution ID and solution. 118 (solution_id, solution) 119 } 120 121 // Initialize a counter. 122 let mut counter = 0; 123 124 loop { 125 // Sample a random fake solution ID and solution. 126 let (solution_id, solution) = 127 if counter % 2 == 0 { sample(&mut shared_rng).await } else { sample(&mut unique_rng).await }; 128 // Initialize a callback sender and receiver. 129 let (callback, callback_receiver) = oneshot::channel(); 130 // Send the fake solution. 131 if let Err(e) = tx_unconfirmed_solution.send((solution_id, solution, callback)).await { 132 error!("Failed to send unconfirmed solution: {e}"); 133 } 134 let _ = callback_receiver.await; 135 // Increment the counter. 136 counter += 1; 137 // Sleep briefly. 138 sleep(Duration::from_millis(interval_ms)).await; 139 } 140 }) 141 } 142 143 /// Fires *fake* unconfirmed transactions at the node. 144 pub fn fire_unconfirmed_transactions( 145 sender: &PrimarySender<CurrentNetwork>, 146 node_id: u16, 147 interval_ms: u64, 148 ) -> JoinHandle<()> { 149 let tx_unconfirmed_transaction = sender.tx_unconfirmed_transaction.clone(); 150 tokio::task::spawn(async move { 151 // This RNG samples the *same* fake transactions for all nodes. 152 let mut shared_rng = TestRng::fixed(123456789); 153 // This RNG samples *different* fake transactions for each node. 154 let mut unique_rng = TestRng::fixed(node_id as u64); 155 156 // A closure to generate an ID and transaction. 157 fn sample( 158 mut rng: impl Rng, 159 ) -> (<CurrentNetwork as Network>::TransactionID, Data<Transaction<CurrentNetwork>>) { 160 // Sample a random fake transaction ID. 161 let id = Field::<CurrentNetwork>::rand(&mut rng).into(); 162 // Sample random fake transaction bytes. 163 let mut vec = vec![0u8; 1024]; 164 rng.fill_bytes(&mut vec); 165 let transaction = Data::Buffer(Bytes::from(vec)); 166 // Return the ID and transaction. 167 (id, transaction) 168 } 169 170 // Initialize a counter. 171 let mut counter = 0; 172 173 loop { 174 // Sample a random fake transaction ID and transaction. 175 let (id, transaction) = if counter % 2 == 0 { sample(&mut shared_rng) } else { sample(&mut unique_rng) }; 176 // Initialize a callback sender and receiver. 177 let (callback, callback_receiver) = oneshot::channel(); 178 // Send the fake transaction. 179 if let Err(e) = tx_unconfirmed_transaction.send((id, transaction, callback)).await { 180 error!("Failed to send unconfirmed transaction: {e}"); 181 } 182 let _ = callback_receiver.await; 183 // Increment the counter. 184 counter += 1; 185 // Sleep briefly. 186 sleep(Duration::from_millis(interval_ms)).await; 187 } 188 }) 189 } 190 191 /// Samples a new ledger with the given number of nodes. 192 pub fn sample_ledger( 193 accounts: &[Account<CurrentNetwork>], 194 committee: &Committee<CurrentNetwork>, 195 rng: &mut TestRng, 196 ) -> Arc<TranslucentLedgerService<CurrentNetwork, ConsensusMemory<CurrentNetwork>>> { 197 let num_nodes = committee.num_members(); 198 let bonded_balances: IndexMap<_, _> = 199 committee.members().iter().map(|(address, (amount, _, _))| (*address, (*address, *address, *amount))).collect(); 200 let gen_key = *accounts[0].private_key(); 201 let public_balance_per_validator = 202 (CurrentNetwork::STARTING_SUPPLY - (num_nodes as u64) * MIN_VALIDATOR_STAKE) / (num_nodes as u64); 203 let mut balances = IndexMap::<Address<CurrentNetwork>, u64>::new(); 204 for account in accounts.iter() { 205 balances.insert(account.address(), public_balance_per_validator); 206 } 207 208 let gen_ledger = 209 primary::genesis_ledger(gen_key, committee.clone(), balances.clone(), bonded_balances.clone(), rng); 210 Arc::new(TranslucentLedgerService::new(gen_ledger, SimpleStoppable::new())) 211 } 212 213 /// Samples a new storage with the given ledger. 214 pub fn sample_storage<N: Network>(ledger: Arc<TranslucentLedgerService<N, ConsensusMemory<N>>>) -> Storage<N> { 215 Storage::new(ledger, Arc::new(BFTMemoryService::new()), BatchHeader::<N>::MAX_GC_ROUNDS as u64) 216 } 217 218 /// Samples a new gateway with the given ledger. 219 pub fn sample_gateway<N: Network>( 220 account: Account<N>, 221 storage: Storage<N>, 222 ledger: Arc<TranslucentLedgerService<N, ConsensusMemory<N>>>, 223 ) -> Gateway<N> { 224 // Initialize the gateway. 225 Gateway::new(account, storage, ledger, None, &[], false, StorageMode::new_test(None), None).unwrap() 226 } 227 228 /// Samples a new worker with the given ledger. 229 pub fn sample_worker<N: Network>( 230 id: u8, 231 account: Account<N>, 232 ledger: Arc<TranslucentLedgerService<N, ConsensusMemory<N>>>, 233 ) -> Worker<N> { 234 // Sample a storage. 235 let storage = sample_storage(ledger.clone()); 236 // Sample a gateway. 237 let gateway = sample_gateway(account, storage.clone(), ledger.clone()); 238 // Sample a dummy proposed batch. 239 let proposed_batch = Arc::new(RwLock::new(None)); 240 // Construct the worker instance. 241 Worker::new(id, Arc::new(gateway.clone()), storage.clone(), ledger, proposed_batch).unwrap() 242 }