bless
This commit is contained in:
parent
4b6801644b
commit
c2f189ccb9
13
Cargo.lock
generated
13
Cargo.lock
generated
@ -144,6 +144,7 @@ dependencies = [
|
|||||||
"clap",
|
"clap",
|
||||||
"crossterm 0.29.0",
|
"crossterm 0.29.0",
|
||||||
"hex",
|
"hex",
|
||||||
|
"once_cell",
|
||||||
"ratatui",
|
"ratatui",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
@ -260,6 +261,15 @@ version = "1.0.4"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
|
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]]
|
[[package]]
|
||||||
name = "compact_str"
|
name = "compact_str"
|
||||||
version = "0.8.1"
|
version = "0.8.1"
|
||||||
@ -1500,6 +1510,9 @@ checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "vlogger"
|
name = "vlogger"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"colored",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "warp"
|
name = "warp"
|
||||||
|
|||||||
@ -20,3 +20,4 @@ web-sys = { version = "0.3.77", features = ["WebSocket"] }
|
|||||||
vlogger = { path = "./lib/logger-rs" }
|
vlogger = { path = "./lib/logger-rs" }
|
||||||
ratatui = "0.29.0"
|
ratatui = "0.29.0"
|
||||||
crossterm = "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.
|
# It is not intended for manual editing.
|
||||||
version = 4
|
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]]
|
[[package]]
|
||||||
name = "vlogger"
|
name = "vlogger"
|
||||||
version = "0.1.0"
|
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"
|
edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
colored = "3.0.0"
|
||||||
|
|||||||
@ -14,22 +14,6 @@ pub const LOG_LEVEL: [&str; 5] = [
|
|||||||
"FATAL",
|
"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 {
|
pub fn current_timestamp() -> String {
|
||||||
let now = SystemTime::now()
|
let now = SystemTime::now()
|
||||||
.duration_since(UNIX_EPOCH)
|
.duration_since(UNIX_EPOCH)
|
||||||
@ -62,16 +46,17 @@ macro_rules! msg {
|
|||||||
match $level {
|
match $level {
|
||||||
$crate::INFO => {
|
$crate::INFO => {
|
||||||
format!(
|
format!(
|
||||||
"[{}] {} | {}\n",
|
"[{}] {} | {}\n",
|
||||||
$crate::colored($crate::LOG_LEVEL[$level], "green"),
|
//$crate::colored($crate::LOG_LEVEL[$level], "green"),
|
||||||
|
$crate::LOG_LEVEL[$level].to_string(),
|
||||||
$crate::current_timestamp(),
|
$crate::current_timestamp(),
|
||||||
formatted_msg
|
formatted_msg
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
$crate::DEBUG => {
|
$crate::DEBUG => {
|
||||||
format!(
|
format!(
|
||||||
"[{}] [{}:{}] {} | {}\n",
|
"[{}]\t[{}:{}] {} | {}\n",
|
||||||
$crate::LOG_LEVEL[$level],
|
$crate::LOG_LEVEL[$level].to_string(),
|
||||||
file!(),
|
file!(),
|
||||||
line!(),
|
line!(),
|
||||||
$crate::current_timestamp(),
|
$crate::current_timestamp(),
|
||||||
@ -81,7 +66,7 @@ macro_rules! msg {
|
|||||||
$crate::WARNING => {
|
$crate::WARNING => {
|
||||||
format!(
|
format!(
|
||||||
"[{}] {} | {}\n",
|
"[{}] {} | {}\n",
|
||||||
$crate::colored($crate::LOG_LEVEL[$level], "yellow"),
|
$crate::LOG_LEVEL[$level].to_string(),
|
||||||
$crate::current_timestamp(),
|
$crate::current_timestamp(),
|
||||||
formatted_msg
|
formatted_msg
|
||||||
)
|
)
|
||||||
@ -89,7 +74,7 @@ macro_rules! msg {
|
|||||||
$crate::ERROR => {
|
$crate::ERROR => {
|
||||||
format!(
|
format!(
|
||||||
"[{}] {} | {}\n",
|
"[{}] {} | {}\n",
|
||||||
$crate::colored($crate::LOG_LEVEL[$level], "red"),
|
$crate::LOG_LEVEL[$level].to_string(),
|
||||||
$crate::current_timestamp(),
|
$crate::current_timestamp(),
|
||||||
formatted_msg
|
formatted_msg
|
||||||
)
|
)
|
||||||
@ -97,7 +82,7 @@ macro_rules! msg {
|
|||||||
$crate::FATAL => {
|
$crate::FATAL => {
|
||||||
format!(
|
format!(
|
||||||
"[{}] [{}:{}] {} | {}\n",
|
"[{}] [{}:{}] {} | {}\n",
|
||||||
$crate::colored($crate::LOG_LEVEL[$level], "red"),
|
$crate::LOG_LEVEL[$level].to_string(),
|
||||||
file!(),
|
file!(),
|
||||||
line!(),
|
line!(),
|
||||||
$crate::current_timestamp(),
|
$crate::current_timestamp(),
|
||||||
@ -154,14 +139,6 @@ mod tests {
|
|||||||
assert!(error_msg.contains("Test error: 42"));
|
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]
|
#[test]
|
||||||
fn test_timestamp() {
|
fn test_timestamp() {
|
||||||
let ts = current_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 clap::{Parser, Subcommand};
|
||||||
use crate::core;
|
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)]
|
#[derive(Parser, Debug)]
|
||||||
#[command(version, about, long_about = None)]
|
#[command(version, about, long_about = None)]
|
||||||
pub struct Args {
|
pub struct CliArgs {
|
||||||
/// Provide address on which node will listen
|
/// Provide address on which node will listen
|
||||||
#[arg(short = 'a', long)]
|
#[arg(short = 'a', long)]
|
||||||
pub addr: Option<SocketAddr>,
|
pub addr: Option<SocketAddr>,
|
||||||
@ -26,6 +131,6 @@ pub enum TxCmd {
|
|||||||
Add(core::Tx)
|
Add(core::Tx)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_args() -> Args {
|
pub fn get_args() -> CliArgs {
|
||||||
Args::parse()
|
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::io::Write;
|
||||||
use std::time::UNIX_EPOCH;
|
use std::time::UNIX_EPOCH;
|
||||||
|
|
||||||
|
const BLOCKCHAIN_ID: &str = "victors-first-blockchain";
|
||||||
|
|
||||||
pub type Account = String;
|
pub type Account = String;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum ValidationError {
|
pub enum ValidationError {
|
||||||
InvalidBlockHash,
|
InvalidBlockHash,
|
||||||
InvalidPreviousBlockHash
|
InvalidPreviousBlockHash
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct Blockchain {
|
pub struct Blockchain {
|
||||||
balances: std::collections::HashMap<Account, u32>,
|
id: String,
|
||||||
blocks: Vec<core::Block>,
|
balances: std::collections::HashMap<Account, u32>,
|
||||||
tx_mempool: Vec<core::Tx>,
|
blocks: Vec<core::Block>,
|
||||||
|
tx_mempool: Vec<core::Tx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
impl Blockchain {
|
impl Blockchain {
|
||||||
pub fn open_account(&mut self, tx: core::Tx) -> Result<(), BlockchainError> {
|
pub fn open_account(&mut self, tx: core::Tx) -> Result<(), BlockchainError> {
|
||||||
if !tx.is_new_account() {
|
if !tx.is_new_account() {
|
||||||
Err(BlockchainError::InvalidAccountCreation)
|
Err(BlockchainError::InvalidAccountCreation)
|
||||||
} else {
|
} else {
|
||||||
self.add(tx)
|
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> {
|
if tx_hashes.len() == 1 {
|
||||||
self.apply(&tx)?;
|
return tx_hashes[0].clone();
|
||||||
self.tx_mempool.push(tx);
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn hash_transaction(tx: &core::Tx) -> String {
|
let mut current_level = tx_hashes.to_vec();
|
||||||
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();
|
while current_level.len() > 1 {
|
||||||
hex::encode(res)
|
current_level = Self::calculate_next_level(¤t_level);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn calculate_next_level(level: &[String]) -> Vec<String> {
|
return current_level[0].clone();
|
||||||
let mut next_level = Vec::new();
|
}
|
||||||
|
|
||||||
for chunk in level.chunks(2) {
|
fn hash_pair(left: &str, right: &str) -> String {
|
||||||
let combined_hash = if chunk.len() == 2 {
|
let combined = format!("{}{}", left, right);
|
||||||
Self::hash_pair(&chunk[0], &chunk[1])
|
Self::hash_data(&combined)
|
||||||
} else {
|
}
|
||||||
Self::hash_pair(&chunk[0], &chunk[0])
|
|
||||||
};
|
fn hash_data(data: &str) -> String {
|
||||||
next_level.push(combined_hash);
|
let mut hasher = Sha256::new();
|
||||||
}
|
hasher.update(data.as_bytes());
|
||||||
next_level
|
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 {
|
new_head.block_hash = block_hash;
|
||||||
let tx_hashes: Vec<String> = tx
|
|
||||||
.iter()
|
|
||||||
.map(|tx| Blockchain::hash_transaction(tx))
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
if tx_hashes.is_empty() {
|
let new_block = core::Block::new(new_head, self.tx_mempool.clone());
|
||||||
return Blockchain::hash_data("");
|
log!(DEBUG, "Created new Block {:#?}", new_block);
|
||||||
}
|
self.blocks.push(new_block);
|
||||||
|
self.blocks.last().unwrap().clone()
|
||||||
|
}
|
||||||
|
|
||||||
if tx_hashes.len() == 1 {
|
pub fn apply(&mut self, tx: &core::Tx) -> Result<(), BlockchainError> {
|
||||||
return tx_hashes[0].clone();
|
self.tx_mempool.push(tx.clone());
|
||||||
}
|
match tx.validate() {
|
||||||
|
Ok(_) => {},
|
||||||
let mut current_level = tx_hashes.to_vec();
|
Err(e) => return Err(BlockchainError::Tx(e))
|
||||||
|
|
||||||
while current_level.len() > 1 {
|
|
||||||
current_level = Self::calculate_next_level(¤t_level);
|
|
||||||
}
|
|
||||||
|
|
||||||
return current_level[0].clone();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn hash_pair(left: &str, right: &str) -> String {
|
if let Some(from_balance) = self.balances.get_mut(tx.from()) {
|
||||||
let combined = format!("{}{}", left, right);
|
if *from_balance > tx.value() {
|
||||||
Self::hash_data(&combined)
|
*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 {
|
if let Some(to_balance) = self.balances.get_mut(&tx.to().to_string()) {
|
||||||
let mut hasher = Sha256::new();
|
*to_balance += tx.value()
|
||||||
hasher.update(data.as_bytes());
|
} else {
|
||||||
hex::encode(hasher.finalize())
|
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) {
|
Ok(())
|
||||||
let block_json = serde_json::to_string_pretty(&self.blocks).unwrap();
|
}
|
||||||
db_file.write_all(&block_json.as_bytes()).unwrap();
|
|
||||||
}
|
pub fn new(balances: HashMap<Account, u32>, blocks: Vec<core::Block>, tx_mempool: Vec<core::Tx>) -> Blockchain {
|
||||||
|
return Self {
|
||||||
pub fn create_block(&mut self) -> core::Block {
|
id: BLOCKCHAIN_ID.to_string(),
|
||||||
let previous_hash = if self.blocks().len() > 0 {
|
balances,
|
||||||
self.blocks().last().unwrap().head().block_hash()
|
blocks,
|
||||||
} else {
|
tx_mempool
|
||||||
""
|
|
||||||
};
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn calculate_block_hash(head: &core::BlockHeader) -> String {
|
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.nonce().to_be_bytes());
|
||||||
hasher.update(head.previous_hash());
|
hasher.update(head.previous_hash());
|
||||||
hasher.update(head.timestamp().to_be_bytes());
|
hasher.update(head.timestamp().to_be_bytes());
|
||||||
hasher.update(head.merkle_root());
|
hasher.update(head.merkle_root());
|
||||||
|
|
||||||
let res = hasher.finalize();
|
let res = hasher.finalize();
|
||||||
hex::encode(res)
|
hex::encode(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Blockchain {
|
impl Blockchain {
|
||||||
pub fn print_blocks(&self) {
|
pub fn print_blocks(&self) {
|
||||||
println!("Blocks List\n--------------");
|
println!("Blocks List\n--------------");
|
||||||
for (i, b) in self.blocks.iter().enumerate() {
|
for (i, b) in self.blocks.iter().enumerate() {
|
||||||
println!("Block #{i}\n{:#?}", b.head().block_hash);
|
println!("Block #{i}\n{:#?}", b.head().block_hash);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_balances(&self) -> &std::collections::HashMap<String, u32> {
|
pub fn get_balances(&self) -> &std::collections::HashMap<String, u32> {
|
||||||
&self.balances
|
&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] {
|
fn validate_block(&self, block: &core::Block) -> Result<(), ValidationError>{
|
||||||
&self.blocks
|
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() {
|
||||||
pub fn add_block(&mut self, block: core::Block) {
|
if head.previous_hash() != prev_block.head().block_hash() {
|
||||||
match self.validate_block(&block) {
|
return Err(ValidationError::InvalidPreviousBlockHash)
|
||||||
Ok(()) => self.blocks.push(block),
|
}
|
||||||
Err(e) => match e {
|
|
||||||
ValidationError::InvalidBlockHash => log!(ERROR, "Invalid Block Hash"),
|
|
||||||
ValidationError::InvalidPreviousBlockHash => log!(ERROR, "Invalid Previos Block Hash")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn validate_block(&self, block: &core::Block) -> Result<(), ValidationError>{
|
fn validate_chain(&self) -> Result<(), ValidationError>{
|
||||||
let head = block.head();
|
log!(INFO, "Validating Chain");
|
||||||
let hash = calculate_block_hash(block.head());
|
let blocks = self.blocks();
|
||||||
if hash != head.block_hash() {
|
for block in blocks {
|
||||||
return Err(ValidationError::InvalidBlockHash)
|
let head = block.head();
|
||||||
}
|
let hash = calculate_block_hash(block.head());
|
||||||
if let Some(prev_block) = self.blocks().last() {
|
|
||||||
if head.previous_hash() != prev_block.head().block_hash() {
|
if hash != head.block_hash() {
|
||||||
return Err(ValidationError::InvalidPreviousBlockHash)
|
return Err(ValidationError::InvalidBlockHash)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn validate_chain(&self) -> Result<(), ValidationError>{
|
pub fn build(blocks: Vec<core::Block>) -> Result<Blockchain, ValidationError> {
|
||||||
log!(INFO, "Validating Chain");
|
log!(INFO, "Starting Chain Build from Genesis");
|
||||||
let blocks = self.blocks();
|
let chain = Blockchain {
|
||||||
for block in blocks {
|
blocks,
|
||||||
let head = block.head();
|
balances: HashMap::new(),
|
||||||
let hash = calculate_block_hash(block.head());
|
tx_mempool: vec![],
|
||||||
|
id: BLOCKCHAIN_ID.to_string(),
|
||||||
|
};
|
||||||
|
|
||||||
if hash != head.block_hash() {
|
chain.validate_chain()?;
|
||||||
return Err(ValidationError::InvalidBlockHash)
|
Ok(chain)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -30,10 +30,10 @@ impl Tx {
|
|||||||
pub fn is_reward(&self) -> bool {
|
pub fn is_reward(&self) -> bool {
|
||||||
return self.data == "reward";
|
return self.data == "reward";
|
||||||
}
|
}
|
||||||
pub fn from(&self) -> &str {
|
pub fn from(&self) -> &Account {
|
||||||
&self.from
|
&self.from
|
||||||
}
|
}
|
||||||
pub fn to(&self) -> &str {
|
pub fn to(&self) -> &Account {
|
||||||
&self.to
|
&self.to
|
||||||
}
|
}
|
||||||
pub fn value(&self) -> u32 {
|
pub fn value(&self) -> u32 {
|
||||||
|
|||||||
@ -4,6 +4,7 @@ pub mod core;
|
|||||||
pub mod native_node;
|
pub mod native_node;
|
||||||
pub mod seeds_constants;
|
pub mod seeds_constants;
|
||||||
pub mod watcher;
|
pub mod watcher;
|
||||||
|
pub mod cli;
|
||||||
|
|
||||||
use crate::{args::get_args, watcher::watcher::Watcher};
|
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;
|
let mut watcher = Watcher::build().file(args.seed_file).addr(args.addr).start().await;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
if watcher.poll().await.is_ok_and(|b| b) {
|
if !watcher.poll().await.is_ok_and(|b| b) {
|
||||||
break ;
|
break ;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,5 +2,3 @@ pub mod node;
|
|||||||
pub mod network;
|
pub mod network;
|
||||||
pub mod message;
|
pub mod message;
|
||||||
pub mod error;
|
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)]
|
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
|
||||||
pub enum ProtocolMessage {
|
pub enum ProtocolMessage {
|
||||||
BootstrapRequest {
|
BootstrapRequest {
|
||||||
node_id: uuid::Uuid,
|
peer_id: uuid::Uuid,
|
||||||
version: String
|
version: String
|
||||||
},
|
},
|
||||||
BootstrapResponse {
|
BootstrapResponse {
|
||||||
@ -23,7 +23,7 @@ pub enum ProtocolMessage {
|
|||||||
GetPeersResponse {
|
GetPeersResponse {
|
||||||
peer_addresses: Vec<SocketAddr>
|
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 },
|
Block { peer_id: uuid::Uuid, height: u64, block: core::Block },
|
||||||
Transaction{ peer_id: uuid::Uuid, tx: core::Tx },
|
Transaction{ peer_id: uuid::Uuid, tx: core::Tx },
|
||||||
Ping { peer_id: uuid::Uuid },
|
Ping { peer_id: uuid::Uuid },
|
||||||
|
|||||||
@ -9,125 +9,160 @@ use tokio::select;
|
|||||||
use tokio::sync::mpsc;
|
use tokio::sync::mpsc;
|
||||||
|
|
||||||
impl node::NativeNode {
|
impl node::NativeNode {
|
||||||
pub async fn connect_to_seeds(&mut self, sender: mpsc::Sender<node::NodeCommand>) {
|
pub async fn connect_to_seeds(&mut self) {
|
||||||
for seed in SEED_NODES.iter() {
|
for addr in SEED_NODES.iter() {
|
||||||
if let Some(a)= self.addr {
|
if let Some(a)= self.addr {
|
||||||
if *seed != a {
|
if *addr != a {
|
||||||
if let Ok(mut stream) = tokio::net::TcpStream::connect(seed).await {
|
self.connect_to_peer(*addr).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_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>
|
pub sender: tokio::sync::mpsc::Sender<ProtocolMessage>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
pub struct NativeNode {
|
pub struct NativeNode {
|
||||||
pub id: Uuid,
|
pub id: Uuid,
|
||||||
pub addr: Option<SocketAddr>,
|
pub addr: Option<SocketAddr>,
|
||||||
@ -35,11 +36,12 @@ pub enum NodeCommand {
|
|||||||
Transaction { tx: core::Tx },
|
Transaction { tx: core::Tx },
|
||||||
StartListner(SocketAddr),
|
StartListner(SocketAddr),
|
||||||
CreateBlock,
|
CreateBlock,
|
||||||
DebugListBlocks,
|
ListBlocks,
|
||||||
DebugListPeers,
|
ListPeers,
|
||||||
DebugShowId,
|
ShowId,
|
||||||
DebugDumpBlocks,
|
DumpBlocks(String),
|
||||||
ConnectToSeeds,
|
ConnectToSeeds,
|
||||||
|
ConnectToPeer(String),
|
||||||
Exit,
|
Exit,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,7 +74,7 @@ impl NativeNode {
|
|||||||
|
|
||||||
fn add_tcp_peer(&mut self, id: Uuid, addr: SocketAddr, sender: tokio::sync::mpsc::Sender<ProtocolMessage>) {
|
fn add_tcp_peer(&mut self, id: Uuid, addr: SocketAddr, sender: tokio::sync::mpsc::Sender<ProtocolMessage>) {
|
||||||
let peer = TcpPeer {
|
let peer = TcpPeer {
|
||||||
id: id,
|
id,
|
||||||
addr,
|
addr,
|
||||||
sender
|
sender
|
||||||
};
|
};
|
||||||
@ -132,12 +134,12 @@ impl NativeNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn send_handshake(id: uuid::Uuid, stream: &mut tokio::net::TcpStream) -> Result<uuid::Uuid, ValidationError> {
|
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();
|
NativeNode::send_message(stream, &handshake).await.unwrap();
|
||||||
if let Ok(response) = NativeNode::receive_message(stream).await {
|
if let Ok(response) = NativeNode::receive_message(stream).await {
|
||||||
match response {
|
match response {
|
||||||
message::ProtocolMessage::Handshake { node_id, version: _ } => {
|
message::ProtocolMessage::Handshake { peer_id, version: _ } => {
|
||||||
Ok(node_id)
|
Ok(peer_id)
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
log!(ERROR, "Invalid response on Handshake");
|
log!(ERROR, "Invalid response on Handshake");
|
||||||
@ -150,25 +152,25 @@ impl NativeNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn bootstrap(&mut self) -> Result<(), ValidationError> {
|
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 mut stream = tokio::net::TcpStream::connect(SEED_NODES[0]).await.unwrap();
|
||||||
|
|
||||||
let id = uuid::Uuid::new_v4();
|
let id = uuid::Uuid::new_v4();
|
||||||
|
|
||||||
if let Ok(_) = NativeNode::send_handshake(id, &mut stream).await {
|
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();
|
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 {
|
if let Ok(response) = NativeNode::receive_message(&mut stream).await {
|
||||||
match response {
|
match response {
|
||||||
ProtocolMessage::BootstrapResponse { blocks } => {
|
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();
|
self.chain = core::Blockchain::build(blocks).unwrap();
|
||||||
Ok(())
|
Ok(())
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
log!(ERROR, "Invalid Response from BootstrapRequest: {:?}", &response);
|
self.log(msg!(ERROR, "Invalid Response from BootstrapRequest: {:?}", &response)).await;
|
||||||
Err(ValidationError::InvalidBlockHash)
|
Err(ValidationError::InvalidBlockHash)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -184,7 +186,7 @@ impl NativeNode {
|
|||||||
for (id, peer) in &self.tcp_peers {
|
for (id, peer) in &self.tcp_peers {
|
||||||
let message = ProtocolMessage::Transaction{peer_id: self.id, tx: tx.clone()};
|
let message = ProtocolMessage::Transaction{peer_id: self.id, tx: tx.clone()};
|
||||||
peer.sender.send(message).await.unwrap();
|
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()
|
block: block.clone()
|
||||||
};
|
};
|
||||||
peer.sender.send(message).await.unwrap();
|
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) {
|
pub async fn run_native(&mut self) {
|
||||||
|
|
||||||
if let Some(a) = self.addr {
|
if let Some(a) = self.addr {
|
||||||
@ -232,8 +238,13 @@ impl NativeNode {
|
|||||||
self.start_connection_listner(addr).await;
|
self.start_connection_listner(addr).await;
|
||||||
}
|
}
|
||||||
NodeCommand::ConnectToSeeds => {
|
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 } => {
|
NodeCommand::AddPeer { peer_id, addr, sender } => {
|
||||||
self.add_tcp_peer(peer_id, addr, sender);
|
self.add_tcp_peer(peer_id, addr, sender);
|
||||||
},
|
},
|
||||||
@ -248,27 +259,27 @@ impl NativeNode {
|
|||||||
self.broadcast_transaction(&tx).await;
|
self.broadcast_transaction(&tx).await;
|
||||||
},
|
},
|
||||||
NodeCommand::CreateBlock => {
|
NodeCommand::CreateBlock => {
|
||||||
log!(INFO, "Received CreateBlock Command");
|
self.log(msg!(INFO, "Received CreateBlock Command")).await;
|
||||||
let block = self.chain.create_block();
|
let block = self.chain.create_block();
|
||||||
self.broadcast_block(&block).await;
|
self.broadcast_block(&block).await;
|
||||||
},
|
},
|
||||||
NodeCommand::DebugListBlocks => {
|
NodeCommand::ListBlocks => {
|
||||||
log!(INFO, "Received DebugListBlocks command");
|
self.log(msg!(INFO, "Received DebugListBlocks command")).await;
|
||||||
self.chain.print_blocks();
|
self.chain.print_blocks();
|
||||||
},
|
},
|
||||||
NodeCommand::DebugListPeers => {
|
NodeCommand::ListPeers => {
|
||||||
log!(INFO, "Received DebugListPeers command");
|
self.log(msg!(INFO, "Received DebugListPeers command")).await;
|
||||||
self.list_peers();
|
self.list_peers();
|
||||||
},
|
},
|
||||||
NodeCommand::DebugShowId => {
|
NodeCommand::ShowId => {
|
||||||
log!(INFO, "Received DebugListBlocks command");
|
self.log(msg!(INFO, "Received DebugListBlocks command")).await;
|
||||||
self.show_id();
|
self.show_id();
|
||||||
},
|
},
|
||||||
NodeCommand::DebugDumpBlocks => {
|
NodeCommand::DumpBlocks(s) => {
|
||||||
// self.chain.dump_blocks(&mut self.db_file);
|
self.chain.dump_blocks(s);
|
||||||
}
|
}
|
||||||
NodeCommand::Exit => {
|
NodeCommand::Exit => {
|
||||||
log!(DEBUG, "Node Exit");
|
self.log(msg!(DEBUG, "Node Exit")).await;
|
||||||
break ;
|
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 tokio::sync::mpsc;
|
||||||
use vlogger::*;
|
use vlogger::*;
|
||||||
|
|
||||||
pub enum ExecutorCommand {
|
pub enum ExecutorCommand {
|
||||||
NodeResponse(String),
|
NodeResponse(String),
|
||||||
Echo(Vec<String>),
|
Echo(Vec<String>),
|
||||||
|
Print(String),
|
||||||
InvalidCommand(String),
|
InvalidCommand(String),
|
||||||
Node(NodeCommand),
|
Node(NodeCommand),
|
||||||
Clear(RenderPane),
|
Clear(RenderPane),
|
||||||
@ -28,14 +29,14 @@ impl Executor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn exit(&mut self) {
|
async fn exit(&mut self) {
|
||||||
log!(DEBUG, "Executor Exit");
|
self.render_string(msg!(DEBUG, "Executor Exit")).await;
|
||||||
self.exit = true
|
self.exit = true
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn listen(&mut self) {
|
async fn listen(&mut self) {
|
||||||
if let Some(cmd) = self.rx.recv().await {
|
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{
|
let rd_cmd = RenderCommand::RenderStringToPane{
|
||||||
str,
|
str,
|
||||||
pane: RenderPane::CliOutput
|
pane: RenderPane::CliOutput
|
||||||
@ -68,37 +69,39 @@ impl Executor {
|
|||||||
let _ = self.render_tx.send(rd_cmd);
|
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(" ");
|
let mut str = s.join(" ");
|
||||||
str.push_str("\n");
|
str.push_str("\n");
|
||||||
let rd_cmd = RenderCommand::RenderStringToPane{
|
let rd_cmd = RenderCommand::RenderStringToPane{
|
||||||
str,
|
str,
|
||||||
pane: RenderPane::CliOutput
|
pane: RenderPane::CliOutput
|
||||||
};
|
};
|
||||||
let _ = self.render_tx.send(rd_cmd);
|
let _ = self.render_tx.send(rd_cmd).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clear(&self, p: RenderPane) {
|
async fn clear(&self, p: RenderPane) {
|
||||||
let rd_cmd = RenderCommand::ClearPane(p);
|
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{
|
let rd_cmd = RenderCommand::RenderStringToPane{
|
||||||
str,
|
str,
|
||||||
pane: RenderPane::CliOutput
|
pane: RenderPane::CliOutput
|
||||||
};
|
};
|
||||||
let _ = self.render_tx.send(rd_cmd);
|
let _ = self.render_tx.send(rd_cmd).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn execute(&mut self, cmd: ExecutorCommand) {
|
async fn execute(&mut self, cmd: ExecutorCommand) {
|
||||||
match cmd {
|
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::Node(n) => self.handle_node_cmd(n).await,
|
||||||
ExecutorCommand::Clear(p) => self.clear(p),
|
ExecutorCommand::Clear(p) => self.clear(p).await,
|
||||||
ExecutorCommand::Echo(s) => self.echo(s),
|
ExecutorCommand::Echo(s) => self.echo(s).await,
|
||||||
ExecutorCommand::InvalidCommand(str) => self.invalid_command(str),
|
ExecutorCommand::Print(s) => self.render_string(s).await,
|
||||||
ExecutorCommand::Exit => self.exit(),
|
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::watcher::executor::ExecutorCommand;
|
||||||
|
|
||||||
use crate::native_node::node::NodeCommand;
|
|
||||||
use crate::watcher::executor::{ExecutorCommand};
|
|
||||||
use vlogger::*;
|
use vlogger::*;
|
||||||
|
use crate::cli::cli;
|
||||||
use crate::core;
|
|
||||||
|
|
||||||
use tokio::time::{timeout, Duration};
|
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;
|
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) {
|
async fn listen(&mut self) {
|
||||||
if let Ok(Some(mes)) = timeout(Duration::from_millis(400), self.rx.recv()).await {
|
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 {
|
match mes {
|
||||||
ParserCommand::ParseCmdString(s) => {
|
ParserCommand::ParseCmdString(s) => {
|
||||||
let s_split: Vec<&str> = s.split(" ").collect();
|
let argv: Vec<&str> = std::iter::once(" ")
|
||||||
|
.chain(s.split_whitespace())
|
||||||
if s_split.len() != 0 {
|
.collect();
|
||||||
let cmd = &s_split[0];
|
let cmd = cli(&argv);
|
||||||
let args = &s_split[1..];
|
let _ = self.exec_tx.send(cmd).await;
|
||||||
let exec_cmd = match *cmd {
|
},
|
||||||
CMD_NODE => {
|
//match *cmd {
|
||||||
if !args.is_empty() {
|
// CMD_NODE => { cli(&s_split) }
|
||||||
match args[0] {
|
// CMD_ECHO => {
|
||||||
"id" => {
|
// if args.is_empty() {
|
||||||
ExecutorCommand::Node(NodeCommand::DebugShowId)
|
// ExecutorCommand::InvalidCommand(msg!(ERROR, "print expects args"))
|
||||||
},
|
// } else {
|
||||||
"tx" => {
|
// ExecutorCommand::Echo(args.iter().map(|a| a.to_string()).collect())
|
||||||
if args.len() != 4 {
|
// }
|
||||||
log!(ERROR, "Invalid arg count! Expected {}, got {}", 4, args.len());
|
// }
|
||||||
}
|
// CMD_CLEAR => {
|
||||||
let from = args[0];
|
// if args.is_empty() {
|
||||||
let to = args[1];
|
// ExecutorCommand::Clear(RenderPane::All)
|
||||||
let value = args[2].parse::<u32>().unwrap();
|
// } else if args[0] == "in" {
|
||||||
let data = args[3];
|
// ExecutorCommand::Clear(RenderPane::CliInput)
|
||||||
|
// } else if args[0] == "out" {
|
||||||
let tx = core::Tx::new(
|
// ExecutorCommand::Clear(RenderPane::CliOutput)
|
||||||
from.to_string(),
|
// } else {
|
||||||
to.to_string(),
|
// ExecutorCommand::InvalidCommand(msg!(ERROR, "clear: Unknown arg {}", args[0]))
|
||||||
value,
|
// }
|
||||||
data.to_string()
|
// }
|
||||||
);
|
// _ => {
|
||||||
|
// ExecutorCommand::InvalidCommand(msg!(ERROR, "Unknown Command {cmd}"))
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ParserCommand::Exit => {
|
ParserCommand::Exit => {
|
||||||
log!(DEBUG, "Parser Exit");
|
self.exit().await;
|
||||||
self.exit();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -31,7 +31,7 @@ pub struct Pane {
|
|||||||
buffer: String,
|
buffer: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone, clap::ValueEnum)]
|
||||||
pub enum RenderPane {
|
pub enum RenderPane {
|
||||||
All,
|
All,
|
||||||
CliInput,
|
CliInput,
|
||||||
@ -200,13 +200,32 @@ impl Widget for &Renderer {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.border_set(border::THICK);
|
.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())
|
Paragraph::new(p.buffer.clone())
|
||||||
.wrap(Wrap::default())
|
.wrap(Wrap::default())
|
||||||
.left_aligned()
|
.left_aligned()
|
||||||
.block(block)
|
.block(block)
|
||||||
|
.scroll((scroll_offset as u16, 0))
|
||||||
.render(layout[p.layout_index as usize], buf);
|
.render(layout[p.layout_index as usize], buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,12 +1,13 @@
|
|||||||
use crate::watcher::*;
|
use crate::watcher::*;
|
||||||
|
|
||||||
use crossterm::{event::{self, Event, KeyCode, KeyEventKind}};
|
use crossterm::event::{self, Event, KeyCode, KeyEventKind};
|
||||||
use tokio::sync::mpsc;
|
use tokio::sync::mpsc;
|
||||||
use std::{io::{self}, net::SocketAddr};
|
use std::{io::{self}, net::SocketAddr};
|
||||||
|
|
||||||
use crate::{native_node::node::{NativeNode, NodeCommand}};
|
use crate::native_node::node::{NativeNode, NodeCommand};
|
||||||
use vlogger::*;
|
use vlogger::*;
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
pub struct Watcher {
|
pub struct Watcher {
|
||||||
render_tx: mpsc::Sender<RenderCommand>,
|
render_tx: mpsc::Sender<RenderCommand>,
|
||||||
parser_tx: mpsc::Sender<ParserCommand>,
|
parser_tx: mpsc::Sender<ParserCommand>,
|
||||||
@ -27,9 +28,11 @@ impl Watcher {
|
|||||||
WatcherBuilder::new()
|
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 };
|
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) {
|
pub async fn exit(self) {
|
||||||
@ -57,8 +60,8 @@ impl Watcher {
|
|||||||
KeyCode::Enter => {
|
KeyCode::Enter => {
|
||||||
let rd_mes = RenderCommand::RenderInput(k.code);
|
let rd_mes = RenderCommand::RenderInput(k.code);
|
||||||
let pr_mes = ParserCommand::ParseCmdString(self.cmd_buffer.clone());
|
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.parser_tx.send(pr_mes).await;
|
||||||
|
let _ = self.render_tx.send(rd_mes).await;
|
||||||
self.cmd_buffer.clear();
|
self.cmd_buffer.clear();
|
||||||
}
|
}
|
||||||
KeyCode::Esc => {
|
KeyCode::Esc => {
|
||||||
@ -96,9 +99,9 @@ impl WatcherBuilder {
|
|||||||
self
|
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 };
|
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 executor_handle = tokio::spawn({
|
||||||
let rend_tx = render_tx.clone();
|
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();
|
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 {
|
Watcher {
|
||||||
render_tx,
|
render_tx,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user