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
#[arg(short = 'f', long)]
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)]

View File

@ -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<String, u32> {
@ -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<core::Block>) -> Result<Blockchain, ValidationError> {
log!(INFO, "Starting Chain Build from Genesis");
let chain = Blockchain {
blocks,
balances: HashMap::new(),

View File

@ -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 {

View File

@ -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<watcher::ExecutorCommand>, 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) {

View File

@ -45,7 +45,6 @@ pub enum NodeCommand {
Exit,
}
impl NativeNode {
pub fn peer_addresses(&self) -> Vec<SocketAddr> {
@ -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<ExecutorCommand>,
addr: Option<SocketAddr>,
@ -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<SocketAddr>,
blocks: Option<Vec<core::Block>>,
exec_tx: mpsc::Sender<ExecutorCommand>,
@ -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;

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{
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<String>) {

View File

@ -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<ParserCommand>,
@ -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<ParserCommand>,
@ -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;
}

View File

@ -20,7 +20,8 @@ pub struct Watcher {
#[derive(Default)]
pub struct WatcherBuilder {
addr: Option<SocketAddr>,
seed_file: Option<String>
seed_file: Option<String>,
bootstrap: bool
}
impl Watcher {
@ -28,6 +29,18 @@ impl Watcher {
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) {
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<RenderCommand>, 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;
}
});