bless
This commit is contained in:
parent
4b6801644b
commit
c2f189ccb9
13
Cargo.lock
generated
13
Cargo.lock
generated
@ -144,6 +144,7 @@ dependencies = [
|
||||
"clap",
|
||||
"crossterm 0.29.0",
|
||||
"hex",
|
||||
"once_cell",
|
||||
"ratatui",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@ -260,6 +261,15 @@ version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
|
||||
|
||||
[[package]]
|
||||
name = "colored"
|
||||
version = "3.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fde0e0ec90c9dfb3b4b1a0891a7dcd0e2bffde2f7efed5fe7c9bb00e5bfb915e"
|
||||
dependencies = [
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "compact_str"
|
||||
version = "0.8.1"
|
||||
@ -1500,6 +1510,9 @@ checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||
[[package]]
|
||||
name = "vlogger"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"colored",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "warp"
|
||||
|
||||
@ -20,3 +20,4 @@ web-sys = { version = "0.3.77", features = ["WebSocket"] }
|
||||
vlogger = { path = "./lib/logger-rs" }
|
||||
ratatui = "0.29.0"
|
||||
crossterm = "0.29.0"
|
||||
once_cell = "1.21.3"
|
||||
|
||||
85
lib/logger-rs/Cargo.lock
generated
85
lib/logger-rs/Cargo.lock
generated
@ -2,6 +2,91 @@
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "colored"
|
||||
version = "3.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fde0e0ec90c9dfb3b4b1a0891a7dcd0e2bffde2f7efed5fe7c9bb00e5bfb915e"
|
||||
dependencies = [
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vlogger"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"colored",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.59.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_i686_gnullvm",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_gnullvm",
|
||||
"windows_x86_64_msvc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||
|
||||
@ -4,3 +4,4 @@ version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
colored = "3.0.0"
|
||||
|
||||
@ -14,22 +14,6 @@ pub const LOG_LEVEL: [&str; 5] = [
|
||||
"FATAL",
|
||||
];
|
||||
|
||||
pub fn colored(text: &str, color: &str) -> String {
|
||||
// For terminals: use ANSI escape codes
|
||||
let ansi_code = match color {
|
||||
"black" => "30",
|
||||
"red" => "31",
|
||||
"green" => "32",
|
||||
"yellow" => "33",
|
||||
"blue" => "34",
|
||||
"purple" => "35",
|
||||
"cyan" => "36",
|
||||
"white" => "37",
|
||||
_ => "0", // default no color
|
||||
};
|
||||
format!("\x1b[{ansi_code}m{text}\x1b[0m")
|
||||
}
|
||||
|
||||
pub fn current_timestamp() -> String {
|
||||
let now = SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
@ -62,16 +46,17 @@ macro_rules! msg {
|
||||
match $level {
|
||||
$crate::INFO => {
|
||||
format!(
|
||||
"[{}] {} | {}\n",
|
||||
$crate::colored($crate::LOG_LEVEL[$level], "green"),
|
||||
"[{}] {} | {}\n",
|
||||
//$crate::colored($crate::LOG_LEVEL[$level], "green"),
|
||||
$crate::LOG_LEVEL[$level].to_string(),
|
||||
$crate::current_timestamp(),
|
||||
formatted_msg
|
||||
)
|
||||
},
|
||||
$crate::DEBUG => {
|
||||
format!(
|
||||
"[{}] [{}:{}] {} | {}\n",
|
||||
$crate::LOG_LEVEL[$level],
|
||||
"[{}]\t[{}:{}] {} | {}\n",
|
||||
$crate::LOG_LEVEL[$level].to_string(),
|
||||
file!(),
|
||||
line!(),
|
||||
$crate::current_timestamp(),
|
||||
@ -81,7 +66,7 @@ macro_rules! msg {
|
||||
$crate::WARNING => {
|
||||
format!(
|
||||
"[{}] {} | {}\n",
|
||||
$crate::colored($crate::LOG_LEVEL[$level], "yellow"),
|
||||
$crate::LOG_LEVEL[$level].to_string(),
|
||||
$crate::current_timestamp(),
|
||||
formatted_msg
|
||||
)
|
||||
@ -89,7 +74,7 @@ macro_rules! msg {
|
||||
$crate::ERROR => {
|
||||
format!(
|
||||
"[{}] {} | {}\n",
|
||||
$crate::colored($crate::LOG_LEVEL[$level], "red"),
|
||||
$crate::LOG_LEVEL[$level].to_string(),
|
||||
$crate::current_timestamp(),
|
||||
formatted_msg
|
||||
)
|
||||
@ -97,7 +82,7 @@ macro_rules! msg {
|
||||
$crate::FATAL => {
|
||||
format!(
|
||||
"[{}] [{}:{}] {} | {}\n",
|
||||
$crate::colored($crate::LOG_LEVEL[$level], "red"),
|
||||
$crate::LOG_LEVEL[$level].to_string(),
|
||||
file!(),
|
||||
line!(),
|
||||
$crate::current_timestamp(),
|
||||
@ -154,14 +139,6 @@ mod tests {
|
||||
assert!(error_msg.contains("Test error: 42"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_colored() {
|
||||
let red_text = colored("error", "red");
|
||||
assert!(red_text.contains("\x1b[31m"));
|
||||
assert!(red_text.contains("error"));
|
||||
assert!(red_text.contains("\x1b[0m"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_timestamp() {
|
||||
let ts = current_timestamp();
|
||||
|
||||
1
lib/logger-rs/target/.rustc_info.json
Normal file
1
lib/logger-rs/target/.rustc_info.json
Normal file
@ -0,0 +1 @@
|
||||
{"rustc_fingerprint":9331962960305057120,"outputs":{"7971740275564407648":{"success":true,"status":"","code":0,"stdout":"___\nlib___.rlib\nlib___.so\nlib___.so\nlib___.a\nlib___.so\n/sgoinfre/vvobis/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu\noff\npacked\nunpacked\n___\ndebug_assertions\nfmt_debug=\"full\"\noverflow_checks\npanic=\"unwind\"\nproc_macro\nrelocation_model=\"pic\"\ntarget_abi=\"\"\ntarget_arch=\"x86_64\"\ntarget_endian=\"little\"\ntarget_env=\"gnu\"\ntarget_family=\"unix\"\ntarget_feature=\"fxsr\"\ntarget_feature=\"sse\"\ntarget_feature=\"sse2\"\ntarget_feature=\"x87\"\ntarget_has_atomic\ntarget_has_atomic=\"16\"\ntarget_has_atomic=\"32\"\ntarget_has_atomic=\"64\"\ntarget_has_atomic=\"8\"\ntarget_has_atomic=\"ptr\"\ntarget_has_atomic_equal_alignment=\"16\"\ntarget_has_atomic_equal_alignment=\"32\"\ntarget_has_atomic_equal_alignment=\"64\"\ntarget_has_atomic_equal_alignment=\"8\"\ntarget_has_atomic_equal_alignment=\"ptr\"\ntarget_has_atomic_load_store\ntarget_has_atomic_load_store=\"16\"\ntarget_has_atomic_load_store=\"32\"\ntarget_has_atomic_load_store=\"64\"\ntarget_has_atomic_load_store=\"8\"\ntarget_has_atomic_load_store=\"ptr\"\ntarget_os=\"linux\"\ntarget_pointer_width=\"64\"\ntarget_thread_local\ntarget_vendor=\"unknown\"\nub_checks\nunix\n","stderr":""},"11857020428658561806":{"success":true,"status":"","code":0,"stdout":"___\nlib___.rlib\nlib___.so\nlib___.so\nlib___.a\nlib___.so\n/sgoinfre/vvobis/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu\noff\npacked\nunpacked\n___\ndebug_assertions\nfmt_debug=\"full\"\noverflow_checks\npanic=\"unwind\"\nproc_macro\nrelocation_model=\"pic\"\ntarget_abi=\"\"\ntarget_arch=\"x86_64\"\ntarget_endian=\"little\"\ntarget_env=\"gnu\"\ntarget_family=\"unix\"\ntarget_feature=\"fxsr\"\ntarget_feature=\"sse\"\ntarget_feature=\"sse2\"\ntarget_feature=\"x87\"\ntarget_has_atomic\ntarget_has_atomic=\"16\"\ntarget_has_atomic=\"32\"\ntarget_has_atomic=\"64\"\ntarget_has_atomic=\"8\"\ntarget_has_atomic=\"ptr\"\ntarget_has_atomic_equal_alignment=\"16\"\ntarget_has_atomic_equal_alignment=\"32\"\ntarget_has_atomic_equal_alignment=\"64\"\ntarget_has_atomic_equal_alignment=\"8\"\ntarget_has_atomic_equal_alignment=\"ptr\"\ntarget_has_atomic_load_store\ntarget_has_atomic_load_store=\"16\"\ntarget_has_atomic_load_store=\"32\"\ntarget_has_atomic_load_store=\"64\"\ntarget_has_atomic_load_store=\"8\"\ntarget_has_atomic_load_store=\"ptr\"\ntarget_os=\"linux\"\ntarget_pointer_width=\"64\"\ntarget_thread_local\ntarget_vendor=\"unknown\"\nub_checks\nunix\n","stderr":""},"17747080675513052775":{"success":true,"status":"","code":0,"stdout":"rustc 1.87.0-nightly (1aeb99d24 2025-03-19)\nbinary: rustc\ncommit-hash: 1aeb99d248e1b0069110cb03c6f1dcc7b36fd7f3\ncommit-date: 2025-03-19\nhost: x86_64-unknown-linux-gnu\nrelease: 1.87.0-nightly\nLLVM version: 20.1.0\n","stderr":""}},"successes":{}}
|
||||
3
lib/logger-rs/target/CACHEDIR.TAG
Normal file
3
lib/logger-rs/target/CACHEDIR.TAG
Normal file
@ -0,0 +1,3 @@
|
||||
Signature: 8a477f597d28d172789f06886806bc55
|
||||
# This file is a cache directory tag created by cargo.
|
||||
# For information about cache directory tags see https://bford.info/cachedir/
|
||||
0
lib/logger-rs/target/debug/.cargo-lock
Normal file
0
lib/logger-rs/target/debug/.cargo-lock
Normal file
Binary file not shown.
@ -0,0 +1 @@
|
||||
This file has an mtime of when this was started.
|
||||
@ -0,0 +1 @@
|
||||
2cdcc8159c269916
|
||||
@ -0,0 +1 @@
|
||||
{"rustc":9200240233716061564,"features":"[]","declared_features":"[\"no-color\"]","target":10635017557502881088,"profile":15657897354478470176,"path":11251442337508459999,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/colored-5b26b8bcd167138a/dep-lib-colored","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0}
|
||||
Binary file not shown.
@ -0,0 +1 @@
|
||||
This file has an mtime of when this was started.
|
||||
@ -0,0 +1 @@
|
||||
b7d5ee472865d234
|
||||
@ -0,0 +1 @@
|
||||
{"rustc":9200240233716061564,"features":"[]","declared_features":"[\"no-color\"]","target":10635017557502881088,"profile":2241668132362809309,"path":11251442337508459999,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/colored-be62070d26ff5634/dep-lib-colored","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0}
|
||||
Binary file not shown.
@ -0,0 +1 @@
|
||||
This file has an mtime of when this was started.
|
||||
@ -0,0 +1 @@
|
||||
12fd561ccccbf38d
|
||||
@ -0,0 +1 @@
|
||||
{"rustc":9200240233716061564,"features":"[]","declared_features":"[]","target":3130845551982539986,"profile":8731458305071235362,"path":10763286916239946207,"deps":[[9114801806035203750,"colored",false,1628375192093383724]],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/vlogger-5e31d9758c815091/dep-lib-vlogger","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0}
|
||||
Binary file not shown.
@ -0,0 +1 @@
|
||||
This file has an mtime of when this was started.
|
||||
@ -0,0 +1 @@
|
||||
aeff26b79a20f245
|
||||
@ -0,0 +1 @@
|
||||
{"rustc":9200240233716061564,"features":"[]","declared_features":"[]","target":3130845551982539986,"profile":17672942494452627365,"path":10763286916239946207,"deps":[[9114801806035203750,"colored",false,3806215858761422263]],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/vlogger-dada301cb6b4723c/dep-lib-vlogger","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0}
|
||||
Binary file not shown.
@ -0,0 +1 @@
|
||||
This file has an mtime of when this was started.
|
||||
@ -0,0 +1 @@
|
||||
af88079a39808c51
|
||||
@ -0,0 +1 @@
|
||||
{"rustc":9200240233716061564,"features":"[]","declared_features":"[]","target":3130845551982539986,"profile":3316208278650011218,"path":10763286916239946207,"deps":[[9114801806035203750,"colored",false,3806215858761422263]],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/vlogger-ee9eba351348c096/dep-test-lib-vlogger","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0}
|
||||
12
lib/logger-rs/target/debug/deps/colored-5b26b8bcd167138a.d
Normal file
12
lib/logger-rs/target/debug/deps/colored-5b26b8bcd167138a.d
Normal file
@ -0,0 +1,12 @@
|
||||
/sgoinfre/vvobis/git/blockchain/lib/logger-rs/target/debug/deps/libcolored-5b26b8bcd167138a.rmeta: /sgoinfre/vvobis/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/colored-3.0.0/src/lib.rs /sgoinfre/vvobis/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/colored-3.0.0/src/color.rs /sgoinfre/vvobis/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/colored-3.0.0/src/control.rs /sgoinfre/vvobis/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/colored-3.0.0/src/error.rs /sgoinfre/vvobis/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/colored-3.0.0/src/style.rs /sgoinfre/vvobis/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/colored-3.0.0/src/customcolors.rs
|
||||
|
||||
/sgoinfre/vvobis/git/blockchain/lib/logger-rs/target/debug/deps/libcolored-5b26b8bcd167138a.rlib: /sgoinfre/vvobis/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/colored-3.0.0/src/lib.rs /sgoinfre/vvobis/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/colored-3.0.0/src/color.rs /sgoinfre/vvobis/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/colored-3.0.0/src/control.rs /sgoinfre/vvobis/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/colored-3.0.0/src/error.rs /sgoinfre/vvobis/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/colored-3.0.0/src/style.rs /sgoinfre/vvobis/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/colored-3.0.0/src/customcolors.rs
|
||||
|
||||
/sgoinfre/vvobis/git/blockchain/lib/logger-rs/target/debug/deps/colored-5b26b8bcd167138a.d: /sgoinfre/vvobis/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/colored-3.0.0/src/lib.rs /sgoinfre/vvobis/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/colored-3.0.0/src/color.rs /sgoinfre/vvobis/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/colored-3.0.0/src/control.rs /sgoinfre/vvobis/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/colored-3.0.0/src/error.rs /sgoinfre/vvobis/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/colored-3.0.0/src/style.rs /sgoinfre/vvobis/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/colored-3.0.0/src/customcolors.rs
|
||||
|
||||
/sgoinfre/vvobis/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/colored-3.0.0/src/lib.rs:
|
||||
/sgoinfre/vvobis/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/colored-3.0.0/src/color.rs:
|
||||
/sgoinfre/vvobis/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/colored-3.0.0/src/control.rs:
|
||||
/sgoinfre/vvobis/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/colored-3.0.0/src/error.rs:
|
||||
/sgoinfre/vvobis/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/colored-3.0.0/src/style.rs:
|
||||
/sgoinfre/vvobis/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/colored-3.0.0/src/customcolors.rs:
|
||||
10
lib/logger-rs/target/debug/deps/colored-be62070d26ff5634.d
Normal file
10
lib/logger-rs/target/debug/deps/colored-be62070d26ff5634.d
Normal file
@ -0,0 +1,10 @@
|
||||
/sgoinfre/vvobis/git/blockchain/lib/logger-rs/target/debug/deps/libcolored-be62070d26ff5634.rmeta: /sgoinfre/vvobis/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/colored-3.0.0/src/lib.rs /sgoinfre/vvobis/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/colored-3.0.0/src/color.rs /sgoinfre/vvobis/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/colored-3.0.0/src/control.rs /sgoinfre/vvobis/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/colored-3.0.0/src/error.rs /sgoinfre/vvobis/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/colored-3.0.0/src/style.rs /sgoinfre/vvobis/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/colored-3.0.0/src/customcolors.rs
|
||||
|
||||
/sgoinfre/vvobis/git/blockchain/lib/logger-rs/target/debug/deps/colored-be62070d26ff5634.d: /sgoinfre/vvobis/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/colored-3.0.0/src/lib.rs /sgoinfre/vvobis/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/colored-3.0.0/src/color.rs /sgoinfre/vvobis/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/colored-3.0.0/src/control.rs /sgoinfre/vvobis/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/colored-3.0.0/src/error.rs /sgoinfre/vvobis/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/colored-3.0.0/src/style.rs /sgoinfre/vvobis/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/colored-3.0.0/src/customcolors.rs
|
||||
|
||||
/sgoinfre/vvobis/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/colored-3.0.0/src/lib.rs:
|
||||
/sgoinfre/vvobis/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/colored-3.0.0/src/color.rs:
|
||||
/sgoinfre/vvobis/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/colored-3.0.0/src/control.rs:
|
||||
/sgoinfre/vvobis/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/colored-3.0.0/src/error.rs:
|
||||
/sgoinfre/vvobis/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/colored-3.0.0/src/style.rs:
|
||||
/sgoinfre/vvobis/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/colored-3.0.0/src/customcolors.rs:
|
||||
BIN
lib/logger-rs/target/debug/deps/libcolored-5b26b8bcd167138a.rlib
Normal file
BIN
lib/logger-rs/target/debug/deps/libcolored-5b26b8bcd167138a.rlib
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
lib/logger-rs/target/debug/deps/libvlogger-5e31d9758c815091.rlib
Normal file
BIN
lib/logger-rs/target/debug/deps/libvlogger-5e31d9758c815091.rlib
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,7 @@
|
||||
/sgoinfre/vvobis/git/blockchain/lib/logger-rs/target/debug/deps/libvlogger-5e31d9758c815091.rmeta: src/lib.rs
|
||||
|
||||
/sgoinfre/vvobis/git/blockchain/lib/logger-rs/target/debug/deps/libvlogger-5e31d9758c815091.rlib: src/lib.rs
|
||||
|
||||
/sgoinfre/vvobis/git/blockchain/lib/logger-rs/target/debug/deps/vlogger-5e31d9758c815091.d: src/lib.rs
|
||||
|
||||
src/lib.rs:
|
||||
@ -0,0 +1,5 @@
|
||||
/sgoinfre/vvobis/git/blockchain/lib/logger-rs/target/debug/deps/libvlogger-dada301cb6b4723c.rmeta: src/lib.rs
|
||||
|
||||
/sgoinfre/vvobis/git/blockchain/lib/logger-rs/target/debug/deps/vlogger-dada301cb6b4723c.d: src/lib.rs
|
||||
|
||||
src/lib.rs:
|
||||
@ -0,0 +1,5 @@
|
||||
/sgoinfre/vvobis/git/blockchain/lib/logger-rs/target/debug/deps/libvlogger-ee9eba351348c096.rmeta: src/lib.rs
|
||||
|
||||
/sgoinfre/vvobis/git/blockchain/lib/logger-rs/target/debug/deps/vlogger-ee9eba351348c096.d: src/lib.rs
|
||||
|
||||
src/lib.rs:
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
1
lib/logger-rs/target/debug/libvlogger.d
Normal file
1
lib/logger-rs/target/debug/libvlogger.d
Normal file
@ -0,0 +1 @@
|
||||
/sgoinfre/vvobis/git/blockchain/lib/logger-rs/target/debug/libvlogger.rlib: /sgoinfre/vvobis/git/blockchain/lib/logger-rs/src/lib.rs
|
||||
BIN
lib/logger-rs/target/debug/libvlogger.rlib
Normal file
BIN
lib/logger-rs/target/debug/libvlogger.rlib
Normal file
Binary file not shown.
111
src/args.rs
111
src/args.rs
@ -2,10 +2,115 @@ use std::net::SocketAddr;
|
||||
|
||||
use clap::{Parser, Subcommand};
|
||||
use crate::core;
|
||||
use crate::watcher::RenderPane;
|
||||
|
||||
use clap::*;
|
||||
|
||||
#[derive(Parser)]
|
||||
pub struct Cli {
|
||||
#[command(subcommand)]
|
||||
pub command: CliCommand
|
||||
}
|
||||
|
||||
|
||||
#[derive(Subcommand)]
|
||||
pub enum CliCommand{
|
||||
#[command(name = "node")]
|
||||
Node {
|
||||
#[command(subcommand)]
|
||||
command: CliNodeCommand
|
||||
},
|
||||
|
||||
#[command(name = "clear", aliases = ["c"])]
|
||||
Clear{
|
||||
pane: RenderPane
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Subcommand)]
|
||||
pub enum CliPeerCommand {
|
||||
/// Connect To Peer With IpAddr
|
||||
#[command(name = "connect", aliases = ["c", "con"])]
|
||||
Connect{addr: String},
|
||||
|
||||
/// Remove Peer Connection
|
||||
#[command(name = "remove", aliases = ["rm"])]
|
||||
Remove{id: String},
|
||||
|
||||
/// List Connected Peers
|
||||
#[command(name = "list", aliases = ["ls", "l"])]
|
||||
List,
|
||||
|
||||
}
|
||||
|
||||
#[derive(Subcommand)]
|
||||
pub enum CliSeedCommand {
|
||||
/// Connect to Seed nodes
|
||||
#[command(name = "connect", aliases = ["c", "con"])]
|
||||
Connect
|
||||
}
|
||||
|
||||
#[derive(Subcommand)]
|
||||
pub enum CliBlockCommand {
|
||||
/// List Blocks in Chain
|
||||
#[command(name = "list", aliases = ["ls", "l"])]
|
||||
List,
|
||||
|
||||
/// Create and Broadcast new Block
|
||||
#[command(name = "create", aliases = ["c", "new"])]
|
||||
Create,
|
||||
|
||||
/// Export Blocks to file
|
||||
#[command(name = "dump", aliases = ["export"])]
|
||||
Dump {
|
||||
/// Output file
|
||||
#[arg(short, long)]
|
||||
output: String
|
||||
}
|
||||
}
|
||||
#[derive(Subcommand)]
|
||||
#[command(name = "node")]
|
||||
#[command(about = "A blockchain node CLI tool")]
|
||||
#[command(version = "1.0")]
|
||||
#[command(long_about = "A comprehensive CLI tool for managing blockchain nodes, peers, and transactions")]
|
||||
pub enum CliNodeCommand {
|
||||
/// Peer related Cmd
|
||||
#[command(name = "peer")]
|
||||
Peer {
|
||||
#[command(subcommand)]
|
||||
peer_cmd: CliPeerCommand
|
||||
},
|
||||
|
||||
/// Block related Cmd
|
||||
#[command(name = "block")]
|
||||
Block {
|
||||
#[command(subcommand)]
|
||||
block_cmd: CliBlockCommand
|
||||
},
|
||||
|
||||
/// Make a Transaction
|
||||
#[command(name = "tx")]
|
||||
Transaction(core::Tx),
|
||||
|
||||
/// Start new TcpListner on Addr
|
||||
#[command(name = "listen")]
|
||||
StartListner{addr: String},
|
||||
|
||||
/// Display Node id
|
||||
#[command(name = "id")]
|
||||
DebugShowId,
|
||||
|
||||
/// Connect to Seed Nodes
|
||||
#[command(name = "seed")]
|
||||
Seeds {
|
||||
#[command(subcommand)]
|
||||
seed_cmd: CliSeedCommand
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
#[command(version, about, long_about = None)]
|
||||
pub struct Args {
|
||||
pub struct CliArgs {
|
||||
/// Provide address on which node will listen
|
||||
#[arg(short = 'a', long)]
|
||||
pub addr: Option<SocketAddr>,
|
||||
@ -26,6 +131,6 @@ pub enum TxCmd {
|
||||
Add(core::Tx)
|
||||
}
|
||||
|
||||
pub fn get_args() -> Args {
|
||||
Args::parse()
|
||||
pub fn get_args() -> CliArgs {
|
||||
CliArgs::parse()
|
||||
}
|
||||
|
||||
50
src/cli.rs
Normal file
50
src/cli.rs
Normal file
@ -0,0 +1,50 @@
|
||||
use crate::args::*;
|
||||
use crate::native_node::node::*;
|
||||
use clap::Parser;
|
||||
use crate::watcher::ExecutorCommand;
|
||||
|
||||
pub fn handle_peer_command(cmd: CliPeerCommand) -> NodeCommand {
|
||||
match cmd {
|
||||
CliPeerCommand::List => NodeCommand::ListPeers,
|
||||
CliPeerCommand::Remove { id } => NodeCommand::RemovePeer{ peer_id: id.parse::<uuid::Uuid>().unwrap() },
|
||||
CliPeerCommand::Connect { addr } => NodeCommand::ConnectToPeer(addr),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_block_command(cmd: CliBlockCommand) -> NodeCommand {
|
||||
match cmd {
|
||||
CliBlockCommand::List => NodeCommand::ListBlocks,
|
||||
CliBlockCommand::Dump { output } => NodeCommand::DumpBlocks(output),
|
||||
CliBlockCommand::Create => NodeCommand::CreateBlock,
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_seed_command(cmd: CliSeedCommand) -> NodeCommand {
|
||||
match cmd {
|
||||
CliSeedCommand::Connect => NodeCommand::ConnectToSeeds
|
||||
}
|
||||
}
|
||||
|
||||
fn node_cli(cmd: CliNodeCommand) -> ExecutorCommand {
|
||||
match cmd {
|
||||
CliNodeCommand::Peer { peer_cmd } => ExecutorCommand::Node(handle_peer_command(peer_cmd)),
|
||||
CliNodeCommand::Block { block_cmd } => ExecutorCommand::Node(handle_block_command(block_cmd)),
|
||||
CliNodeCommand::Transaction(tx)=> ExecutorCommand::Node(NodeCommand::Transaction{tx}),
|
||||
CliNodeCommand::DebugShowId => ExecutorCommand::Node(NodeCommand::ShowId),
|
||||
CliNodeCommand::StartListner { addr } => {
|
||||
ExecutorCommand::Node(NodeCommand::StartListner(addr.parse().unwrap()))
|
||||
},
|
||||
CliNodeCommand::Seeds { seed_cmd } => ExecutorCommand::Node(handle_seed_command(seed_cmd)),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn cli(input: &[&str]) -> ExecutorCommand {
|
||||
match Cli::try_parse_from(input) {
|
||||
Ok(cmd) => match cmd.command {
|
||||
CliCommand::Node{ command } => node_cli(command),
|
||||
CliCommand::Clear { pane } => ExecutorCommand::Clear(pane),
|
||||
}
|
||||
Err(e) => ExecutorCommand::InvalidCommand(format!("{e}"))
|
||||
}
|
||||
}
|
||||
@ -9,248 +9,258 @@ use std::collections::HashMap;
|
||||
use std::io::Write;
|
||||
use std::time::UNIX_EPOCH;
|
||||
|
||||
const BLOCKCHAIN_ID: &str = "victors-first-blockchain";
|
||||
|
||||
pub type Account = String;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ValidationError {
|
||||
InvalidBlockHash,
|
||||
InvalidPreviousBlockHash
|
||||
InvalidBlockHash,
|
||||
InvalidPreviousBlockHash
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct Blockchain {
|
||||
balances: std::collections::HashMap<Account, u32>,
|
||||
blocks: Vec<core::Block>,
|
||||
tx_mempool: Vec<core::Tx>,
|
||||
id: String,
|
||||
balances: std::collections::HashMap<Account, u32>,
|
||||
blocks: Vec<core::Block>,
|
||||
tx_mempool: Vec<core::Tx>,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl Blockchain {
|
||||
pub fn open_account(&mut self, tx: core::Tx) -> Result<(), BlockchainError> {
|
||||
if !tx.is_new_account() {
|
||||
Err(BlockchainError::InvalidAccountCreation)
|
||||
} else {
|
||||
self.add(tx)
|
||||
}
|
||||
pub fn open_account(&mut self, tx: core::Tx) -> Result<(), BlockchainError> {
|
||||
if !tx.is_new_account() {
|
||||
Err(BlockchainError::InvalidAccountCreation)
|
||||
} else {
|
||||
self.add(tx)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add(&mut self, tx: core::Tx) -> Result<(), BlockchainError> {
|
||||
self.apply(&tx)?;
|
||||
self.tx_mempool.push(tx);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn hash_transaction(tx: &core::Tx) -> String {
|
||||
let mut hasher = Sha256::new();
|
||||
hasher.update(tx.to());
|
||||
hasher.update(tx.from());
|
||||
hasher.update(tx.value().to_be_bytes());
|
||||
hasher.update(tx.data());
|
||||
|
||||
let res = hasher.finalize();
|
||||
hex::encode(res)
|
||||
}
|
||||
|
||||
pub fn calculate_next_level(level: &[String]) -> Vec<String> {
|
||||
let mut next_level = Vec::new();
|
||||
|
||||
for chunk in level.chunks(2) {
|
||||
let combined_hash = if chunk.len() == 2 {
|
||||
Self::hash_pair(&chunk[0], &chunk[1])
|
||||
} else {
|
||||
Self::hash_pair(&chunk[0], &chunk[0])
|
||||
};
|
||||
next_level.push(combined_hash);
|
||||
}
|
||||
next_level
|
||||
}
|
||||
|
||||
pub fn calculate_merkle_root(tx: &[core::Tx]) -> String {
|
||||
let tx_hashes: Vec<String> = tx
|
||||
.iter()
|
||||
.map(|tx| Blockchain::hash_transaction(tx))
|
||||
.collect();
|
||||
|
||||
if tx_hashes.is_empty() {
|
||||
return Blockchain::hash_data("");
|
||||
}
|
||||
|
||||
pub fn add(&mut self, tx: core::Tx) -> Result<(), BlockchainError> {
|
||||
self.apply(&tx)?;
|
||||
self.tx_mempool.push(tx);
|
||||
Ok(())
|
||||
if tx_hashes.len() == 1 {
|
||||
return tx_hashes[0].clone();
|
||||
}
|
||||
|
||||
pub fn hash_transaction(tx: &core::Tx) -> String {
|
||||
let mut hasher = Sha256::new();
|
||||
hasher.update(tx.to());
|
||||
hasher.update(tx.from());
|
||||
hasher.update(tx.value().to_be_bytes());
|
||||
hasher.update(tx.data());
|
||||
let mut current_level = tx_hashes.to_vec();
|
||||
|
||||
let res = hasher.finalize();
|
||||
hex::encode(res)
|
||||
while current_level.len() > 1 {
|
||||
current_level = Self::calculate_next_level(¤t_level);
|
||||
}
|
||||
|
||||
pub fn calculate_next_level(level: &[String]) -> Vec<String> {
|
||||
let mut next_level = Vec::new();
|
||||
return current_level[0].clone();
|
||||
}
|
||||
|
||||
for chunk in level.chunks(2) {
|
||||
let combined_hash = if chunk.len() == 2 {
|
||||
Self::hash_pair(&chunk[0], &chunk[1])
|
||||
} else {
|
||||
Self::hash_pair(&chunk[0], &chunk[0])
|
||||
};
|
||||
next_level.push(combined_hash);
|
||||
}
|
||||
next_level
|
||||
fn hash_pair(left: &str, right: &str) -> String {
|
||||
let combined = format!("{}{}", left, right);
|
||||
Self::hash_data(&combined)
|
||||
}
|
||||
|
||||
fn hash_data(data: &str) -> String {
|
||||
let mut hasher = Sha256::new();
|
||||
hasher.update(data.as_bytes());
|
||||
hex::encode(hasher.finalize())
|
||||
}
|
||||
|
||||
fn acc_exists(&self, acc: &Account) -> bool {
|
||||
self.balances.iter().find(|(k, _)| *k == acc).is_some()
|
||||
}
|
||||
|
||||
pub fn dump_blocks(&self, path: String) {
|
||||
let block_json = serde_json::to_string_pretty(&self.blocks).unwrap();
|
||||
if let Ok(mut db_file) = std::fs::OpenOptions::new().truncate(true).create(true).write(true).open(path) {
|
||||
db_file.write_all(&block_json.as_bytes()).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_block(&mut self) -> core::Block {
|
||||
let previous_hash = if self.blocks().len() > 0 {
|
||||
self.blocks().last().unwrap().head().block_hash()
|
||||
} else {
|
||||
""
|
||||
};
|
||||
let merkle_root = Self::calculate_merkle_root(&self.tx_mempool);
|
||||
let timestamp = std::time::SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs();
|
||||
let nonce = 0;
|
||||
let mut new_head = core::BlockHeader {
|
||||
previous_hash: previous_hash.to_string(),
|
||||
merkle_root,
|
||||
timestamp,
|
||||
nonce,
|
||||
block_hash: "".to_string()
|
||||
};
|
||||
|
||||
let mut block_hash = String::new();
|
||||
while !block_hash.starts_with("0") {
|
||||
new_head.nonce += 1;
|
||||
block_hash = calculate_block_hash(&new_head)
|
||||
}
|
||||
|
||||
pub fn calculate_merkle_root(tx: &[core::Tx]) -> String {
|
||||
let tx_hashes: Vec<String> = tx
|
||||
.iter()
|
||||
.map(|tx| Blockchain::hash_transaction(tx))
|
||||
.collect();
|
||||
new_head.block_hash = block_hash;
|
||||
|
||||
if tx_hashes.is_empty() {
|
||||
return Blockchain::hash_data("");
|
||||
}
|
||||
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()
|
||||
}
|
||||
|
||||
if tx_hashes.len() == 1 {
|
||||
return tx_hashes[0].clone();
|
||||
}
|
||||
|
||||
let mut current_level = tx_hashes.to_vec();
|
||||
|
||||
while current_level.len() > 1 {
|
||||
current_level = Self::calculate_next_level(¤t_level);
|
||||
}
|
||||
|
||||
return current_level[0].clone();
|
||||
pub fn apply(&mut self, tx: &core::Tx) -> Result<(), BlockchainError> {
|
||||
self.tx_mempool.push(tx.clone());
|
||||
match tx.validate() {
|
||||
Ok(_) => {},
|
||||
Err(e) => return Err(BlockchainError::Tx(e))
|
||||
}
|
||||
|
||||
fn hash_pair(left: &str, right: &str) -> String {
|
||||
let combined = format!("{}{}", left, right);
|
||||
Self::hash_data(&combined)
|
||||
if let Some(from_balance) = self.balances.get_mut(tx.from()) {
|
||||
if *from_balance > tx.value() {
|
||||
*from_balance -= tx.value();
|
||||
} else {
|
||||
return Err(BlockchainError::Tx(TxError::FromInsuffitientFonds))
|
||||
}
|
||||
} else {
|
||||
return Err(BlockchainError::Tx(TxError::UnknownAccount(tx.from().to_string())))
|
||||
}
|
||||
|
||||
fn hash_data(data: &str) -> String {
|
||||
let mut hasher = Sha256::new();
|
||||
hasher.update(data.as_bytes());
|
||||
hex::encode(hasher.finalize())
|
||||
if let Some(to_balance) = self.balances.get_mut(&tx.to().to_string()) {
|
||||
*to_balance += tx.value()
|
||||
} else {
|
||||
if self.acc_exists(tx.to()) {
|
||||
*self.balances.get_mut(tx.to()).unwrap() += tx.value();
|
||||
} else {
|
||||
self.balances.insert(tx.to().clone(), tx.value());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn dump_blocks(&self, db_file: &mut std::fs::File) {
|
||||
let block_json = serde_json::to_string_pretty(&self.blocks).unwrap();
|
||||
db_file.write_all(&block_json.as_bytes()).unwrap();
|
||||
}
|
||||
|
||||
pub fn create_block(&mut self) -> core::Block {
|
||||
let previous_hash = if self.blocks().len() > 0 {
|
||||
self.blocks().last().unwrap().head().block_hash()
|
||||
} else {
|
||||
""
|
||||
};
|
||||
let merkle_root = Self::calculate_merkle_root(&self.tx_mempool);
|
||||
let timestamp = std::time::SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs();
|
||||
let nonce = 0;
|
||||
let mut new_head = core::BlockHeader {
|
||||
previous_hash: previous_hash.to_string(),
|
||||
merkle_root,
|
||||
timestamp,
|
||||
nonce,
|
||||
block_hash: "".to_string()
|
||||
};
|
||||
|
||||
let mut block_hash = String::new();
|
||||
while !block_hash.starts_with("0") {
|
||||
new_head.nonce += 1;
|
||||
block_hash = calculate_block_hash(&new_head)
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
|
||||
pub fn apply(&mut self, tx: &core::Tx) -> Result<(), BlockchainError> {
|
||||
self.tx_mempool.push(tx.clone());
|
||||
return Ok(());
|
||||
match tx.validate() {
|
||||
Ok(_) => {},
|
||||
Err(e) => return Err(BlockchainError::Tx(e))
|
||||
}
|
||||
|
||||
if let Some(from_balance) = self.balances.get_mut(tx.from()) {
|
||||
if *from_balance > tx.value() {
|
||||
*from_balance -= tx.value();
|
||||
} else {
|
||||
return Err(BlockchainError::Tx(TxError::FromInsuffitientFonds))
|
||||
}
|
||||
} else {
|
||||
return Err(BlockchainError::Tx(TxError::UnknownAccount(tx.from().to_string())))
|
||||
}
|
||||
|
||||
if let Some(to_balance) = self.balances.get_mut(&tx.to().to_string()) {
|
||||
*to_balance += tx.value()
|
||||
} else {
|
||||
if tx.is_new_account() {
|
||||
self.balances.insert(tx.to().to_string(), tx.value());
|
||||
} else {
|
||||
return Err(BlockchainError::Tx(TxError::UnknownAccount(tx.to().to_string())))
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn new(balances: HashMap<Account, u32>, blocks: Vec<core::Block>, tx_mempool: Vec<core::Tx>) -> Blockchain {
|
||||
return Self {
|
||||
balances,
|
||||
blocks,
|
||||
tx_mempool
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn new(balances: HashMap<Account, u32>, blocks: Vec<core::Block>, tx_mempool: Vec<core::Tx>) -> Blockchain {
|
||||
return Self {
|
||||
id: BLOCKCHAIN_ID.to_string(),
|
||||
balances,
|
||||
blocks,
|
||||
tx_mempool
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pub fn calculate_block_hash(head: &core::BlockHeader) -> String {
|
||||
let mut hasher = sha2::Sha256::new();
|
||||
let mut hasher = sha2::Sha256::new();
|
||||
|
||||
hasher.update(head.nonce().to_be_bytes());
|
||||
hasher.update(head.previous_hash());
|
||||
hasher.update(head.timestamp().to_be_bytes());
|
||||
hasher.update(head.merkle_root());
|
||||
hasher.update(head.nonce().to_be_bytes());
|
||||
hasher.update(head.previous_hash());
|
||||
hasher.update(head.timestamp().to_be_bytes());
|
||||
hasher.update(head.merkle_root());
|
||||
|
||||
let res = hasher.finalize();
|
||||
hex::encode(res)
|
||||
let res = hasher.finalize();
|
||||
hex::encode(res)
|
||||
}
|
||||
|
||||
impl Blockchain {
|
||||
pub fn print_blocks(&self) {
|
||||
println!("Blocks List\n--------------");
|
||||
for (i, b) in self.blocks.iter().enumerate() {
|
||||
println!("Block #{i}\n{:#?}", b.head().block_hash);
|
||||
}
|
||||
pub fn print_blocks(&self) {
|
||||
println!("Blocks List\n--------------");
|
||||
for (i, b) in self.blocks.iter().enumerate() {
|
||||
println!("Block #{i}\n{:#?}", b.head().block_hash);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_balances(&self) -> &std::collections::HashMap<String, u32> {
|
||||
&self.balances
|
||||
pub fn get_balances(&self) -> &std::collections::HashMap<String, u32> {
|
||||
&self.balances
|
||||
}
|
||||
|
||||
pub fn blocks(&self) -> &[core::Block] {
|
||||
&self.blocks
|
||||
}
|
||||
|
||||
pub fn add_block(&mut self, block: core::Block) {
|
||||
match self.validate_block(&block) {
|
||||
Ok(()) => self.blocks.push(block),
|
||||
Err(e) => match e {
|
||||
ValidationError::InvalidBlockHash => log!(ERROR, "Invalid Block Hash"),
|
||||
ValidationError::InvalidPreviousBlockHash => log!(ERROR, "Invalid Previos Block Hash")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn blocks(&self) -> &[core::Block] {
|
||||
&self.blocks
|
||||
fn validate_block(&self, block: &core::Block) -> Result<(), ValidationError>{
|
||||
let head = block.head();
|
||||
let hash = calculate_block_hash(block.head());
|
||||
if hash != head.block_hash() {
|
||||
return Err(ValidationError::InvalidBlockHash)
|
||||
}
|
||||
|
||||
pub fn add_block(&mut self, block: core::Block) {
|
||||
match self.validate_block(&block) {
|
||||
Ok(()) => self.blocks.push(block),
|
||||
Err(e) => match e {
|
||||
ValidationError::InvalidBlockHash => log!(ERROR, "Invalid Block Hash"),
|
||||
ValidationError::InvalidPreviousBlockHash => log!(ERROR, "Invalid Previos Block Hash")
|
||||
}
|
||||
}
|
||||
if let Some(prev_block) = self.blocks().last() {
|
||||
if head.previous_hash() != prev_block.head().block_hash() {
|
||||
return Err(ValidationError::InvalidPreviousBlockHash)
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn validate_block(&self, block: &core::Block) -> Result<(), ValidationError>{
|
||||
let head = block.head();
|
||||
let hash = calculate_block_hash(block.head());
|
||||
if hash != head.block_hash() {
|
||||
return Err(ValidationError::InvalidBlockHash)
|
||||
}
|
||||
if let Some(prev_block) = self.blocks().last() {
|
||||
if head.previous_hash() != prev_block.head().block_hash() {
|
||||
return Err(ValidationError::InvalidPreviousBlockHash)
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
fn validate_chain(&self) -> Result<(), ValidationError>{
|
||||
log!(INFO, "Validating Chain");
|
||||
let blocks = self.blocks();
|
||||
for block in blocks {
|
||||
let head = block.head();
|
||||
let hash = calculate_block_hash(block.head());
|
||||
|
||||
if hash != head.block_hash() {
|
||||
return Err(ValidationError::InvalidBlockHash)
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn validate_chain(&self) -> Result<(), ValidationError>{
|
||||
log!(INFO, "Validating Chain");
|
||||
let blocks = self.blocks();
|
||||
for block in blocks {
|
||||
let head = block.head();
|
||||
let hash = calculate_block_hash(block.head());
|
||||
pub fn build(blocks: Vec<core::Block>) -> Result<Blockchain, ValidationError> {
|
||||
log!(INFO, "Starting Chain Build from Genesis");
|
||||
let chain = Blockchain {
|
||||
blocks,
|
||||
balances: HashMap::new(),
|
||||
tx_mempool: vec![],
|
||||
id: BLOCKCHAIN_ID.to_string(),
|
||||
};
|
||||
|
||||
if hash != head.block_hash() {
|
||||
return Err(ValidationError::InvalidBlockHash)
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn build(blocks: Vec<core::Block>) -> Result<Blockchain, ValidationError> {
|
||||
log!(INFO, "Starting Chain Build from Genesis");
|
||||
let chain = Blockchain {
|
||||
blocks,
|
||||
balances: HashMap::new(),
|
||||
tx_mempool: vec![]
|
||||
};
|
||||
|
||||
chain.validate_chain()?;
|
||||
Ok(chain)
|
||||
}
|
||||
chain.validate_chain()?;
|
||||
Ok(chain)
|
||||
}
|
||||
}
|
||||
|
||||
@ -30,10 +30,10 @@ impl Tx {
|
||||
pub fn is_reward(&self) -> bool {
|
||||
return self.data == "reward";
|
||||
}
|
||||
pub fn from(&self) -> &str {
|
||||
pub fn from(&self) -> &Account {
|
||||
&self.from
|
||||
}
|
||||
pub fn to(&self) -> &str {
|
||||
pub fn to(&self) -> &Account {
|
||||
&self.to
|
||||
}
|
||||
pub fn value(&self) -> u32 {
|
||||
|
||||
@ -4,6 +4,7 @@ pub mod core;
|
||||
pub mod native_node;
|
||||
pub mod seeds_constants;
|
||||
pub mod watcher;
|
||||
pub mod cli;
|
||||
|
||||
use crate::{args::get_args, watcher::watcher::Watcher};
|
||||
|
||||
@ -15,7 +16,7 @@ async fn main() {
|
||||
let mut watcher = Watcher::build().file(args.seed_file).addr(args.addr).start().await;
|
||||
|
||||
loop {
|
||||
if watcher.poll().await.is_ok_and(|b| b) {
|
||||
if !watcher.poll().await.is_ok_and(|b| b) {
|
||||
break ;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,5 +2,3 @@ pub mod node;
|
||||
pub mod network;
|
||||
pub mod message;
|
||||
pub mod error;
|
||||
pub mod cli;
|
||||
|
||||
|
||||
@ -1,36 +0,0 @@
|
||||
use crate::native_node::{node};
|
||||
use vlogger::*;
|
||||
use tokio::sync::mpsc;
|
||||
use crate::core;
|
||||
use std::io::{self, Write};
|
||||
|
||||
impl node::NativeNode {
|
||||
pub async fn cli(command_sender: mpsc::Sender<node::NodeCommand>) {
|
||||
loop {
|
||||
print!("\n> ");
|
||||
io::stdout().flush().unwrap();
|
||||
let mut input = String::new();
|
||||
match io::stdin().read_line(&mut input) {
|
||||
Ok(_) => {
|
||||
let input = input.trim();
|
||||
if input.is_empty() {
|
||||
continue ;
|
||||
}
|
||||
|
||||
let parts: Vec<&str> = input.split_whitespace().collect();
|
||||
let command = parts[0];
|
||||
let args = &parts[1..];
|
||||
|
||||
match command {
|
||||
_ => {
|
||||
log!(ERROR, "Unkown command {command}");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
},
|
||||
Err(_) => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -11,7 +11,7 @@ use vlogger::*;
|
||||
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
|
||||
pub enum ProtocolMessage {
|
||||
BootstrapRequest {
|
||||
node_id: uuid::Uuid,
|
||||
peer_id: uuid::Uuid,
|
||||
version: String
|
||||
},
|
||||
BootstrapResponse {
|
||||
@ -23,7 +23,7 @@ pub enum ProtocolMessage {
|
||||
GetPeersResponse {
|
||||
peer_addresses: Vec<SocketAddr>
|
||||
},
|
||||
Handshake { node_id: uuid::Uuid, version: String },
|
||||
Handshake { peer_id: uuid::Uuid, version: String },
|
||||
Block { peer_id: uuid::Uuid, height: u64, block: core::Block },
|
||||
Transaction{ peer_id: uuid::Uuid, tx: core::Tx },
|
||||
Ping { peer_id: uuid::Uuid },
|
||||
|
||||
@ -9,125 +9,160 @@ use tokio::select;
|
||||
use tokio::sync::mpsc;
|
||||
|
||||
impl node::NativeNode {
|
||||
pub async fn connect_to_seeds(&mut self, sender: mpsc::Sender<node::NodeCommand>) {
|
||||
for seed in SEED_NODES.iter() {
|
||||
if let Some(a)= self.addr {
|
||||
if *seed != a {
|
||||
if let Ok(mut stream) = tokio::net::TcpStream::connect(seed).await {
|
||||
if let Ok(peer_id) = node::NativeNode::send_handshake(self.id.clone(), &mut stream).await {
|
||||
let sender = sender.clone();
|
||||
node::NativeNode::establish_connection(peer_id, *seed, stream, sender).await;
|
||||
}
|
||||
pub async fn connect_to_seeds(&mut self) {
|
||||
for addr in SEED_NODES.iter() {
|
||||
if let Some(a)= self.addr {
|
||||
if *addr != a {
|
||||
self.connect_to_peer(*addr).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn connect_to_peer(
|
||||
&self,
|
||||
addr: SocketAddr,
|
||||
) {
|
||||
if let Ok(stream) = tokio::net::TcpStream::connect(addr).await {
|
||||
Self::establish_connection(self.id, None, addr, stream, self.tx().clone()).await;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub async fn accept_connections(
|
||||
listner: tokio::net::TcpListener,
|
||||
request_sender: tokio::sync::mpsc::Sender<node::NodeCommand>,
|
||||
node_id: uuid::Uuid
|
||||
) {
|
||||
log!(INFO, "Starting to accept connections");
|
||||
|
||||
while let Ok((mut stream, addr)) = listner.accept().await {
|
||||
if let Ok(message) = node::NativeNode::receive_message(&mut stream).await {
|
||||
match message {
|
||||
message::ProtocolMessage::Handshake { peer_id, .. } => {
|
||||
node::NativeNode::establish_connection(node_id, Some(peer_id), addr, stream, request_sender.clone()).await;
|
||||
},
|
||||
_ => {
|
||||
log!(WARNING, "Invalid Response! expected Handshake, got {:?}", message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pub async fn establish_connection(
|
||||
node_id: uuid::Uuid,
|
||||
peer_id: Option<uuid::Uuid>,
|
||||
addr: SocketAddr,
|
||||
mut stream: tokio::net::TcpStream,
|
||||
request_sender: tokio::sync::mpsc::Sender<node::NodeCommand>
|
||||
) {
|
||||
|
||||
let handshake_response = message::ProtocolMessage::Handshake {
|
||||
peer_id: node_id.clone(),
|
||||
version: "".to_string()
|
||||
};
|
||||
|
||||
match peer_id {
|
||||
Some(id) => {
|
||||
if let Ok(()) = Self::send_message(&mut stream, &handshake_response).await {
|
||||
let (response_sender, response_receiver) = mpsc::channel::<message::ProtocolMessage>(100);
|
||||
|
||||
let add_peer = node::NodeCommand::AddPeer {
|
||||
peer_id: id,
|
||||
addr: addr.clone(),
|
||||
sender: response_sender
|
||||
};
|
||||
|
||||
if let Err(_) = request_sender.send(add_peer).await {
|
||||
log!(ERROR, "Failed to send AddPeer to {}", addr);
|
||||
}
|
||||
|
||||
log!(INFO, "Established Connection with {}", addr);
|
||||
node::NativeNode::start_peer_handler(stream, id, request_sender.clone(), response_receiver).await;
|
||||
}
|
||||
}
|
||||
None => {
|
||||
if let Ok(mes) = Self::receive_message(&mut stream).await {
|
||||
let (response_sender, response_receiver) = mpsc::channel::<message::ProtocolMessage>(100);
|
||||
|
||||
match mes {
|
||||
message::ProtocolMessage::Handshake { peer_id, .. } => {
|
||||
let add_peer = node::NodeCommand::AddPeer {
|
||||
peer_id,
|
||||
addr: addr.clone(),
|
||||
sender: response_sender
|
||||
};
|
||||
|
||||
if let Err(_) = request_sender.send(add_peer).await {
|
||||
log!(ERROR, "Failed to send AddPeer to {}", addr);
|
||||
}
|
||||
|
||||
log!(INFO, "Established Connection with {}", addr);
|
||||
node::NativeNode::start_peer_handler(stream, peer_id, request_sender.clone(), response_receiver).await;
|
||||
}
|
||||
_ => { }
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn start_peer_handler(
|
||||
mut stream: tokio::net::TcpStream,
|
||||
peer_id: uuid::Uuid,
|
||||
request_sender: tokio::sync::mpsc::Sender<node::NodeCommand>,
|
||||
mut response_receiver: tokio::sync::mpsc::Receiver<message::ProtocolMessage>
|
||||
) {
|
||||
let peer_id_clone = peer_id.clone();
|
||||
|
||||
tokio::spawn(async move {
|
||||
log!(INFO, "Started Message Handler for {}", peer_id_clone);
|
||||
|
||||
loop {
|
||||
select! {
|
||||
response_result = response_receiver.recv() => {
|
||||
match response_result {
|
||||
Some(response) => {
|
||||
log!(INFO, "Sending response to {peer_id_clone}: {:#?}", response);
|
||||
if let Err(e) = node::NativeNode::send_message(&mut stream, &response).await {
|
||||
log!(ERROR, "Failed to send response to {peer_id_clone}: {}", e);
|
||||
break;
|
||||
}
|
||||
},
|
||||
None => {
|
||||
log!(INFO, "Response channel closed for {peer_id_clone}");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
message_result = node::NativeNode::receive_message(&mut stream) => {
|
||||
match message_result {
|
||||
Ok(message) => {
|
||||
log!(INFO, "Received Message from {peer_id_clone}");
|
||||
|
||||
let command = node::NodeCommand::ProcessMessage {
|
||||
peer_id,
|
||||
message: message.clone()
|
||||
};
|
||||
|
||||
if request_sender.send(command).await.is_err() {
|
||||
log!(ERROR, "Failed to send command to main thread from {peer_id}");
|
||||
break;
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
log!(WARNING, "Connection to {peer_id_clone} closed: {}", e.message);
|
||||
let cmd = node::NodeCommand::RemovePeer { peer_id: peer_id_clone.clone() };
|
||||
request_sender.send(cmd).await.unwrap();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn establish_connection(
|
||||
peer_id: uuid::Uuid,
|
||||
addr: SocketAddr,
|
||||
stream: tokio::net::TcpStream,
|
||||
request_sender: tokio::sync::mpsc::Sender<node::NodeCommand>
|
||||
) {
|
||||
let (response_sender, response_receiver) = mpsc::channel::<message::ProtocolMessage>(100);
|
||||
|
||||
let add_peer = node::NodeCommand::AddPeer {
|
||||
peer_id,
|
||||
addr: addr.clone(),
|
||||
sender: response_sender
|
||||
};
|
||||
|
||||
if let Err(_) = request_sender.send(add_peer).await {
|
||||
log!(ERROR, "Failed to send AddPeer to {}", addr);
|
||||
}
|
||||
|
||||
log!(INFO, "Established Connection with {}", addr);
|
||||
node::NativeNode::start_peer_handler(stream, peer_id, request_sender.clone(), response_receiver).await;
|
||||
}
|
||||
|
||||
pub async fn accept_connections(
|
||||
listner: tokio::net::TcpListener,
|
||||
request_sender: tokio::sync::mpsc::Sender<node::NodeCommand>,
|
||||
node_id: uuid::Uuid
|
||||
) {
|
||||
log!(INFO, "Starting to accept connections");
|
||||
|
||||
while let Ok((mut stream, addr)) = listner.accept().await {
|
||||
let handshake_response = message::ProtocolMessage::Handshake {
|
||||
node_id: node_id.clone(),
|
||||
version: "".to_string()
|
||||
};
|
||||
|
||||
if let Ok(_) = node::NativeNode::send_message(&mut stream, &handshake_response).await {
|
||||
if let Ok(message) = node::NativeNode::receive_message(&mut stream).await {
|
||||
match message {
|
||||
message::ProtocolMessage::Handshake { node_id, .. } => {
|
||||
node::NativeNode::establish_connection(node_id, addr, stream, request_sender.clone()).await;
|
||||
},
|
||||
_ => {
|
||||
log!(WARNING, "Invalid Response! expected Handshake, got {:?}", message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
async fn start_peer_handler(
|
||||
mut stream: tokio::net::TcpStream,
|
||||
peer_id: uuid::Uuid,
|
||||
request_sender: tokio::sync::mpsc::Sender<node::NodeCommand>,
|
||||
mut response_receiver: tokio::sync::mpsc::Receiver<message::ProtocolMessage>
|
||||
) {
|
||||
let peer_id_clone = peer_id.clone();
|
||||
|
||||
tokio::spawn(async move {
|
||||
log!(INFO, "Started Message Handler for {}", peer_id_clone);
|
||||
|
||||
loop {
|
||||
select! {
|
||||
response_result = response_receiver.recv() => {
|
||||
match response_result {
|
||||
Some(response) => {
|
||||
log!(INFO, "Sending response to {peer_id_clone}: {:#?}", response);
|
||||
if let Err(e) = node::NativeNode::send_message(&mut stream, &response).await {
|
||||
log!(ERROR, "Failed to send response to {peer_id_clone}: {}", e);
|
||||
break;
|
||||
}
|
||||
},
|
||||
None => {
|
||||
log!(INFO, "Response channel closed for {peer_id_clone}");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
message_result = node::NativeNode::receive_message(&mut stream) => {
|
||||
match message_result {
|
||||
Ok(message) => {
|
||||
log!(INFO, "Received Message from {peer_id_clone}");
|
||||
|
||||
let command = node::NodeCommand::ProcessMessage {
|
||||
peer_id,
|
||||
message: message.clone()
|
||||
};
|
||||
|
||||
if request_sender.send(command).await.is_err() {
|
||||
log!(ERROR, "Failed to send command to main thread from {peer_id}");
|
||||
break;
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
log!(WARNING, "Connection to {peer_id_clone} closed: {}", e.message);
|
||||
let cmd = node::NodeCommand::RemovePeer { peer_id: peer_id_clone.clone() };
|
||||
request_sender.send(cmd).await.unwrap();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -16,6 +16,7 @@ pub struct TcpPeer {
|
||||
pub sender: tokio::sync::mpsc::Sender<ProtocolMessage>
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub struct NativeNode {
|
||||
pub id: Uuid,
|
||||
pub addr: Option<SocketAddr>,
|
||||
@ -35,11 +36,12 @@ pub enum NodeCommand {
|
||||
Transaction { tx: core::Tx },
|
||||
StartListner(SocketAddr),
|
||||
CreateBlock,
|
||||
DebugListBlocks,
|
||||
DebugListPeers,
|
||||
DebugShowId,
|
||||
DebugDumpBlocks,
|
||||
ListBlocks,
|
||||
ListPeers,
|
||||
ShowId,
|
||||
DumpBlocks(String),
|
||||
ConnectToSeeds,
|
||||
ConnectToPeer(String),
|
||||
Exit,
|
||||
}
|
||||
|
||||
@ -72,7 +74,7 @@ impl NativeNode {
|
||||
|
||||
fn add_tcp_peer(&mut self, id: Uuid, addr: SocketAddr, sender: tokio::sync::mpsc::Sender<ProtocolMessage>) {
|
||||
let peer = TcpPeer {
|
||||
id: id,
|
||||
id,
|
||||
addr,
|
||||
sender
|
||||
};
|
||||
@ -132,12 +134,12 @@ impl NativeNode {
|
||||
}
|
||||
|
||||
pub async fn send_handshake(id: uuid::Uuid, stream: &mut tokio::net::TcpStream) -> Result<uuid::Uuid, ValidationError> {
|
||||
let handshake = ProtocolMessage::Handshake { node_id: id.clone(), version: "".to_string() };
|
||||
let handshake = ProtocolMessage::Handshake { peer_id: id.clone(), version: "".to_string() };
|
||||
NativeNode::send_message(stream, &handshake).await.unwrap();
|
||||
if let Ok(response) = NativeNode::receive_message(stream).await {
|
||||
match response {
|
||||
message::ProtocolMessage::Handshake { node_id, version: _ } => {
|
||||
Ok(node_id)
|
||||
message::ProtocolMessage::Handshake { peer_id, version: _ } => {
|
||||
Ok(peer_id)
|
||||
},
|
||||
_ => {
|
||||
log!(ERROR, "Invalid response on Handshake");
|
||||
@ -150,25 +152,25 @@ impl NativeNode {
|
||||
}
|
||||
|
||||
pub async fn bootstrap(&mut self) -> Result<(), ValidationError> {
|
||||
log!(INFO, "Running As Native Node");
|
||||
self.log(msg!(INFO, "Running As Native Node")).await;
|
||||
|
||||
let mut stream = tokio::net::TcpStream::connect(SEED_NODES[0]).await.unwrap();
|
||||
|
||||
let id = uuid::Uuid::new_v4();
|
||||
|
||||
if let Ok(_) = NativeNode::send_handshake(id, &mut stream).await {
|
||||
let message = message::ProtocolMessage::BootstrapRequest { node_id: id.clone(), version: "".to_string() };
|
||||
let message = message::ProtocolMessage::BootstrapRequest { peer_id: id.clone(), version: "".to_string() };
|
||||
NativeNode::send_message(&mut stream, &message).await.unwrap();
|
||||
log!(INFO, "Sent BootstrapRequest to seed");
|
||||
self.log(msg!(INFO, "Sent BootstrapRequest to seed")).await;
|
||||
if let Ok(response) = NativeNode::receive_message(&mut stream).await {
|
||||
match response {
|
||||
ProtocolMessage::BootstrapResponse { blocks } => {
|
||||
log!(INFO, "Received BootstrapResponse from seed");
|
||||
self.log(msg!(INFO, "Received BootstrapResponse from seed")).await;
|
||||
self.chain = core::Blockchain::build(blocks).unwrap();
|
||||
Ok(())
|
||||
},
|
||||
_ => {
|
||||
log!(ERROR, "Invalid Response from BootstrapRequest: {:?}", &response);
|
||||
self.log(msg!(ERROR, "Invalid Response from BootstrapRequest: {:?}", &response)).await;
|
||||
Err(ValidationError::InvalidBlockHash)
|
||||
}
|
||||
}
|
||||
@ -184,7 +186,7 @@ impl NativeNode {
|
||||
for (id, peer) in &self.tcp_peers {
|
||||
let message = ProtocolMessage::Transaction{peer_id: self.id, tx: tx.clone()};
|
||||
peer.sender.send(message).await.unwrap();
|
||||
log!(DEBUG, "Send Transaction message to {id}");
|
||||
self.log(msg!(DEBUG, "Send Transaction message to {id}")).await;
|
||||
}
|
||||
}
|
||||
|
||||
@ -196,7 +198,7 @@ impl NativeNode {
|
||||
block: block.clone()
|
||||
};
|
||||
peer.sender.send(message).await.unwrap();
|
||||
log!(DEBUG, "Send Block message to {id}");
|
||||
self.log(msg!(DEBUG, "Send Block message to {id}")).await;
|
||||
}
|
||||
}
|
||||
|
||||
@ -220,6 +222,10 @@ impl NativeNode {
|
||||
};
|
||||
}
|
||||
|
||||
async fn log(&self, msg: String) {
|
||||
let _ = self.exec_tx.send(ExecutorCommand::Print(msg));
|
||||
}
|
||||
|
||||
pub async fn run_native(&mut self) {
|
||||
|
||||
if let Some(a) = self.addr {
|
||||
@ -232,8 +238,13 @@ impl NativeNode {
|
||||
self.start_connection_listner(addr).await;
|
||||
}
|
||||
NodeCommand::ConnectToSeeds => {
|
||||
self.connect_to_seeds(self.tx()).await;
|
||||
self.connect_to_seeds().await;
|
||||
},
|
||||
NodeCommand::ConnectToPeer(addr) => {
|
||||
if let Ok(addr_sock) = addr.parse::<SocketAddr>() {
|
||||
self.connect_to_peer(addr_sock).await;
|
||||
}
|
||||
}
|
||||
NodeCommand::AddPeer { peer_id, addr, sender } => {
|
||||
self.add_tcp_peer(peer_id, addr, sender);
|
||||
},
|
||||
@ -248,27 +259,27 @@ impl NativeNode {
|
||||
self.broadcast_transaction(&tx).await;
|
||||
},
|
||||
NodeCommand::CreateBlock => {
|
||||
log!(INFO, "Received CreateBlock Command");
|
||||
self.log(msg!(INFO, "Received CreateBlock Command")).await;
|
||||
let block = self.chain.create_block();
|
||||
self.broadcast_block(&block).await;
|
||||
},
|
||||
NodeCommand::DebugListBlocks => {
|
||||
log!(INFO, "Received DebugListBlocks command");
|
||||
NodeCommand::ListBlocks => {
|
||||
self.log(msg!(INFO, "Received DebugListBlocks command")).await;
|
||||
self.chain.print_blocks();
|
||||
},
|
||||
NodeCommand::DebugListPeers => {
|
||||
log!(INFO, "Received DebugListPeers command");
|
||||
NodeCommand::ListPeers => {
|
||||
self.log(msg!(INFO, "Received DebugListPeers command")).await;
|
||||
self.list_peers();
|
||||
},
|
||||
NodeCommand::DebugShowId => {
|
||||
log!(INFO, "Received DebugListBlocks command");
|
||||
NodeCommand::ShowId => {
|
||||
self.log(msg!(INFO, "Received DebugListBlocks command")).await;
|
||||
self.show_id();
|
||||
},
|
||||
NodeCommand::DebugDumpBlocks => {
|
||||
// self.chain.dump_blocks(&mut self.db_file);
|
||||
NodeCommand::DumpBlocks(s) => {
|
||||
self.chain.dump_blocks(s);
|
||||
}
|
||||
NodeCommand::Exit => {
|
||||
log!(DEBUG, "Node Exit");
|
||||
self.log(msg!(DEBUG, "Node Exit")).await;
|
||||
break ;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,10 +1,11 @@
|
||||
use crate::{native_node::node::NodeCommand, watcher::renderer::*};
|
||||
use crate::{native_node::node::NodeCommand, watcher::{ watcher::Watcher, renderer::* }};
|
||||
use tokio::sync::mpsc;
|
||||
use vlogger::*;
|
||||
|
||||
pub enum ExecutorCommand {
|
||||
NodeResponse(String),
|
||||
Echo(Vec<String>),
|
||||
Print(String),
|
||||
InvalidCommand(String),
|
||||
Node(NodeCommand),
|
||||
Clear(RenderPane),
|
||||
@ -28,14 +29,14 @@ impl Executor {
|
||||
}
|
||||
}
|
||||
|
||||
fn exit(&mut self) {
|
||||
log!(DEBUG, "Executor Exit");
|
||||
async fn exit(&mut self) {
|
||||
self.render_string(msg!(DEBUG, "Executor Exit")).await;
|
||||
self.exit = true
|
||||
}
|
||||
|
||||
async fn listen(&mut self) {
|
||||
if let Some(cmd) = self.rx.recv().await {
|
||||
let _ = self.execute(cmd);
|
||||
let _ = self.execute(cmd).await;
|
||||
}
|
||||
}
|
||||
|
||||
@ -60,7 +61,7 @@ impl Executor {
|
||||
// }
|
||||
}
|
||||
|
||||
fn render_string(&self, str: String) {
|
||||
async fn render_string(&self, str: String) {
|
||||
let rd_cmd = RenderCommand::RenderStringToPane{
|
||||
str,
|
||||
pane: RenderPane::CliOutput
|
||||
@ -68,37 +69,39 @@ impl Executor {
|
||||
let _ = self.render_tx.send(rd_cmd);
|
||||
}
|
||||
|
||||
fn echo(&self, s: Vec<String>) {
|
||||
async fn echo(&self, s: Vec<String>) {
|
||||
Watcher::log(&self.render_tx, msg!(INFO, "Exec: Recieved echo command")).await;
|
||||
let mut str = s.join(" ");
|
||||
str.push_str("\n");
|
||||
let rd_cmd = RenderCommand::RenderStringToPane{
|
||||
str,
|
||||
pane: RenderPane::CliOutput
|
||||
};
|
||||
let _ = self.render_tx.send(rd_cmd);
|
||||
let _ = self.render_tx.send(rd_cmd).await;
|
||||
}
|
||||
|
||||
fn clear(&self, p: RenderPane) {
|
||||
async fn clear(&self, p: RenderPane) {
|
||||
let rd_cmd = RenderCommand::ClearPane(p);
|
||||
let _ = self.render_tx.send(rd_cmd);
|
||||
let _ = self.render_tx.send(rd_cmd).await;
|
||||
}
|
||||
|
||||
fn invalid_command(&self, str: String) {
|
||||
async fn invalid_command(&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 execute(&mut self, cmd: ExecutorCommand) {
|
||||
match cmd {
|
||||
ExecutorCommand::NodeResponse(resp) => self.render_string(resp),
|
||||
ExecutorCommand::NodeResponse(resp) => self.render_string(resp).await,
|
||||
ExecutorCommand::Node(n) => self.handle_node_cmd(n).await,
|
||||
ExecutorCommand::Clear(p) => self.clear(p),
|
||||
ExecutorCommand::Echo(s) => self.echo(s),
|
||||
ExecutorCommand::InvalidCommand(str) => self.invalid_command(str),
|
||||
ExecutorCommand::Exit => self.exit(),
|
||||
ExecutorCommand::Clear(p) => self.clear(p).await,
|
||||
ExecutorCommand::Echo(s) => self.echo(s).await,
|
||||
ExecutorCommand::Print(s) => self.render_string(s).await,
|
||||
ExecutorCommand::InvalidCommand(str) => self.invalid_command(str).await,
|
||||
ExecutorCommand::Exit => self.exit().await,
|
||||
}
|
||||
}
|
||||
|
||||
@ -108,4 +111,3 @@ impl Executor {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,10 +1,6 @@
|
||||
use std::net::SocketAddr;
|
||||
|
||||
use crate::native_node::node::NodeCommand;
|
||||
use crate::watcher::executor::{ExecutorCommand};
|
||||
use crate::watcher::executor::ExecutorCommand;
|
||||
use vlogger::*;
|
||||
|
||||
use crate::core;
|
||||
use crate::cli::cli;
|
||||
|
||||
use tokio::time::{timeout, Duration};
|
||||
|
||||
@ -40,7 +36,8 @@ impl Parser {
|
||||
}
|
||||
}
|
||||
|
||||
fn exit(&mut self) {
|
||||
async fn exit(&mut self) {
|
||||
self.print(msg!(DEBUG, "Parser Exit")).await;
|
||||
self.exit = true;
|
||||
}
|
||||
|
||||
@ -50,108 +47,49 @@ impl Parser {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn print(&self, msg: String) {
|
||||
if let Err(e) = self.exec_tx.send(ExecutorCommand::Echo(vec![msg])).await {
|
||||
log!(ERROR, "Error response from exec: {e}");
|
||||
}
|
||||
}
|
||||
|
||||
async fn listen(&mut self) {
|
||||
if let Ok(Some(mes)) = timeout(Duration::from_millis(400), self.rx.recv()).await {
|
||||
log!(DEBUG, "Parser: Received message from watcher");
|
||||
self.print(msg!(INFO, "Parser: Received message from watcher")).await;
|
||||
match mes {
|
||||
ParserCommand::ParseCmdString(s) => {
|
||||
let s_split: Vec<&str> = s.split(" ").collect();
|
||||
|
||||
if s_split.len() != 0 {
|
||||
let cmd = &s_split[0];
|
||||
let args = &s_split[1..];
|
||||
let exec_cmd = match *cmd {
|
||||
CMD_NODE => {
|
||||
if !args.is_empty() {
|
||||
match args[0] {
|
||||
"id" => {
|
||||
ExecutorCommand::Node(NodeCommand::DebugShowId)
|
||||
},
|
||||
"tx" => {
|
||||
if args.len() != 4 {
|
||||
log!(ERROR, "Invalid arg count! Expected {}, got {}", 4, args.len());
|
||||
}
|
||||
let from = args[0];
|
||||
let to = args[1];
|
||||
let value = args[2].parse::<u32>().unwrap();
|
||||
let data = args[3];
|
||||
|
||||
let tx = core::Tx::new(
|
||||
from.to_string(),
|
||||
to.to_string(),
|
||||
value,
|
||||
data.to_string()
|
||||
);
|
||||
|
||||
ExecutorCommand::Node(NodeCommand::Transaction { tx })
|
||||
},
|
||||
"block" => {
|
||||
ExecutorCommand::Node(NodeCommand::CreateBlock)
|
||||
},
|
||||
"list" => {
|
||||
if args.len() != 1 {
|
||||
ExecutorCommand::InvalidCommand(msg!(ERROR, "node list: expects 1 argument"))
|
||||
} else {
|
||||
match args[0] {
|
||||
"blocks" => ExecutorCommand::Node(NodeCommand::DebugListBlocks),
|
||||
"peers" => ExecutorCommand::Node(NodeCommand::DebugListPeers),
|
||||
_ => ExecutorCommand::InvalidCommand(msg!(ERROR, "Unkown arg: {}", args[0])),
|
||||
}
|
||||
}
|
||||
},
|
||||
"dump_blocks" => {
|
||||
ExecutorCommand::Node(NodeCommand::DebugDumpBlocks)
|
||||
},
|
||||
"connect" => {
|
||||
ExecutorCommand::Node(NodeCommand::ConnectToSeeds)
|
||||
},
|
||||
"listen" => {
|
||||
if args.len() != 1 {
|
||||
ExecutorCommand::InvalidCommand(msg!(ERROR, "node listen: expects 1 argument"))
|
||||
} else {
|
||||
if let Ok(addr) = args[0].parse::<SocketAddr>() {
|
||||
ExecutorCommand::Node(NodeCommand::StartListner(addr))
|
||||
} else {
|
||||
ExecutorCommand::InvalidCommand(msg!(ERROR, "node listen: invalid address {}", args[0]))
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
ExecutorCommand::InvalidCommand(msg!(ERROR, "node: unknown argument {}", args[0]))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ExecutorCommand::InvalidCommand(msg!(ERROR, "node: expected arguments"))
|
||||
}
|
||||
}
|
||||
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}"))
|
||||
}
|
||||
};
|
||||
let _ = self.exec_tx.send(exec_cmd).await;
|
||||
}
|
||||
}
|
||||
let argv: Vec<&str> = std::iter::once(" ")
|
||||
.chain(s.split_whitespace())
|
||||
.collect();
|
||||
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 => {
|
||||
log!(DEBUG, "Parser Exit");
|
||||
self.exit();
|
||||
self.exit().await;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -31,7 +31,7 @@ pub struct Pane {
|
||||
buffer: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
#[derive(Debug, PartialEq, Clone, clap::ValueEnum)]
|
||||
pub enum RenderPane {
|
||||
All,
|
||||
CliInput,
|
||||
@ -200,13 +200,32 @@ impl Widget for &Renderer {
|
||||
}
|
||||
})
|
||||
.border_set(border::THICK);
|
||||
let inner_area = block.inner(layout[p.layout_index as usize]);
|
||||
let content_width = inner_area.width as usize;
|
||||
let content_height = inner_area.height as usize;
|
||||
let wrapped_lines = p.buffer
|
||||
.lines()
|
||||
.map(|line| {
|
||||
if line.is_empty() {
|
||||
1
|
||||
} else {
|
||||
(line.len() + content_width - 1) / content_width
|
||||
}
|
||||
})
|
||||
.sum::<usize>();
|
||||
|
||||
let scroll_offset = if wrapped_lines > content_height {
|
||||
wrapped_lines - content_height
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
Paragraph::new(p.buffer.clone())
|
||||
.wrap(Wrap::default())
|
||||
.left_aligned()
|
||||
.block(block)
|
||||
.scroll((scroll_offset as u16, 0))
|
||||
.render(layout[p.layout_index as usize], buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,12 +1,13 @@
|
||||
use crate::watcher::*;
|
||||
|
||||
use crossterm::{event::{self, Event, KeyCode, KeyEventKind}};
|
||||
use crossterm::event::{self, Event, KeyCode, KeyEventKind};
|
||||
use tokio::sync::mpsc;
|
||||
use std::{io::{self}, net::SocketAddr};
|
||||
|
||||
use crate::{native_node::node::{NativeNode, NodeCommand}};
|
||||
use crate::native_node::node::{NativeNode, NodeCommand};
|
||||
use vlogger::*;
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub struct Watcher {
|
||||
render_tx: mpsc::Sender<RenderCommand>,
|
||||
parser_tx: mpsc::Sender<ParserCommand>,
|
||||
@ -27,9 +28,11 @@ impl Watcher {
|
||||
WatcherBuilder::new()
|
||||
}
|
||||
|
||||
pub async fn log(&self, msg: String) -> Result<(), mpsc::error::SendError<RenderCommand>> {
|
||||
pub async fn log(render_tx: &mpsc::Sender<RenderCommand>, msg: String) {
|
||||
let rendermsg = RenderCommand::RenderStringToPane { str: msg, pane: RenderPane::CliOutput };
|
||||
self.render_tx.send(rendermsg).await
|
||||
if let Err(e) = render_tx.send(rendermsg).await {
|
||||
log!(FATAL, "Failed to send render command: {e}");
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn exit(self) {
|
||||
@ -57,8 +60,8 @@ impl Watcher {
|
||||
KeyCode::Enter => {
|
||||
let rd_mes = RenderCommand::RenderInput(k.code);
|
||||
let pr_mes = ParserCommand::ParseCmdString(self.cmd_buffer.clone());
|
||||
let _ = self.render_tx.send(rd_mes).await;
|
||||
let _ = self.parser_tx.send(pr_mes).await;
|
||||
let _ = self.render_tx.send(rd_mes).await;
|
||||
self.cmd_buffer.clear();
|
||||
}
|
||||
KeyCode::Esc => {
|
||||
@ -96,9 +99,9 @@ impl WatcherBuilder {
|
||||
self
|
||||
}
|
||||
|
||||
pub async fn log(render_tx: &mpsc::Sender<RenderCommand>, msg: String) -> Result<(), mpsc::error::SendError<RenderCommand>> {
|
||||
pub async fn log(render_tx: &mpsc::Sender<RenderCommand>, msg: String) {
|
||||
let rendermsg = RenderCommand::RenderStringToPane { str: msg, pane: RenderPane::CliOutput };
|
||||
render_tx.send(rendermsg).await
|
||||
let _ = render_tx.send(rendermsg).await;
|
||||
}
|
||||
|
||||
|
||||
@ -129,7 +132,7 @@ impl WatcherBuilder {
|
||||
}
|
||||
});
|
||||
|
||||
let _ = Self::log(&render_tx, msg!(INFO, "Started Parser")).await;
|
||||
Watcher::log(&render_tx, msg!(INFO, "Started Parser")).await;
|
||||
|
||||
let executor_handle = tokio::spawn({
|
||||
let rend_tx = render_tx.clone();
|
||||
@ -139,7 +142,7 @@ impl WatcherBuilder {
|
||||
}
|
||||
});
|
||||
|
||||
let _ = Self::log(&render_tx, msg!(INFO, "Started Executor")).await;
|
||||
Watcher::log(&render_tx, msg!(INFO, "Started Executor")).await;
|
||||
|
||||
let node_tx = node.tx();
|
||||
|
||||
@ -149,7 +152,7 @@ impl WatcherBuilder {
|
||||
}
|
||||
});
|
||||
|
||||
let _ = Self::log(&render_tx, msg!(INFO, "Started Node")).await;
|
||||
Watcher::log(&render_tx, msg!(INFO, "Started Node")).await;
|
||||
|
||||
Watcher {
|
||||
render_tx,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user