This commit is contained in:
Victor Vobis 2025-08-27 23:02:58 +02:00
parent 7ac62bdc00
commit d6f7c758c0
8 changed files with 80 additions and 61 deletions

View File

@ -118,6 +118,14 @@ pub struct CliArgs {
/// Provide File with current chain /// Provide File with current chain
#[arg(short = 'f', long)] #[arg(short = 'f', long)]
pub seed_file: Option<String>, pub seed_file: Option<String>,
/// 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)] #[derive(Subcommand, Debug)]

View File

@ -19,6 +19,7 @@ pub enum ValidationError {
InvalidPreviousBlockHash InvalidPreviousBlockHash
} }
#[allow(dead_code)]
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct Blockchain { pub struct Blockchain {
id: String, id: String,
@ -139,7 +140,6 @@ impl Blockchain {
new_head.block_hash = block_hash; new_head.block_hash = block_hash;
let new_block = core::Block::new(new_head, self.tx_mempool.clone()); 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.push(new_block);
self.blocks.last().unwrap().clone() self.blocks.last().unwrap().clone()
} }
@ -198,11 +198,12 @@ pub fn calculate_block_hash(head: &core::BlockHeader) -> String {
} }
impl Blockchain { impl Blockchain {
pub fn print_blocks(&self) { pub fn list_blocks(&self) -> String {
println!("Blocks List\n--------------"); let mut ret = String::from("Blocks List\n-------------------");
for (i, b) in self.blocks.iter().enumerate() { 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<String, u32> { pub fn get_balances(&self) -> &std::collections::HashMap<String, u32> {
@ -238,7 +239,6 @@ impl Blockchain {
} }
fn validate_chain(&self) -> Result<(), ValidationError>{ fn validate_chain(&self) -> Result<(), ValidationError>{
log!(INFO, "Validating Chain");
let blocks = self.blocks(); let blocks = self.blocks();
for block in blocks { for block in blocks {
let head = block.head(); let head = block.head();
@ -252,7 +252,6 @@ impl Blockchain {
} }
pub fn build(blocks: Vec<core::Block>) -> Result<Blockchain, ValidationError> { pub fn build(blocks: Vec<core::Block>) -> Result<Blockchain, ValidationError> {
log!(INFO, "Starting Chain Build from Genesis");
let chain = Blockchain { let chain = Blockchain {
blocks, blocks,
balances: HashMap::new(), balances: HashMap::new(),

View File

@ -24,20 +24,22 @@ pub enum TxError {
UnknownAccount(String) UnknownAccount(String)
} }
pub fn print_error_chain(err: &dyn std::error::Error) { pub fn print_error_chain(err: &dyn std::error::Error) -> String {
eprintln!("Error: {}", err);
let mut err_string = String::from(format!("Error: {}", err));
let mut source = err.source(); let mut source = err.source();
let mut level = 1; let mut level = 1;
while let Some(err) = source { while let Some(err) = source {
eprintln!(" {}: {}", level, err); err_string.push_str(format!(" {}: {}", level, err).as_str());
source = err.source(); source = err.source();
level += 1; level += 1;
} }
err_string
} }
pub fn handle_error(err: BlockchainError) { pub fn handle_error(err: BlockchainError) -> String {
match &err { match &err {
BlockchainError::Tx(tx) => { BlockchainError::Tx(tx) => {
match tx { match tx {

View File

@ -6,14 +6,24 @@ pub mod seeds_constants;
pub mod watcher; pub mod watcher;
pub mod cli; 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<watcher::ExecutorCommand>, msg: String) {
let cmd = watcher::ExecutorCommand::Print(msg);
let _ = exec_tx.send(cmd).await;
}
#[tokio::main] #[tokio::main]
async fn 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 { loop {
if !watcher.poll().await.is_ok_and(|b| b) { if !watcher.poll().await.is_ok_and(|b| b) {

View File

@ -45,7 +45,6 @@ pub enum NodeCommand {
Exit, Exit,
} }
impl NativeNode { impl NativeNode {
pub fn peer_addresses(&self) -> Vec<SocketAddr> { pub fn peer_addresses(&self) -> Vec<SocketAddr> {
@ -84,7 +83,7 @@ impl NativeNode {
self.tcp_peers.insert(id, peer); self.tcp_peers.insert(id, peer);
} }
pub fn new_with_id( pub async fn new_with_id(
id: uuid::Uuid, id: uuid::Uuid,
exec_tx: mpsc::Sender<ExecutorCommand>, exec_tx: mpsc::Sender<ExecutorCommand>,
addr: Option<SocketAddr>, addr: Option<SocketAddr>,
@ -96,6 +95,7 @@ impl NativeNode {
tcp_peers: HashMap::new(), tcp_peers: HashMap::new(),
chain: { chain: {
if blocks.is_some() { if blocks.is_some() {
crate::log(&exec_tx, msg!(INFO, "Building Chain")).await;
Blockchain::build(blocks.unwrap()).unwrap_or(Default::default()) Blockchain::build(blocks.unwrap()).unwrap_or(Default::default())
} else { } else {
Default::default() Default::default()
@ -109,7 +109,7 @@ impl NativeNode {
} }
} }
pub fn new( pub async fn new(
addr: Option<SocketAddr>, addr: Option<SocketAddr>,
blocks: Option<Vec<core::Block>>, blocks: Option<Vec<core::Block>>,
exec_tx: mpsc::Sender<ExecutorCommand>, exec_tx: mpsc::Sender<ExecutorCommand>,
@ -120,6 +120,7 @@ impl NativeNode {
tcp_peers: HashMap::new(), tcp_peers: HashMap::new(),
chain: { chain: {
if blocks.is_some() { if blocks.is_some() {
crate::log(&exec_tx, msg!(INFO, "Building Chain")).await;
Blockchain::build(blocks.unwrap()).unwrap_or(Default::default()) Blockchain::build(blocks.unwrap()).unwrap_or(Default::default())
} else { } else {
Default::default() Default::default()
@ -223,10 +224,17 @@ impl NativeNode {
} }
async fn log(&self, msg: String) { 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 { if let Some(a) = self.addr {
self.start_connection_listner(a.clone()).await; self.start_connection_listner(a.clone()).await;
@ -255,7 +263,7 @@ impl NativeNode {
self.process_message(peer_id, &message).await; self.process_message(peer_id, &message).await;
}, },
NodeCommand::Transaction { tx } => { NodeCommand::Transaction { tx } => {
self.chain.apply(&tx).unwrap(); self.transaction(&tx).await;
self.broadcast_transaction(&tx).await; self.broadcast_transaction(&tx).await;
}, },
NodeCommand::CreateBlock => { NodeCommand::CreateBlock => {
@ -265,7 +273,7 @@ impl NativeNode {
}, },
NodeCommand::ListBlocks => { NodeCommand::ListBlocks => {
self.log(msg!(INFO, "Received DebugListBlocks command")).await; self.log(msg!(INFO, "Received DebugListBlocks command")).await;
self.chain.print_blocks(); self.log(self.chain.list_blocks()).await;
}, },
NodeCommand::ListPeers => { NodeCommand::ListPeers => {
self.log(msg!(INFO, "Received DebugListPeers command")).await; self.log(msg!(INFO, "Received DebugListPeers command")).await;

View File

@ -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{ let rd_cmd = RenderCommand::RenderStringToPane{
str, str,
pane: RenderPane::CliOutput pane: RenderPane::CliOutput
}; };
let _ = self.render_tx.send(rd_cmd); let _ = self.render_tx.send(rd_cmd).await;
} }
async fn echo(&self, s: Vec<String>) { async fn echo(&self, s: Vec<String>) {

View File

@ -6,8 +6,6 @@ use tokio::time::{timeout, Duration};
use tokio::sync::mpsc; use tokio::sync::mpsc;
use crate::watcher::renderer::RenderPane;
#[derive(Debug)] #[derive(Debug)]
pub struct Parser { pub struct Parser {
rx: mpsc::Receiver<ParserCommand>, rx: mpsc::Receiver<ParserCommand>,
@ -20,10 +18,6 @@ pub enum ParserCommand {
Exit Exit
} }
const CMD_ECHO: &str = "echo";
const CMD_CLEAR: &str = "clear";
const CMD_NODE: &str = "node";
impl Parser { impl Parser {
pub fn new( pub fn new(
rx: mpsc::Receiver<ParserCommand>, rx: mpsc::Receiver<ParserCommand>,
@ -64,30 +58,6 @@ impl Parser {
let cmd = cli(&argv); let cmd = cli(&argv);
let _ = self.exec_tx.send(cmd).await; 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 => { ParserCommand::Exit => {
self.exit().await; self.exit().await;
} }

View File

@ -20,7 +20,8 @@ pub struct Watcher {
#[derive(Default)] #[derive(Default)]
pub struct WatcherBuilder { pub struct WatcherBuilder {
addr: Option<SocketAddr>, addr: Option<SocketAddr>,
seed_file: Option<String> seed_file: Option<String>,
bootstrap: bool
} }
impl Watcher { impl Watcher {
@ -28,6 +29,18 @@ impl Watcher {
WatcherBuilder::new() WatcherBuilder::new()
} }
pub fn render_tx(&self) -> mpsc::Sender<RenderCommand> {
self.render_tx.clone()
}
pub fn parser_tx(&self) -> mpsc::Sender<ParserCommand> {
self.parser_tx.clone()
}
pub fn exec_tx(&self) -> mpsc::Sender<ExecutorCommand> {
self.exec_tx.clone()
}
pub async fn log(render_tx: &mpsc::Sender<RenderCommand>, msg: String) { pub async fn log(render_tx: &mpsc::Sender<RenderCommand>, msg: String) {
let rendermsg = RenderCommand::RenderStringToPane { str: msg, pane: RenderPane::CliOutput }; let rendermsg = RenderCommand::RenderStringToPane { str: msg, pane: RenderPane::CliOutput };
if let Err(e) = render_tx.send(rendermsg).await { if let Err(e) = render_tx.send(rendermsg).await {
@ -99,6 +112,11 @@ impl WatcherBuilder {
self self
} }
pub fn bootstrap(mut self, bootstrap: bool) -> Self {
self.bootstrap = bootstrap;
self
}
pub async fn log(render_tx: &mpsc::Sender<RenderCommand>, msg: String) { pub async fn log(render_tx: &mpsc::Sender<RenderCommand>, msg: String) {
let rendermsg = RenderCommand::RenderStringToPane { str: msg, pane: RenderPane::CliOutput }; let rendermsg = RenderCommand::RenderStringToPane { str: msg, pane: RenderPane::CliOutput };
let _ = render_tx.send(rendermsg).await; let _ = render_tx.send(rendermsg).await;
@ -122,7 +140,11 @@ impl WatcherBuilder {
.as_ref() .as_ref()
.and_then(|path| std::fs::read_to_string(path).ok()) .and_then(|path| std::fs::read_to_string(path).ok())
.and_then(|content| serde_json::from_str(&content).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 _ = Self::log(&render_tx, msg!(INFO, "Build Node"));
let parser_handle = tokio::spawn({ let parser_handle = tokio::spawn({
@ -148,7 +170,7 @@ impl WatcherBuilder {
let node_handle = tokio::spawn({ let node_handle = tokio::spawn({
async move { async move {
node.run_native().await; node.run().await;
} }
}); });