This commit is contained in:
victor 2025-09-08 21:18:42 +02:00
parent ffeb300e9e
commit 1ab99e475b
17 changed files with 396 additions and 48 deletions

195
node/Cargo.lock generated
View File

@ -331,6 +331,7 @@ dependencies = [
"sled",
"textwrap",
"thiserror 2.0.16",
"tinyhttp",
"tokio",
"tokio-tungstenite",
"uuid",
@ -396,6 +397,17 @@ dependencies = [
"shlex",
]
[[package]]
name = "cfb"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d38f2da7a0a2c4ccf0065be06397cc26a81f4e528be095826eee9d4adbb8c60f"
dependencies = [
"byteorder",
"fnv",
"uuid",
]
[[package]]
name = "cfg-if"
version = "0.1.10"
@ -598,6 +610,15 @@ dependencies = [
"cfg-if 1.0.3",
]
[[package]]
name = "crossbeam-channel"
version = "0.5.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2"
dependencies = [
"crossbeam-utils",
]
[[package]]
name = "crossbeam-epoch"
version = "0.9.18"
@ -818,6 +839,12 @@ dependencies = [
"litrs",
]
[[package]]
name = "dyn-clone"
version = "1.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555"
[[package]]
name = "ecdsa"
version = "0.16.9"
@ -910,6 +937,16 @@ dependencies = [
"toml",
]
[[package]]
name = "flate2"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d"
dependencies = [
"crc32fast",
"miniz_oxide",
]
[[package]]
name = "fluent"
version = "0.16.1"
@ -966,6 +1003,21 @@ version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
[[package]]
name = "foreign-types"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
dependencies = [
"foreign-types-shared",
]
[[package]]
name = "foreign-types-shared"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
[[package]]
name = "form_urlencoded"
version = "1.2.2"
@ -1463,6 +1515,15 @@ version = "2.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4c7245a08504955605670dbf141fceab975f15ca21570696aebe9d2e71576bd"
[[package]]
name = "infer"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb33622da908807a06f9513c19b3c1ad50fab3e4137d82a78107d502075aa199"
dependencies = [
"cfb",
]
[[package]]
name = "inout"
version = "0.1.4"
@ -1697,6 +1758,22 @@ dependencies = [
"windows-sys 0.52.0",
]
[[package]]
name = "mime"
version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
[[package]]
name = "mime_guess"
version = "2.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e"
dependencies = [
"mime",
"unicase",
]
[[package]]
name = "minimal-lexical"
version = "0.2.1"
@ -1797,6 +1874,16 @@ dependencies = [
"autocfg",
]
[[package]]
name = "num_cpus"
version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b"
dependencies = [
"hermit-abi",
"libc",
]
[[package]]
name = "object"
version = "0.36.7"
@ -1830,6 +1917,44 @@ version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381"
[[package]]
name = "openssl"
version = "0.10.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8"
dependencies = [
"bitflags 2.9.3",
"cfg-if 1.0.3",
"foreign-types",
"libc",
"once_cell",
"openssl-macros",
"openssl-sys",
]
[[package]]
name = "openssl-macros"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "openssl-sys"
version = "0.9.109"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571"
dependencies = [
"cc",
"libc",
"pkg-config",
"vcpkg",
]
[[package]]
name = "parking_lot"
version = "0.11.2"
@ -1956,6 +2081,12 @@ dependencies = [
"spki",
]
[[package]]
name = "pkg-config"
version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
[[package]]
name = "poly1305"
version = "0.8.0"
@ -2308,6 +2439,19 @@ version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
[[package]]
name = "rusty_pool"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ed36cdb20de66d89a17ea04b8883fc7a386f2cf877aaedca5005583ce4876ff"
dependencies = [
"crossbeam-channel",
"futures",
"futures-channel",
"futures-executor",
"num_cpus",
]
[[package]]
name = "ryu"
version = "1.0.20"
@ -2724,6 +2868,45 @@ dependencies = [
"syn",
]
[[package]]
name = "tinyhttp"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40da872cd88188b99336266db850a3a87037dc463b376db7a422236427e3a0b6"
dependencies = [
"tinyhttp-codegen",
"tinyhttp-internal",
]
[[package]]
name = "tinyhttp-codegen"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "020ea8639b093aa2a1f70cdcb07af1935ec1fcdcc36b3f7e1208751dbbf2470d"
dependencies = [
"quote",
"syn",
"tinyhttp-internal",
]
[[package]]
name = "tinyhttp-internal"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "58a51a6d7166b0083f7f9537a54cb749ce16ef73811bfd77452e4d4eab1c4389"
dependencies = [
"dyn-clone",
"flate2",
"infer",
"log",
"mime_guess",
"num_cpus",
"openssl",
"rusty_pool",
"thiserror 1.0.69",
"tokio",
]
[[package]]
name = "tinystr"
version = "0.8.1"
@ -2835,6 +3018,12 @@ dependencies = [
"tinystr",
]
[[package]]
name = "unicase"
version = "2.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539"
[[package]]
name = "unicode-ident"
version = "1.0.18"
@ -2940,6 +3129,12 @@ dependencies = [
"wasm-bindgen",
]
[[package]]
name = "vcpkg"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
[[package]]
name = "version_check"
version = "0.9.5"

View File

@ -32,3 +32,4 @@ ring = "0.17.14"
shared = { path = "../shared", features = ["node"] }
wallet = { path = "../wallet" }
cli-renderer = { path = "../cli-renderer" }
tinyhttp = { version = "0.5.0", features = ["async"] }

View File

@ -0,0 +1,22 @@
use std::net::TcpStream;
use tinyhttp;
use tokio::net::{TcpListener, TcpSocket};
#[derive(Error, Clone)]
enum HttpServerError {
#[error("Socket Error: {0}")]
SockerError(#[from] std::io::Error)
}
async fn start_server() {
let tcp_listner = TcpListener::bind("127.0.0.1:6080").await.unwrap();
let config = tinyhttp::prelude::Config::new();
let home_route = tinyhttp::prelude::Routes::new();
let server = tinyhttp::prelude::HttpListener::new(tcp_listner, config);
server.start();
}

View File

@ -167,4 +167,10 @@ pub struct CliArgs {
/// Enable debug mode (alternative syntax)
#[arg(short = 's', long = "seed", action = clap::ArgAction::SetTrue)]
pub seed: bool,
/// Run with temporary db
#[arg(short = 't', long = "seed", action = clap::ArgAction::SetTrue)]
pub temporary: bool,
}

View File

@ -1,7 +1,9 @@
use crate::args::*;
use shared::core::ChainData;
use vlogger::*;
use crate::executor::ExecutorCommand;
use crate::node::*;
use crate::log;
use cli_renderer::RenderCommand;
use clap::Parser;
@ -53,7 +55,17 @@ pub fn cli(input: &str) -> ExecutorCommand {
CliCommand::Transaction(tx) => {
ExecutorCommand::Node(NodeCommand::ProcessChainData(ChainData::Transaction(tx)))
}
CliCommand::Award { address, amount } => {ExecutorCommand::Node(NodeCommand::AwardCurrency{ address, amount })}
CliCommand::Award { address, amount } => {
let mut bytes = [0u8; 20];
if address.len() != 20 {
log(msg!(ERROR, "Invalid address length"))
} else if !address.is_ascii() {
log(msg!(ERROR, "Invalid address content"))
}
bytes.copy_from_slice(address.as_bytes());
ExecutorCommand::Node(NodeCommand::AwardCurrency{ address: bytes, amount }
)}
CliCommand::DebugShowId => ExecutorCommand::Node(NodeCommand::ShowId),
CliCommand::StartListner { addr } => {
ExecutorCommand::Node(NodeCommand::StartListner(addr.parse().unwrap()))

View File

@ -43,7 +43,7 @@ fn prefix(prefix: &[u8], key: &[u8]) -> Vec<u8> {
}
impl ChainDb {
pub fn new(path: Option<String>) -> Result<ChainDb, DatabaseError> {
pub fn new(path: Option<String>, db_temp: bool) -> Result<ChainDb, DatabaseError> {
let path = if path.is_some() {
&path.unwrap()
} else {
@ -52,6 +52,7 @@ impl ChainDb {
let config = sled::Config::new()
.cache_capacity(512 * 1024)
.segment_size(1024 * 1024)
.temporary(db_temp)
.path(&path);
match config.open() {
@ -176,7 +177,7 @@ impl ChainDb {
let mut chain_data = Vec::new();
for data_hash in &block.data {
let data_hash = prefix(&CHAIN_DATA_PREFIX, data_hash.as_bytes());
let data_hash = prefix(&CHAIN_DATA_PREFIX, data_hash);
if let Some(bin_data) = self.db.get(&data_hash)? {
let (data, _) = bincode::decode_from_slice::<ChainData, _>(&bin_data, BINCODE_CONFIG)?;
chain_data.push(data);
@ -211,14 +212,14 @@ impl ChainDb {
pub fn add_block(&self, block: &core::Block) -> Result<(), DatabaseError> {
let mut db_batch = Batch::default();
let bin_block = bincode::encode_to_vec(block, BINCODE_CONFIG)?;
db_batch.insert(prefix(&BLOCK_PREFIX, block.head().block_hash().as_bytes()), bin_block);
db_batch.insert(prefix(&BLOCK_PREFIX, block.head().block_hash()), bin_block);
db_batch.insert(
prefix(&HEIGHT_TO_HASH_PREFIX, &block.head().height.to_be_bytes()),
block.head().block_hash(),
);
for data in block.data() {
db_batch.insert(
prefix(&DATA_TO_BLOCK_PREFIX, data.as_bytes()),
prefix(&DATA_TO_BLOCK_PREFIX, data),
block.head().block_hash(),
);
}

View File

@ -11,6 +11,11 @@ pub mod node {
pub mod cli;
pub mod api {
pub mod server;
pub use server::*;
}
pub mod args;
pub mod error;

View File

@ -18,6 +18,7 @@ async fn main() -> Result<(), std::io::Error> {
.debug(args.debug)
.render(args.render)
.bootstrap(args.bootstrap)
.temporary(args.temporary)
.start()
.await;

View File

@ -1,6 +1,7 @@
use std::sync::Arc;
use std::time::UNIX_EPOCH;
use shared::core::Address;
use thiserror::*;
use shared::core;
@ -55,7 +56,7 @@ pub enum ValidationError {
#[allow(dead_code)]
impl Blockchain {
fn hash_transaction_pool(&self) -> Vec<String> {
fn hash_transaction_pool(&self) -> Vec<[u8; 32]> {
self
.mempool
.iter()
@ -63,17 +64,23 @@ impl Blockchain {
.collect()
}
pub fn award_currency(&self, address: String, amount: u64) -> Result<(), BlockchainError> {
Ok(self.db.add_balance(&address, amount)?)
pub fn award_currency(&self, address: Address, amount: u64) -> Result<(), BlockchainError> {
let previous_balance = self.db.get_balance(&address)?;
let new_balance = if previous_balance.is_some() {
previous_balance.unwrap() + amount
} else {
amount
};
Ok(self.db.set_balance(&address, new_balance)?)
}
pub fn create_block(&mut self) -> Result<Arc<core::Block>, BlockchainError> {
match self.blocks() {
Ok(blocks) => {
let previous_hash = if blocks.len() > 0 {
blocks.last().unwrap().head().block_hash()
<[u8; 32]>::try_from(blocks.last().unwrap().head().block_hash()).unwrap()
} else {
""
[0u8; 32]
};
let tx_hashes = self.hash_transaction_pool();
let merkle_root = Hasher::calculate_merkle_root(&tx_hashes);
@ -85,16 +92,16 @@ impl Blockchain {
let nonce = 0;
let mut new_head = core::BlockHeader {
previous_hash: previous_hash.to_string(),
previous_hash: <[u8; 32]>::from(previous_hash),
merkle_root,
timestamp,
nonce,
height: blocks.len() as u64 + 1,
block_hash: "".to_string(),
block_hash: [0u8; 32],
};
let mut block_hash = String::new();
while !block_hash.starts_with("0") {
let mut block_hash = [0u8; 32];
while !block_hash.starts_with(b"0") {
new_head.nonce += 1;
block_hash = Hasher::calculate_block_hash(&new_head)
}
@ -121,7 +128,7 @@ impl Blockchain {
};
if tx.value() > from_balance {
return Err(BlockchainError::InsufficientFunds(tx.from().to_string()))
return Err(BlockchainError::InsufficientFunds(hex::encode(from)))
}
let new_from_balance = from_balance - tx.value();
@ -130,7 +137,7 @@ impl Blockchain {
let changes = vec![(from, new_from_balance), (to, new_to_balance)];
Ok(self.db.set_balance_batch(changes)?)
} else {
Err(BlockchainError::Database(DatabaseError::AccountNotFound(from.to_string())))
Err(BlockchainError::Database(DatabaseError::AccountNotFound(hex::encode(from))))
}
}
@ -146,11 +153,11 @@ impl Blockchain {
}
impl Blockchain {
pub fn list_blocks(&self) -> Result<Vec<String>, BlockchainError> {
pub fn list_blocks(&self) -> Result<Vec<[u8; 32]>, BlockchainError> {
let mut ret = Vec::new();
let blocks = self.blocks()?;
for b in blocks.iter() {
ret.push(b.head.block_hash().to_string())
ret.push(<[u8; 32]>::try_from(b.head.block_hash()).unwrap())
}
Ok(ret)
}
@ -224,8 +231,8 @@ impl Blockchain {
Ok(())
}
pub fn build(path: Option<String>) -> Result<Blockchain, BlockchainError> {
let db = db::ChainDb::new(path).or_else(|e| Err(BlockchainError::Database(e)))?;
pub fn build(path: Option<String>, db_temp: bool) -> Result<Blockchain, BlockchainError> {
let db = db::ChainDb::new(path, db_temp).or_else(|e| Err(BlockchainError::Database(e)))?;
let mempool = db.recover_mempool()?;
let chain = Blockchain {

View File

@ -1,6 +1,6 @@
use crate::bus::{publish_system_event, publish_watcher_event, subscribe_system_event, SystemEvent};
use shared::core::{self, ChainData};
use shared::core::print_error_chain;
use shared::print_error_chain;
use crate::executor::ExecutorCommand;
use crate::log;
use crate::protocol::ProtocolMessage;
@ -76,7 +76,7 @@ pub enum NodeCommand {
ListBlocks,
ListPeers,
ShowId,
AwardCurrency { address: String, amount: u64 },
AwardCurrency { address: [u8; 20], amount: u64 },
ConnectToSeeds,
ConnectTcpPeer(String),
BootStrap,
@ -203,7 +203,7 @@ impl Node {
}
ProtocolMessage::BootstrapResponse { blocks } => {
log(msg!(DEBUG, "Received BootstrapResponse from seed"));
self.chain = Blockchain::build(blocks).unwrap();
self.chain = Blockchain::build(blocks, true).unwrap();
}
ProtocolMessage::Pong { peer_id } => {
log(msg!(DEBUG, "Received Pong from {peer_id}"));
@ -397,6 +397,7 @@ impl Node {
NodeCommand::RemovePeer { peer_id } => {
self.remove_tcp_peer(peer_id).await;
}
NodeCommand::ProcessMessage { peer_id, message } => {
self.process_message(peer_id, message).await;
}
@ -417,7 +418,7 @@ impl Node {
log(msg!(
INFO,
"Created Block with hash {}",
block.head().block_hash()
hex::encode(block.head().block_hash())
));
self.broadcast_block(&block).await;
}
@ -428,7 +429,7 @@ impl Node {
Err(e) => return print_error_chain(&e.into()),
};
let wat_cmd = WatcherCommand::SetMode(WatcherMode::Select {
content: blocks.into(),
content: blocks.iter().map(|h| hex::encode(h)).collect::<Vec<String>>().into(),
title: "Select Block to display".to_string(),
callback: Box::new(ExecutorCommand::Node(NodeCommand::DisplayBlockByKey("".to_string()))),
index: 0
@ -440,7 +441,7 @@ impl Node {
NodeCommand::ListBlocks => {
log(msg!(DEBUG, "Received DebugListBlocks command"));
match self.chain.list_blocks() {
Ok(s) => log(s.join("\n")),
Ok(s) => log(s.iter().map(|h| format!("{}\n", hex::encode(h))).collect::<Vec<String>>().join("\n")),
Err(e) => print_error_chain(&e.into()),
}
}
@ -471,6 +472,7 @@ impl Node {
))
.await;
};
let mut system_rx = subscribe_system_event();
publish_system_event(SystemEvent::NodeStarted);

View File

@ -4,7 +4,7 @@ use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::net;
use tokio::sync::mpsc;
use vlogger::*;
use shared::core::print_error_chain;
use shared::print_error_chain;
use thiserror::*;
use crate::log;

View File

@ -18,6 +18,7 @@ pub struct WatcherBuilder {
debug: bool,
seed: bool,
render: bool,
temporary: bool
}
impl WatcherBuilder {
@ -55,6 +56,11 @@ impl WatcherBuilder {
self
}
pub fn temporary(mut self, temporary: bool) -> Self {
self.temporary = temporary;
self
}
pub async fn start(mut self) -> Watcher {
let (exec_tx, exec_rx) = mpsc::channel::<ExecutorCommand>(100);
let mut sys_event = subscribe_system_event();
@ -70,7 +76,7 @@ impl WatcherBuilder {
self.addr = Some(crate::seeds_constants::SEED_NODES[0]);
}
let chain = node::Blockchain::build(None).unwrap();
let chain = node::Blockchain::build(None, self.temporary).unwrap();
let mut node = Node::new(self.addr.clone(), exec_tx.clone(), chain);
log(msg!(INFO, "Built Node"));

View File

@ -5,7 +5,7 @@ use crate::{
watcher::WatcherMode
};
use shared::core::print_error_chain;
use shared::print_error_chain;
use crossterm::event::{Event, EventStream, KeyCode, KeyEventKind, MouseButton, MouseEventKind};
use futures::StreamExt;
use memory_stats::memory_stats;

12
node_client/app.js Normal file
View File

@ -0,0 +1,12 @@
const connection = {
ws: [],
node_list: [],
}
function establishConnection() {
const ws = new WebSocket('ws://localhost:6000');
}
function updateTableStats() {
}

76
node_client/index.html Normal file
View File

@ -0,0 +1,76 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title></title>
<!-- <link href="css/style.css" rel="stylesheet"> -->
</head>
<body class="background">
<div class="main-container">
<h1>Node Stats</h1>
<div class="table-container">
<table style="box-sizing: border-box; max-height: 100%; width: 100%; table-layout: fixed; border-collapse: collapse;" id='stat-table' >
<thead>
<tr style="border-bottom: 1px solid black;">
<th>stat 1</th>
<th>stat 2</th>
<th>stat 3</th>
<th>stat 4</th>
<th>stat 5</th>
</tr>
</thead>
<tbody style="box-sizing: border-box; max-height: 100%; overflow-y: scroll;"id='stat-table-body'>
</tbody>
</table>
</div>
</div>
<script src="/app.js" ></script>
<script>
const table = document.getElementById('stat-table-body');
for (var i = 0; i < 30; i++)
{
const new_row = document.createElement('tr');
let row_content = '';
for (var j = 0; j < 5; j++) {
row_content += `<td style="text-align: right; padding: 0 4px ; border-top: 1px solid black;">${i + j}</td>`
}
new_row.innerHTML = row_content;
table.appendChild(new_row);
}
</script>
</body>
<style>
body {
margin: 0;
padding: 0;
}
.main-container {
padding: 6px;
display: flex;
align-content: center;
flex-direction: column;
height: 100%;
width: 100%;
box-sizing: border-box;
}
.table-container {
padding: 6px;
place-self: center;
border: 2px solid #000000;
width: 50%;
height: 50%;
box-sizing: border-box;
}
.background {
background-color: #808080;
width: 100vw;
height: 100vh;
max-height: 100vh;
max-width: 100vw;
box-sizing: border-box;
}
</style>
</html>

View File

@ -2,10 +2,10 @@
Clone, Debug, serde::Deserialize, serde::Serialize, Default, bincode::Decode, bincode::Encode,
)]
pub struct BlockHeader {
pub previous_hash: String,
pub previous_hash: [u8; 32],
pub timestamp: u64,
pub merkle_root: String,
pub block_hash: String,
pub merkle_root: [u8; 32],
pub block_hash: [u8; 32],
pub nonce: u32,
pub height: u64,
}
@ -15,11 +15,11 @@ pub struct BlockHeader {
)]
pub struct Block {
pub head: BlockHeader,
pub data: Vec<String>,
pub data: Vec<[u8; 32]>,
}
impl BlockHeader {
pub fn previous_hash(&self) -> &str {
pub fn previous_hash(&self) -> &[u8] {
&self.previous_hash
}
pub fn timestamp(&self) -> u64 {
@ -28,22 +28,22 @@ impl BlockHeader {
pub fn nonce(&self) -> u32 {
self.nonce
}
pub fn merkle_root(&self) -> &str {
pub fn merkle_root(&self) -> &[u8] {
&self.merkle_root
}
pub fn block_hash(&self) -> &str {
pub fn block_hash(&self) -> &[u8] {
&self.block_hash
}
}
impl Block {
pub fn new(head: BlockHeader, data: Vec<String>) -> Self {
pub fn new(head: BlockHeader, data: Vec<[u8; 32]>) -> Self {
Self { head, data }
}
pub fn head(&self) -> &BlockHeader {
&self.head
}
pub fn data(&self) -> &[String] {
pub fn data(&self) -> &[[u8; 32]] {
&self.data
}
}

View File

@ -21,7 +21,7 @@ impl Hasher {
res.into()
}
pub fn calculate_next_level(level: &[String]) -> Vec<String> {
pub fn calculate_next_level(level: &[[u8; 32]]) -> Vec<[u8; 32]> {
let mut next_level = Vec::new();
for chunk in level.chunks(2) {
@ -35,9 +35,9 @@ impl Hasher {
next_level
}
pub fn calculate_merkle_root(tx_hashes: &[String]) -> String {
pub fn calculate_merkle_root(tx_hashes: &[[u8; 32]]) -> [u8; 32] {
if tx_hashes.is_empty() {
return Self::hash_data("");
return Self::hash_data(b"");
}
if tx_hashes.len() == 1 {
@ -53,18 +53,20 @@ impl Hasher {
return current_level[0].clone();
}
fn hash_pair(left: &str, right: &str) -> String {
let combined = format!("{}{}", left, right);
fn hash_pair(left: &[u8], right: &[u8]) -> [u8; 32] {
let mut combined = Vec::with_capacity(left.len() + right.len());
combined.copy_from_slice(left);
combined.copy_from_slice(right);
Self::hash_data(&combined)
}
fn hash_data(data: &str) -> String {
fn hash_data(data: &[u8]) -> [u8; 32] {
let mut hasher = Sha256::new();
hasher.update(data.as_bytes());
hex::encode(hasher.finalize())
hasher.update(data);
hasher.finalize().into()
}
pub fn calculate_block_hash(head: &BlockHeader) -> String {
pub fn calculate_block_hash(head: &BlockHeader) -> [u8; 32] {
let mut hasher = sha2::Sha256::new();
hasher.update(head.nonce().to_be_bytes());
@ -73,6 +75,6 @@ impl Hasher {
hasher.update(head.merkle_root());
let res = hasher.finalize();
hex::encode(res)
res.into()
}
}