diff --git a/src/args.rs b/src/args.rs index 3da5854..04da0b7 100644 --- a/src/args.rs +++ b/src/args.rs @@ -118,6 +118,14 @@ pub struct CliArgs { /// Provide File with current chain #[arg(short = 'f', long)] pub seed_file: Option, + + /// Enable debug mode (alternative syntax) + #[arg(short = 'b', long = "bootstrap", action = clap::ArgAction::SetTrue)] + pub bootstrap: bool, + + /// Enable debug mode (alternative syntax) + #[arg(short = 's', long = "seed", action = clap::ArgAction::SetTrue)] + pub seed: bool, } #[derive(Subcommand, Debug)] diff --git a/src/core/blockchain.rs b/src/core/blockchain.rs index bf9f000..ec818c4 100644 --- a/src/core/blockchain.rs +++ b/src/core/blockchain.rs @@ -19,6 +19,7 @@ pub enum ValidationError { InvalidPreviousBlockHash } +#[allow(dead_code)] #[derive(Debug, Default)] pub struct Blockchain { id: String, @@ -139,7 +140,6 @@ impl Blockchain { new_head.block_hash = block_hash; let new_block = core::Block::new(new_head, self.tx_mempool.clone()); - log!(DEBUG, "Created new Block {:#?}", new_block); self.blocks.push(new_block); self.blocks.last().unwrap().clone() } @@ -198,11 +198,12 @@ pub fn calculate_block_hash(head: &core::BlockHeader) -> String { } impl Blockchain { - pub fn print_blocks(&self) { - println!("Blocks List\n--------------"); + pub fn list_blocks(&self) -> String { + let mut ret = String::from("Blocks List\n-------------------"); for (i, b) in self.blocks.iter().enumerate() { - println!("Block #{i}\n{:#?}", b.head().block_hash); + ret.push_str(format!("Block Hash #{i}: {}\n", b.head.block_hash()).as_str()) } + ret } pub fn get_balances(&self) -> &std::collections::HashMap { @@ -238,7 +239,6 @@ impl Blockchain { } fn validate_chain(&self) -> Result<(), ValidationError>{ - log!(INFO, "Validating Chain"); let blocks = self.blocks(); for block in blocks { let head = block.head(); @@ -252,7 +252,6 @@ impl Blockchain { } pub fn build(blocks: Vec) -> Result { - log!(INFO, "Starting Chain Build from Genesis"); let chain = Blockchain { blocks, balances: HashMap::new(), diff --git a/src/error.rs b/src/error.rs index 24104fa..ca2b51f 100644 --- a/src/error.rs +++ b/src/error.rs @@ -24,20 +24,22 @@ pub enum TxError { UnknownAccount(String) } -pub fn print_error_chain(err: &dyn std::error::Error) { - eprintln!("Error: {}", err); +pub fn print_error_chain(err: &dyn std::error::Error) -> String { - let mut source = err.source(); - let mut level = 1; + let mut err_string = String::from(format!("Error: {}", err)); - while let Some(err) = source { - eprintln!(" {}: {}", level, err); - source = err.source(); - level += 1; - } + let mut source = err.source(); + let mut level = 1; + + while let Some(err) = source { + err_string.push_str(format!(" {}: {}", level, err).as_str()); + source = err.source(); + level += 1; + } + err_string } -pub fn handle_error(err: BlockchainError) { +pub fn handle_error(err: BlockchainError) -> String { match &err { BlockchainError::Tx(tx) => { match tx { diff --git a/src/main.rs b/src/main.rs index d5b568d..9ca76d5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,14 +6,24 @@ pub mod seeds_constants; pub mod watcher; pub mod cli; -use crate::{args::get_args, watcher::watcher::Watcher}; +use crate::watcher::watcher::Watcher; +use clap::Parser; + +pub async fn log(exec_tx: &tokio::sync::mpsc::Sender, msg: String) { + let cmd = watcher::ExecutorCommand::Print(msg); + let _ = exec_tx.send(cmd).await; +} #[tokio::main] async fn main() { - let args = get_args(); + let args = args::CliArgs::parse(); - let mut watcher = Watcher::build().file(args.seed_file).addr(args.addr).start().await; + let mut watcher = Watcher::build() + .file(args.seed_file) + .addr(args.addr) + .bootstrap(args.bootstrap) + .start().await; loop { if !watcher.poll().await.is_ok_and(|b| b) { diff --git a/src/native_node/node.rs b/src/native_node/node.rs index 57be2a1..b46f6f5 100644 --- a/src/native_node/node.rs +++ b/src/native_node/node.rs @@ -45,7 +45,6 @@ pub enum NodeCommand { Exit, } - impl NativeNode { pub fn peer_addresses(&self) -> Vec { @@ -84,7 +83,7 @@ impl NativeNode { self.tcp_peers.insert(id, peer); } - pub fn new_with_id( + pub async fn new_with_id( id: uuid::Uuid, exec_tx: mpsc::Sender, addr: Option, @@ -96,6 +95,7 @@ impl NativeNode { tcp_peers: HashMap::new(), chain: { if blocks.is_some() { + crate::log(&exec_tx, msg!(INFO, "Building Chain")).await; Blockchain::build(blocks.unwrap()).unwrap_or(Default::default()) } else { Default::default() @@ -109,7 +109,7 @@ impl NativeNode { } } - pub fn new( + pub async fn new( addr: Option, blocks: Option>, exec_tx: mpsc::Sender, @@ -120,6 +120,7 @@ impl NativeNode { tcp_peers: HashMap::new(), chain: { if blocks.is_some() { + crate::log(&exec_tx, msg!(INFO, "Building Chain")).await; Blockchain::build(blocks.unwrap()).unwrap_or(Default::default()) } else { Default::default() @@ -223,10 +224,17 @@ impl NativeNode { } async fn log(&self, msg: String) { - let _ = self.exec_tx.send(ExecutorCommand::Print(msg)); + let _ = self.exec_tx.send(ExecutorCommand::Print(msg)).await; } - pub async fn run_native(&mut self) { + pub async fn transaction(&mut self, tx: &core::Tx) { + match self.chain.apply(tx) { + Ok(_) => self.log(msg!(INFO, "Transaction applied")).await, + Err(e) => self.log(crate::error::print_error_chain(&e)).await + }; + } + + pub async fn run(&mut self) { if let Some(a) = self.addr { self.start_connection_listner(a.clone()).await; @@ -255,7 +263,7 @@ impl NativeNode { self.process_message(peer_id, &message).await; }, NodeCommand::Transaction { tx } => { - self.chain.apply(&tx).unwrap(); + self.transaction(&tx).await; self.broadcast_transaction(&tx).await; }, NodeCommand::CreateBlock => { @@ -265,7 +273,7 @@ impl NativeNode { }, NodeCommand::ListBlocks => { self.log(msg!(INFO, "Received DebugListBlocks command")).await; - self.chain.print_blocks(); + self.log(self.chain.list_blocks()).await; }, NodeCommand::ListPeers => { self.log(msg!(INFO, "Received DebugListPeers command")).await; diff --git a/src/watcher/executor.rs b/src/watcher/executor.rs index 9b01e66..7672c11 100644 --- a/src/watcher/executor.rs +++ b/src/watcher/executor.rs @@ -61,12 +61,12 @@ impl Executor { // } } - async fn render_string(&self, str: String) { + pub async fn render_string(&self, str: String) { let rd_cmd = RenderCommand::RenderStringToPane{ str, pane: RenderPane::CliOutput }; - let _ = self.render_tx.send(rd_cmd); + let _ = self.render_tx.send(rd_cmd).await; } async fn echo(&self, s: Vec) { diff --git a/src/watcher/parser.rs b/src/watcher/parser.rs index 92ddfd6..419f8f3 100644 --- a/src/watcher/parser.rs +++ b/src/watcher/parser.rs @@ -6,8 +6,6 @@ use tokio::time::{timeout, Duration}; use tokio::sync::mpsc; -use crate::watcher::renderer::RenderPane; - #[derive(Debug)] pub struct Parser { rx: mpsc::Receiver, @@ -20,10 +18,6 @@ pub enum ParserCommand { Exit } -const CMD_ECHO: &str = "echo"; -const CMD_CLEAR: &str = "clear"; -const CMD_NODE: &str = "node"; - impl Parser { pub fn new( rx: mpsc::Receiver, @@ -64,30 +58,6 @@ impl Parser { let cmd = cli(&argv); let _ = self.exec_tx.send(cmd).await; }, - //match *cmd { - // CMD_NODE => { cli(&s_split) } - // CMD_ECHO => { - // if args.is_empty() { - // ExecutorCommand::InvalidCommand(msg!(ERROR, "print expects args")) - // } else { - // ExecutorCommand::Echo(args.iter().map(|a| a.to_string()).collect()) - // } - // } - // CMD_CLEAR => { - // if args.is_empty() { - // ExecutorCommand::Clear(RenderPane::All) - // } else if args[0] == "in" { - // ExecutorCommand::Clear(RenderPane::CliInput) - // } else if args[0] == "out" { - // ExecutorCommand::Clear(RenderPane::CliOutput) - // } else { - // ExecutorCommand::InvalidCommand(msg!(ERROR, "clear: Unknown arg {}", args[0])) - // } - // } - // _ => { - // ExecutorCommand::InvalidCommand(msg!(ERROR, "Unknown Command {cmd}")) - // } - // }; ParserCommand::Exit => { self.exit().await; } diff --git a/src/watcher/watcher.rs b/src/watcher/watcher.rs index 028689a..40ea6ab 100644 --- a/src/watcher/watcher.rs +++ b/src/watcher/watcher.rs @@ -20,7 +20,8 @@ pub struct Watcher { #[derive(Default)] pub struct WatcherBuilder { addr: Option, - seed_file: Option + seed_file: Option, + bootstrap: bool } impl Watcher { @@ -28,6 +29,18 @@ impl Watcher { WatcherBuilder::new() } + pub fn render_tx(&self) -> mpsc::Sender { + self.render_tx.clone() + } + + pub fn parser_tx(&self) -> mpsc::Sender { + self.parser_tx.clone() + } + + pub fn exec_tx(&self) -> mpsc::Sender { + self.exec_tx.clone() + } + pub async fn log(render_tx: &mpsc::Sender, msg: String) { let rendermsg = RenderCommand::RenderStringToPane { str: msg, pane: RenderPane::CliOutput }; if let Err(e) = render_tx.send(rendermsg).await { @@ -99,6 +112,11 @@ impl WatcherBuilder { self } + pub fn bootstrap(mut self, bootstrap: bool) -> Self { + self.bootstrap = bootstrap; + self + } + pub async fn log(render_tx: &mpsc::Sender, msg: String) { let rendermsg = RenderCommand::RenderStringToPane { str: msg, pane: RenderPane::CliOutput }; let _ = render_tx.send(rendermsg).await; @@ -122,7 +140,11 @@ impl WatcherBuilder { .as_ref() .and_then(|path| std::fs::read_to_string(path).ok()) .and_then(|content| serde_json::from_str(&content).ok()); - let mut node = NativeNode::new(self.addr.clone(), blocks, exec_tx.clone()); + + let mut node = NativeNode::new(self.addr.clone(), blocks, exec_tx.clone()).await; + if self.bootstrap { + let _ = node.bootstrap().await; + } let _ = Self::log(&render_tx, msg!(INFO, "Build Node")); let parser_handle = tokio::spawn({ @@ -148,7 +170,7 @@ impl WatcherBuilder { let node_handle = tokio::spawn({ async move { - node.run_native().await; + node.run().await; } });