diff --git a/node/Cargo.lock b/node/Cargo.lock index 60c9cb1..1dce4d0 100644 --- a/node/Cargo.lock +++ b/node/Cargo.lock @@ -126,6 +126,12 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + [[package]] name = "bitflags" version = "2.9.3" @@ -151,22 +157,19 @@ dependencies = [ "clap", "crossterm 0.29.0", "hex", - "jemalloc", - "jemallocator", "memory-stats", "once_cell", "ratatui", "serde", "serde_json", "sha2", + "sled", "textwrap", "thiserror", "tokio", "tokio-tungstenite", "uuid", "vlogger", - "wasm-bindgen", - "web-sys", ] [[package]] @@ -175,6 +178,12 @@ version = "3.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + [[package]] name = "bytes" version = "1.10.1" @@ -318,16 +327,40 @@ dependencies = [ "libc", ] +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + [[package]] name = "crossterm" version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "829d955a0bb380ef178a640b91779e3987da38c9aea133b20614cfed8cdea9c6" dependencies = [ - "bitflags", + "bitflags 2.9.3", "crossterm_winapi", "mio", - "parking_lot", + "parking_lot 0.12.4", "rustix 0.38.44", "signal-hook", "signal-hook-mio", @@ -340,12 +373,12 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d8b9f2e4c67f833b660cdb0a3523065869fb35570177239812ed4c905aeff87b" dependencies = [ - "bitflags", + "bitflags 2.9.3", "crossterm_winapi", "derive_more", "document-features", "mio", - "parking_lot", + "parking_lot 0.12.4", "rustix 1.0.8", "signal-hook", "signal-hook-mio", @@ -486,6 +519,16 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" +[[package]] +name = "fs2" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "futures-core" version = "0.3.31" @@ -518,6 +561,15 @@ dependencies = [ "slab", ] +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + [[package]] name = "generic-array" version = "0.14.7" @@ -635,13 +687,22 @@ dependencies = [ "syn", ] +[[package]] +name = "instant" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" +dependencies = [ + "cfg-if", +] + [[package]] name = "io-uring" version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "046fa2d4d00aea763528b4950358d0ead425372445dc8ff86312b3c69ff7727b" dependencies = [ - "bitflags", + "bitflags 2.9.3", "cfg-if", "libc", ] @@ -667,35 +728,6 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" -[[package]] -name = "jemalloc" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd5927dc2630919333682c1757ed2d1518f510336096d0f43f0426a0f776f8e6" -dependencies = [ - "loca", -] - -[[package]] -name = "jemalloc-sys" -version = "0.5.4+5.3.0-patched" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac6c1946e1cea1788cbfde01c993b52a10e2da07f4bac608228d1bed20bfebf2" -dependencies = [ - "cc", - "libc", -] - -[[package]] -name = "jemallocator" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0de374a9f8e63150e6f5e8a60cc14c668226d7a347d8aee1a45766e3c4dd3bc" -dependencies = [ - "jemalloc-sys", - "libc", -] - [[package]] name = "js-sys" version = "0.3.77" @@ -730,15 +762,6 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f5e54036fe321fd421e10d732f155734c4e4afd610dd556d9a82833ab3ee0bed" -[[package]] -name = "loca" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "669389264b730a98e0d11713d0260f0ab363ad7e50ffc6d36db9c75bb7a5e527" -dependencies = [ - "ptr", -] - [[package]] name = "lock_api" version = "0.4.13" @@ -831,6 +854,17 @@ version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" +[[package]] +name = "parking_lot" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core 0.8.6", +] + [[package]] name = "parking_lot" version = "0.12.4" @@ -838,7 +872,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" dependencies = [ "lock_api", - "parking_lot_core", + "parking_lot_core 0.9.11", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" +dependencies = [ + "cfg-if", + "instant", + "libc", + "redox_syscall 0.2.16", + "smallvec", + "winapi", ] [[package]] @@ -849,7 +897,7 @@ checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" dependencies = [ "cfg-if", "libc", - "redox_syscall", + "redox_syscall 0.5.17", "smallvec", "windows-targets 0.52.6", ] @@ -890,12 +938,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "ptr" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76208293e44a44a702aa22f5cf40e2e55f4a6cd19953ddadb0b3f68e337d87ce" - [[package]] name = "quote" version = "1.0.40" @@ -946,7 +988,7 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eabd94c2f37801c20583fc49dd5cd6b0ba68c716787c2dd6ed18571e1e63117b" dependencies = [ - "bitflags", + "bitflags 2.9.3", "cassowary", "compact_str", "crossterm 0.28.1", @@ -961,13 +1003,22 @@ dependencies = [ "unicode-width 0.2.0", ] +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags 1.3.2", +] + [[package]] name = "redox_syscall" version = "0.5.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77" dependencies = [ - "bitflags", + "bitflags 2.9.3", ] [[package]] @@ -982,7 +1033,7 @@ version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ - "bitflags", + "bitflags 2.9.3", "errno", "libc", "linux-raw-sys 0.4.15", @@ -995,7 +1046,7 @@ version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "11181fbabf243db407ef8df94a6ce0b2f9a733bd8be4ad02b4eda9602296cac8" dependencies = [ - "bitflags", + "bitflags 2.9.3", "errno", "libc", "linux-raw-sys 0.9.4", @@ -1116,6 +1167,22 @@ version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" +[[package]] +name = "sled" +version = "0.34.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f96b4737c2ce5987354855aed3797279def4ebf734436c6aa4552cf8e169935" +dependencies = [ + "crc32fast", + "crossbeam-epoch", + "crossbeam-utils", + "fs2", + "fxhash", + "libc", + "log", + "parking_lot 0.11.2", +] + [[package]] name = "smallvec" version = "1.15.1" @@ -1225,9 +1292,7 @@ dependencies = [ "io-uring", "libc", "mio", - "parking_lot", "pin-project-lite", - "signal-hook-registry", "slab", "socket2", "tokio-macros", @@ -1431,16 +1496,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "web-sys" -version = "0.3.77" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - [[package]] name = "winapi" version = "0.3.9" @@ -1684,7 +1739,7 @@ version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" dependencies = [ - "bitflags", + "bitflags 2.9.3", ] [[package]] diff --git a/node/Cargo.toml b/node/Cargo.toml index 511cec9..66a4c45 100644 --- a/node/Cargo.toml +++ b/node/Cargo.toml @@ -11,11 +11,9 @@ serde = { version = "1.0.219", features = ["derive"] } serde_json = "1.0.143" sha2 = "0.10.9" thiserror = "2.0.16" -tokio = { version = "1.47.1", features = ["full"] } +tokio = { version = "1.47.1", features = ["rt-multi-thread", "net", "sync", "time", "macros"] } tokio-tungstenite = "0.27.0" uuid = { version = "1.18.0", features = ["v4", "serde"] } -wasm-bindgen = "0.2.100" -web-sys = { version = "0.3.77", features = ["WebSocket"] } vlogger = { path = "./lib/logger-rs" } ratatui = "0.29.0" crossterm = "0.29.0" @@ -23,6 +21,7 @@ once_cell = "1.21.3" async-trait = "0.1.89" anyhow = "1.0.99" memory-stats = "1.2.0" -jemalloc = "0.3.0" -jemallocator = "0.5.4" +# jemalloc = "0.3.0" +# jemallocator = "0.5.4" textwrap = "0.16.2" +sled = "0.34.7" diff --git a/node/database/genesis.json b/node/database/genesis.json deleted file mode 100644 index 2f570ee..0000000 --- a/node/database/genesis.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "genesis_time": "2019-03-18T00:00:00.000000000Z", - "chain_id": "the-blockchain-bar-ledger", - "balances": { - "andrej": 1000000 - } -} diff --git a/node/database/state.json b/node/database/state.json deleted file mode 100644 index 2a93c6a..0000000 --- a/node/database/state.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "balances": { - "andrej": 998801 - } -} diff --git a/node/database/tx.db b/node/database/tx.db deleted file mode 100644 index 34eb4c5..0000000 --- a/node/database/tx.db +++ /dev/null @@ -1,31 +0,0 @@ -[ - { - "head": { - "previous_hash": "", - "timestamp": 1756502951, - "merkle_root": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", - "block_hash": "04e5cdf592f6ab35dccdc41add80568c0de8be60609f5f9053cbe0d156fb8ea0", - "nonce": 6 - }, - "data": [] - }, - { - "head": { - "previous_hash": "04e5cdf592f6ab35dccdc41add80568c0de8be60609f5f9053cbe0d156fb8ea0", - "timestamp": 1756503577, - "merkle_root": "3f99805580f3b4bbd1a903180d2057cfd7dace97d820d7170ffd83c95ce3852c", - "block_hash": "0655c8ab80aeda9ed1db6e72ec48cdf9d9c7799356b11519979f3d7dbce57677", - "nonce": 7 - }, - "data": [ - { - "Transaction": { - "from": "victor", - "to": "pia", - "value": 500, - "data": "almosen" - } - } - ] - } -] \ No newline at end of file diff --git a/node/proc/09:09:13_6977 b/node/proc/09:09:13_6977 new file mode 100644 index 0000000..2021aaf --- /dev/null +++ b/node/proc/09:09:13_6977 @@ -0,0 +1,4 @@ +[INFO ] [watcher.rs :60 ] 09:09:43: Physical memory usage: 9 MB +[INFO ] [watcher.rs :61 ] 09:09:43: Virtual memory usage: 1066 MB +[INFO ] [watcher.rs :60 ] 09:10:13: Physical memory usage: 9 MB +[INFO ] [watcher.rs :61 ] 09:10:13: Virtual memory usage: 1066 MB diff --git a/node/proc/09:12:45_7340 b/node/proc/09:12:45_7340 new file mode 100644 index 0000000..a27cf7e --- /dev/null +++ b/node/proc/09:12:45_7340 @@ -0,0 +1,30 @@ +[INFO ] [watcher.rs :60 ] 09:12:55: Physical memory usage: 5 MB +[INFO ] [watcher.rs :61 ] 09:12:55: Virtual memory usage: 1062 MB +[INFO ] [watcher.rs :60 ] 09:13:05: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:13:05: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:13:15: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:13:15: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:13:25: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:13:25: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:13:35: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:13:35: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:13:45: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:13:45: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:13:55: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:13:55: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:14:05: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:14:05: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:14:15: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:14:15: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:14:25: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:14:25: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:14:35: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:14:35: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:14:45: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:14:45: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:14:55: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:14:55: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:15:05: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:15:05: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:15:15: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:15:15: Virtual memory usage: 1063 MB diff --git a/node/proc/09:15:49_17386 b/node/proc/09:15:49_17386 new file mode 100644 index 0000000..b9311fd --- /dev/null +++ b/node/proc/09:15:49_17386 @@ -0,0 +1,410 @@ +[INFO ] [watcher.rs :60 ] 09:15:59: Physical memory usage: 5 MB +[INFO ] [watcher.rs :61 ] 09:15:59: Virtual memory usage: 1062 MB +[INFO ] [watcher.rs :60 ] 09:16:09: Physical memory usage: 5 MB +[INFO ] [watcher.rs :61 ] 09:16:09: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:16:19: Physical memory usage: 5 MB +[INFO ] [watcher.rs :61 ] 09:16:19: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:16:29: Physical memory usage: 5 MB +[INFO ] [watcher.rs :61 ] 09:16:29: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:16:39: Physical memory usage: 5 MB +[INFO ] [watcher.rs :61 ] 09:16:39: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:16:49: Physical memory usage: 5 MB +[INFO ] [watcher.rs :61 ] 09:16:49: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:16:59: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:16:59: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:17:09: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:17:09: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:17:19: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:17:19: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:17:29: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:17:29: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:17:39: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:17:39: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:17:49: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:17:49: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:17:59: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:17:59: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:18:09: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:18:09: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:18:19: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:18:19: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:18:29: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:18:29: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:18:39: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:18:39: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:18:49: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:18:49: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:18:59: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:18:59: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:19:09: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:19:09: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:19:19: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:19:19: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:19:29: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:19:29: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:19:39: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:19:39: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:19:49: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:19:49: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:19:59: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:19:59: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:20:09: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:20:09: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:20:19: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:20:19: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:20:29: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:20:29: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:20:39: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:20:39: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:20:49: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:20:49: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:20:59: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:20:59: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:21:09: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:21:09: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:21:19: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:21:19: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:21:29: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:21:29: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:21:39: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:21:39: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:21:49: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:21:49: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:21:59: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:21:59: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:22:09: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:22:09: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:22:19: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:22:19: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:22:29: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:22:29: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:22:39: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:22:39: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:22:49: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:22:49: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:22:59: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:22:59: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:23:09: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:23:09: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:23:19: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:23:19: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:23:29: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:23:29: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:23:39: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:23:39: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:23:49: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:23:49: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:23:59: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:23:59: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:24:09: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:24:09: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:24:19: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:24:19: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:24:29: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:24:29: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:24:39: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:24:39: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:24:49: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:24:49: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:24:59: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:24:59: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:25:09: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:25:09: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:25:19: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:25:19: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:25:29: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:25:29: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:25:39: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:25:39: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:25:49: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:25:49: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:25:59: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:25:59: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:26:09: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:26:09: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:26:19: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:26:19: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:26:29: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:26:29: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:26:39: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:26:39: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:26:49: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:26:49: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:26:59: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:26:59: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:27:09: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:27:09: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:27:19: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:27:19: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:27:29: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:27:29: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:27:39: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:27:39: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:27:49: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:27:49: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:27:59: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:27:59: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:28:09: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:28:09: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:28:19: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:28:19: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:28:29: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:28:29: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:28:39: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:28:39: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:28:49: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:28:49: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:28:59: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:28:59: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:29:09: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:29:09: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:29:19: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:29:19: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:29:29: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:29:29: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:29:39: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:29:39: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:29:49: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:29:49: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:29:59: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:29:59: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:30:09: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:30:09: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:30:19: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:30:19: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:30:29: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:30:29: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:30:39: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:30:39: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:30:49: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:30:49: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:30:59: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:30:59: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:31:09: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:31:09: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:31:19: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:31:19: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:31:29: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:31:29: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:31:39: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:31:39: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:31:49: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:31:49: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:31:59: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:31:59: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:32:09: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:32:09: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:32:19: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:32:19: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:32:29: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:32:29: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:32:39: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:32:39: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:32:49: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:32:49: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:32:59: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:32:59: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:33:09: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:33:09: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:33:19: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:33:19: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:33:29: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:33:29: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:33:39: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:33:39: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:33:49: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:33:49: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:33:59: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:33:59: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:34:09: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:34:09: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:34:19: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:34:19: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:34:29: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:34:29: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:34:39: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:34:39: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:34:49: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:34:49: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:34:59: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:34:59: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:35:09: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:35:09: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:35:19: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:35:19: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:35:29: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:35:29: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:35:39: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:35:39: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:35:49: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:35:49: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:35:59: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:35:59: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:36:09: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:36:09: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:36:19: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:36:19: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:36:29: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:36:29: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:36:39: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:36:39: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:36:49: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:36:49: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:36:59: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:36:59: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:37:09: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:37:09: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:37:19: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:37:19: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:37:29: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:37:29: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:37:39: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:37:39: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:37:49: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:37:49: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:37:59: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:37:59: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:38:09: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:38:09: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:38:19: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:38:19: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:38:29: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:38:29: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:38:39: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:38:39: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:38:49: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:38:49: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:38:59: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:38:59: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:39:09: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:39:09: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:39:19: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:39:19: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:39:29: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:39:29: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:39:39: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:39:39: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:39:49: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:39:49: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:39:59: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:39:59: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:40:09: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:40:09: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:40:19: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:40:19: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:40:29: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:40:29: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:40:39: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:40:39: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:40:49: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:40:49: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:40:59: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:40:59: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:41:09: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:41:09: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:41:19: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:41:19: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:41:29: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:41:29: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:41:39: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:41:39: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:41:49: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:41:49: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:41:59: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:41:59: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:42:09: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:42:09: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:42:19: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:42:19: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:42:29: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:42:29: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:42:39: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:42:39: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:42:49: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:42:49: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:42:59: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:42:59: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:43:09: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:43:09: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:43:19: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:43:19: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:43:29: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:43:29: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:43:39: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:43:39: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:43:49: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:43:49: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:43:59: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:43:59: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:44:09: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:44:09: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:44:19: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:44:19: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:44:29: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:44:29: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:44:39: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:44:39: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:44:49: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:44:49: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:44:59: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:44:59: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:45:09: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:45:09: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:45:19: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:45:19: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:45:29: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:45:29: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:45:39: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:45:39: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:45:49: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:45:49: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:45:59: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:45:59: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:46:09: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:46:09: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:46:19: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:46:19: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:46:29: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:46:29: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:46:39: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:46:39: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:46:49: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:46:49: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:46:59: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:46:59: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:47:09: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:47:09: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:47:19: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:47:19: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:47:29: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:47:29: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:47:39: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:47:39: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:47:49: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:47:49: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:47:59: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:47:59: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:48:10: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:48:10: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:48:20: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:48:20: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:48:30: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:48:30: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:48:40: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:48:40: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:48:50: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:48:50: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:49:00: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:49:00: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:49:10: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:49:10: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:49:20: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:49:20: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:49:30: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:49:30: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:49:40: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:49:40: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:49:50: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:49:50: Virtual memory usage: 1063 MB +[INFO ] [watcher.rs :60 ] 09:50:00: Physical memory usage: 6 MB +[INFO ] [watcher.rs :61 ] 09:50:00: Virtual memory usage: 1063 MB diff --git a/node/src/api/server.rs b/node/src/api/server.rs new file mode 100644 index 0000000..e69de29 diff --git a/node/src/args.rs b/node/src/args.rs index a60a860..cde4581 100644 --- a/node/src/args.rs +++ b/node/src/args.rs @@ -1,180 +1,171 @@ use std::net::SocketAddr; -use clap::{Parser, Subcommand}; use crate::core; use crate::watcher::{RenderLayoutKind, RenderPane}; - +use clap::{Parser, Subcommand}; use clap::*; #[derive(Parser)] pub struct Cli { - #[command(subcommand)] - pub command: CliCommand + #[command(subcommand)] + pub command: CliCommand, } - #[derive(Subcommand)] -pub enum CliCommand{ - #[command(name = "ping")] - Ping{ - #[command(subcommand)] - ping_cmd: CliPingCommand - }, +pub enum CliCommand { + #[command(name = "ping")] + Ping { + #[command(subcommand)] + ping_cmd: CliPingCommand, + }, - /// Peer related Cmd - #[command(name = "peer")] - Peer { - #[command(subcommand)] - peer_cmd: CliPeerCommand - }, + /// Peer related Cmd + #[command(name = "peer")] + Peer { + #[command(subcommand)] + peer_cmd: CliPeerCommand, + }, - /// Block related Cmd - #[command(name = "block")] - Block { - #[command(subcommand)] - block_cmd: CliBlockCommand - }, + /// Block related Cmd + #[command(name = "block")] + Block { + #[command(subcommand)] + block_cmd: CliBlockCommand, + }, - /// Make a Transaction - #[command(name = "tx")] - Transaction(core::Tx), + /// Make a Transaction + #[command(name = "tx")] + Transaction(core::Tx), - /// Start new TcpListner on Addr - #[command(name = "listen")] - StartListner{addr: String}, + /// Start new TcpListner on Addr + #[command(name = "listen")] + StartListner { addr: String }, - /// Display Node id - #[command(name = "id")] - DebugShowId, + /// Display Node id + #[command(name = "id")] + DebugShowId, - /// Connect to Seed Nodes - #[command(name = "seed")] - Seeds { - #[command(subcommand)] - seed_cmd: CliSeedCommand - }, + /// Connect to Seed Nodes + #[command(name = "seed")] + Seeds { + #[command(subcommand)] + seed_cmd: CliSeedCommand, + }, - /// Clear Pane - #[command(name = "clear", aliases = ["c"])] - Clear{ - pane: RenderPane - }, + /// Clear Pane + #[command(name = "clear", aliases = ["c"])] + Clear { pane: RenderPane }, - #[command(name = "layout", aliases = ["lay"])] - Layout { - mode: RenderLayoutKind - } + #[command(name = "layout", aliases = ["lay"])] + Layout { mode: RenderLayoutKind }, } #[derive(Subcommand)] pub enum CliPeerCommand { - /// Connect To Peer With IpAddr - #[command(name = "connect", aliases = ["c", "con"])] - Connect{addr: String}, + /// 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, + /// 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 + /// 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, + /// List Blocks in Chain + #[command(name = "list", aliases = ["ls", "l"])] + List, - /// Create and Broadcast new Block - #[command(name = "create", aliases = ["c", "new"])] - Create, + /// 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 - } + /// Export Blocks to file + #[command(name = "dump", aliases = ["export"])] + Dump { + /// Output file + #[arg(short, long)] + output: String, + }, } #[derive(Subcommand)] pub enum CliPingCommand { + /// Ping Peer by Id + #[command(name = "id", aliases = ["i"])] + Id { + #[arg(short, long)] + id: String, + }, - /// Ping Peer by Id - #[command(name = "id", aliases = ["i"])] - Id { - #[arg(short, long)] - id: String - }, - - /// Ping Peer by Address - #[command(name = "addr", aliases = ["a", "ad"])] - Addr { - #[arg(short, long)] - addr: String - } + /// Ping Peer by Address + #[command(name = "addr", aliases = ["a", "ad"])] + Addr { + #[arg(short, long)] + addr: 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 { -} +#[command( + long_about = "A comprehensive CLI tool for managing blockchain nodes, peers, and transactions" +)] +pub enum CliNodeCommand {} #[derive(Parser, Debug)] #[command(version, about, long_about = None)] pub struct CliArgs { - /// Provide address on which node will listen - #[arg(short = 'a', long)] - pub addr: Option, + /// Provide address on which node will listen + #[arg(short = 'a', long)] + pub addr: Option, - /// Provide File with current chain - #[arg(short = 'f', long)] - pub seed_file: Option, + /// Provide File with current chain + #[arg(short = 'd', long)] + pub database: Option, - /// Enable bootstrap mode (alternative syntax) - #[arg(short = 'b', long = "bootstrap", action = clap::ArgAction::SetTrue)] - pub bootstrap: bool, + /// Enable bootstrap mode (alternative syntax) + #[arg(short = 'b', long = "bootstrap", action = clap::ArgAction::SetTrue)] + pub bootstrap: bool, - /// Enable debug mode (alternative syntax) - #[arg(short = 'd', long = "debug", action = clap::ArgAction::SetTrue)] - pub debug: bool, + /// Enable debug mode (alternative syntax) + #[arg(long = "debug", action = clap::ArgAction::SetTrue)] + pub debug: bool, - /// Enable rendering (alternative syntax) - #[arg(short = 'r', long = "render", action = clap::ArgAction::Set, default_value = "true")] - pub render: bool, + /// Enable rendering (alternative syntax) + #[arg(short = 'r', long = "render", action = clap::ArgAction::Set, default_value = "true")] + pub render: bool, - /// Enable debug mode (alternative syntax) - #[arg(short = 's', long = "seed", action = clap::ArgAction::SetTrue)] - pub seed: bool, + /// Enable debug mode (alternative syntax) + #[arg(short = 's', long = "seed", action = clap::ArgAction::SetTrue)] + pub seed: bool, } #[derive(Subcommand, Debug)] -pub enum Commands { -} +pub enum Commands {} #[derive(Subcommand, Debug)] pub enum TxCmd { - /// Add a new transaction to the DB - #[command(short_flag = 'a')] - Add(core::Tx) + /// Add a new transaction to the DB + #[command(short_flag = 'a')] + Add(core::Tx), } pub fn get_args() -> CliArgs { - CliArgs::parse() + CliArgs::parse() } diff --git a/node/src/bus/event_bus.rs b/node/src/bus/event_bus.rs new file mode 100644 index 0000000..d929a1d --- /dev/null +++ b/node/src/bus/event_bus.rs @@ -0,0 +1,29 @@ +use tokio::sync::broadcast; + +pub struct EventBus +where + T: Clone + std::fmt::Debug, +{ + sender: broadcast::Sender, + _receiver: broadcast::Receiver, +} + +impl EventBus { + pub fn new() -> Self { + let (sender, receiver) = broadcast::channel(1000); + Self { + sender, + _receiver: receiver, + } + } + + pub fn publish(&self, event: T) { + if let Err(e) = self.sender.send(event) { + eprintln!("{e}") + } + } + + pub fn subscribe(&self) -> broadcast::Receiver { + self.sender.subscribe() + } +} diff --git a/node/src/bus/executor.rs b/node/src/bus/executor.rs new file mode 100644 index 0000000..f68b8a1 --- /dev/null +++ b/node/src/bus/executor.rs @@ -0,0 +1,17 @@ +use once_cell::sync::Lazy; +use std::sync::Arc; +use tokio::sync::broadcast; + +use super::event_bus::EventBus; +use crate::watcher::ExecutorCommand; + +static EXECUTOR_EVENT_BUS: Lazy>> = + Lazy::new(|| Arc::new(EventBus::new())); + +pub fn publish_executor_event(event: ExecutorCommand) { + EXECUTOR_EVENT_BUS.publish(event); +} + +pub fn subscribe_executor_event() -> broadcast::Receiver { + EXECUTOR_EVENT_BUS.subscribe() +} diff --git a/node/src/bus/network.rs b/node/src/bus/network.rs new file mode 100644 index 0000000..2f9fb2d --- /dev/null +++ b/node/src/bus/network.rs @@ -0,0 +1,25 @@ +use once_cell::sync::Lazy; +use std::sync::Arc; +use tokio::sync::broadcast; + +use super::event_bus::EventBus; + +#[derive(Clone, Debug)] +pub enum NetworkEvent { + SeedConnected(String), + SeedDisconnected(String), + AllSeedsConnected, + BootstrapCompleted, + NodeReady, +} + +static NETWORK_EVENT_BUS: Lazy>> = + Lazy::new(|| Arc::new(EventBus::new())); + +pub fn publish_network_event(event: NetworkEvent) { + NETWORK_EVENT_BUS.publish(event); +} + +pub fn subscribe_network_event() -> broadcast::Receiver { + NETWORK_EVENT_BUS.subscribe() +} diff --git a/node/src/bus/render.rs b/node/src/bus/render.rs new file mode 100644 index 0000000..8a5af82 --- /dev/null +++ b/node/src/bus/render.rs @@ -0,0 +1,17 @@ +use once_cell::sync::Lazy; +use std::sync::Arc; +use tokio::sync::broadcast; + +use super::event_bus::EventBus; +use crate::watcher::renderer::RenderCommand; + +static RENDER_CHANNEL: Lazy>> = Lazy::new(|| Arc::new(EventBus::new())); +pub fn publish_render_event(event: RenderCommand) { + RENDER_CHANNEL.publish(event); +} + +pub fn subscribe_render_event() -> broadcast::Receiver { + RENDER_CHANNEL.subscribe() + + +} diff --git a/node/src/bus/system.rs b/node/src/bus/system.rs new file mode 100644 index 0000000..c36fb56 --- /dev/null +++ b/node/src/bus/system.rs @@ -0,0 +1,23 @@ +use once_cell::sync::Lazy; +use std::sync::Arc; +use tokio::sync::broadcast; + +use super::event_bus::EventBus; + +#[derive(Clone, Debug)] +pub enum SystemEvent { + ExecutorStarted, + RendererStarted, + NodeStarted, + Exit, +} + +static SYSTEM_EVENT_BUS: Lazy>> = Lazy::new(|| Arc::new(EventBus::new())); + +pub fn publish_system_event(event: SystemEvent) { + SYSTEM_EVENT_BUS.publish(event); +} + +pub fn subscribe_system_event() -> broadcast::Receiver { + SYSTEM_EVENT_BUS.subscribe() +} diff --git a/node/src/cli.rs b/node/src/cli.rs index 7bb5606..41b5330 100644 --- a/node/src/cli.rs +++ b/node/src/cli.rs @@ -1,54 +1,61 @@ use crate::args::*; use crate::core::NetworkData; -use crate::event_bus::publish_render_event; -use crate::native_node::node::*; +use crate::node::*; +use crate::watcher::{RenderCommand, ExecutorCommand}; use clap::Parser; -use crate::watcher::{ExecutorCommand, RenderCommand}; pub fn handle_peer_command(cmd: CliPeerCommand) -> NodeCommand { - match cmd { - CliPeerCommand::List => NodeCommand::ListPeers, - CliPeerCommand::Remove { id } => NodeCommand::RemovePeer{ peer_id: id.parse::().unwrap() }, - CliPeerCommand::Connect { addr } => NodeCommand::ConnectTcpPeer(addr), - } + match cmd { + CliPeerCommand::List => NodeCommand::ListPeers, + CliPeerCommand::Remove { id } => NodeCommand::RemovePeer { + peer_id: id.parse::().unwrap(), + }, + CliPeerCommand::Connect { addr } => NodeCommand::ConnectTcpPeer(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, - } + 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 - } + match cmd { + CliSeedCommand::Connect => NodeCommand::ConnectToSeeds, + } } fn handle_ping(cmd: CliPingCommand) -> NodeCommand { - match cmd { - CliPingCommand::Id {id} => NodeCommand::PingId(id), - CliPingCommand::Addr {addr} => NodeCommand::PingAddr(addr) - } + match cmd { + CliPingCommand::Id { id } => NodeCommand::PingId(id), + CliPingCommand::Addr { addr } => NodeCommand::PingAddr(addr), + } } pub fn cli(input: &[&str]) -> ExecutorCommand { - match Cli::try_parse_from(input) { - Ok(cmd) => match cmd.command { - CliCommand::Layout { mode } => ExecutorCommand::Render(RenderCommand::ChangeLayout(mode)), - CliCommand::Clear { pane } => ExecutorCommand::Render(RenderCommand::ClearPane(pane)), - CliCommand::Peer { peer_cmd } => ExecutorCommand::Node(handle_peer_command(peer_cmd)), - CliCommand::Block { block_cmd } => ExecutorCommand::Node(handle_block_command(block_cmd)), - CliCommand::Transaction(tx)=> ExecutorCommand::Node(NodeCommand::ProcessNetworkData(NetworkData::Transaction(tx))), - CliCommand::DebugShowId => ExecutorCommand::Node(NodeCommand::ShowId), - CliCommand::StartListner { addr } => { - ExecutorCommand::Node(NodeCommand::StartListner(addr.parse().unwrap())) - }, - CliCommand::Seeds { seed_cmd } => ExecutorCommand::Node(handle_seed_command(seed_cmd)), - CliCommand::Ping { ping_cmd } => ExecutorCommand::Node(handle_ping(ping_cmd)) + match Cli::try_parse_from(input) { + Ok(cmd) => match cmd.command { + CliCommand::Layout { mode } => { + ExecutorCommand::Render(RenderCommand::ChangeLayout(mode)) + } + CliCommand::Clear { pane } => ExecutorCommand::Render(RenderCommand::ClearPane(pane)), + CliCommand::Peer { peer_cmd } => ExecutorCommand::Node(handle_peer_command(peer_cmd)), + CliCommand::Block { block_cmd } => { + ExecutorCommand::Node(handle_block_command(block_cmd)) + } + CliCommand::Transaction(tx) => ExecutorCommand::Node(NodeCommand::ProcessNetworkData( + NetworkData::Transaction(tx), + )), + CliCommand::DebugShowId => ExecutorCommand::Node(NodeCommand::ShowId), + CliCommand::StartListner { addr } => { + ExecutorCommand::Node(NodeCommand::StartListner(addr.parse().unwrap())) + } + CliCommand::Seeds { seed_cmd } => ExecutorCommand::Node(handle_seed_command(seed_cmd)), + CliCommand::Ping { ping_cmd } => ExecutorCommand::Node(handle_ping(ping_cmd)), + }, + Err(e) => ExecutorCommand::InvalidCommand(format!("{e}")), } - Err(e) => ExecutorCommand::InvalidCommand(format!("{e}")) - } } diff --git a/node/src/core/block.rs b/node/src/core/block.rs index bbe0feb..894d2f4 100644 --- a/node/src/core/block.rs +++ b/node/src/core/block.rs @@ -6,13 +6,14 @@ pub struct BlockHeader { pub timestamp: u64, pub merkle_root: String, pub block_hash: String, - pub nonce: u32 + pub nonce: u32, + pub height: u64, } #[derive(Clone, Debug, serde::Deserialize, serde::Serialize, Default)] pub struct Block { pub head: BlockHeader, - pub data: Vec + pub data: Vec, } impl BlockHeader { diff --git a/node/src/core/blockchain.rs b/node/src/core/blockchain.rs index 340b238..78aad1c 100644 --- a/node/src/core/blockchain.rs +++ b/node/src/core/blockchain.rs @@ -1,13 +1,13 @@ use sha2::Digest; use sha2::Sha256; -use vlogger::*; use crate::core::NetworkData; use crate::error::print_error_chain; use crate::log; +use vlogger::*; use crate::core; -use crate::error::{ BlockchainError, TxError }; +use crate::error::{BlockchainError, TxError}; use std::collections::HashMap; use std::io::Write; use std::time::UNIX_EPOCH; @@ -18,265 +18,273 @@ pub type Account = String; #[derive(Debug, thiserror::Error)] pub enum ValidationError { - #[error("Invalid Block Hash Detected")] - InvalidBlockHash, - #[error("Previous Block Hash doesn't match")] - InvalidPreviousBlockHash, - #[error("Invalid Block JSON: {0}")] - InvalidBlockJson(#[from] serde_json::Error) + #[error("Invalid Block Hash Detected")] + InvalidBlockHash, + #[error("Previous Block Hash doesn't match")] + InvalidPreviousBlockHash, + #[error("Invalid Block JSON: {0}")] + InvalidBlockJson(#[from] serde_json::Error), } #[allow(dead_code)] #[derive(Debug, Default)] pub struct Blockchain { - id: String, - balances: std::collections::HashMap, - blocks: Vec, - mempool: Vec, + id: String, + balances: std::collections::HashMap, + mempool: Vec, } #[allow(dead_code)] impl Blockchain { - pub fn add(&mut self, data: NetworkData) -> Result<(), BlockchainError> { - self.apply(data.clone())?; - self.mempool.push(data); - Ok(()) - } - - pub fn hash_network_data(data: &NetworkData) -> String { - match data { - NetworkData::Transaction(tx) => Self::hash_transaction(tx) - } - } - - 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 { - 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: &[NetworkData]) -> String { - let tx_hashes: Vec = tx - .iter() - .map(|tx| Blockchain::hash_network_data(tx)) - .collect(); - - if tx_hashes.is_empty() { - return Blockchain::hash_data(""); - } - - 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(); - } - - 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.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.mempool.clone()); - self.blocks.push(new_block); - self.blocks.last().unwrap().clone() - } - - fn apply_transaction(&mut self, tx: &core::Tx) -> Result<(), BlockchainError> { - tx.validate()?; - return Ok(()); - 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 self.acc_exists(tx.to()) { - *self.balances.get_mut(tx.to()).unwrap() += tx.value(); - } else { - self.balances.insert(tx.to().clone(), tx.value()); - } - } - Ok(()) - } - - pub fn apply(&mut self, data: NetworkData) -> Result<(), BlockchainError> { - match &data { - NetworkData::Transaction(tx) => { - self.apply_transaction(tx)?; + pub fn add(&mut self, data: NetworkData) -> Result<(), BlockchainError> { + self.apply(data.clone())?; self.mempool.push(data); - } + Ok(()) } - Ok(()) - } - pub fn new(balances: HashMap, blocks: Vec, mempool: Vec) -> Blockchain { - return Self { - id: BLOCKCHAIN_ID.to_string(), - balances, - blocks, - mempool + pub fn hash_network_data(data: &NetworkData) -> String { + match data { + NetworkData::Transaction(tx) => Self::hash_transaction(tx), + } } - } + 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 { + 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: &[NetworkData]) -> String { + let tx_hashes: Vec = tx + .iter() + .map(|tx| Blockchain::hash_network_data(tx)) + .collect(); + + if tx_hashes.is_empty() { + return Blockchain::hash_data(""); + } + + 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(); + } + + 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.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, + height: self.blocks().len() as u64 + 1, + 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.mempool.clone()); + self.blocks.push(new_block); + self.blocks.last().unwrap().clone() + } + + fn apply_transaction(&mut self, tx: &core::Tx) -> Result<(), BlockchainError> { + tx.validate()?; + return Ok(()); + 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 self.acc_exists(tx.to()) { + *self.balances.get_mut(tx.to()).unwrap() += tx.value(); + } else { + self.balances.insert(tx.to().clone(), tx.value()); + } + } + Ok(()) + } + + pub fn apply(&mut self, data: NetworkData) -> Result<(), BlockchainError> { + match &data { + NetworkData::Transaction(tx) => { + self.apply_transaction(tx)?; + self.mempool.push(data); + } + } + Ok(()) + } + + pub fn new(balances: HashMap, mempool: Vec) -> Blockchain { + return Self { + id: BLOCKCHAIN_ID.to_string(), + balances, + 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 list_blocks(&self) -> String { - let mut ret = String::from("Blocks List\n-------------------\n"); - for (i, b) in self.blocks.iter().enumerate() { - ret.push_str(format!("Block Hash #{i}: {}\n", b.head.block_hash()).as_str()) + pub fn list_blocks(&self) -> String { + let mut ret = String::from("Blocks List\n-------------------\n"); + for (i, b) in self.blocks.iter().enumerate() { + ret.push_str(format!("Block Hash #{i}: {}\n", b.head.block_hash()).as_str()) + } + ret } - ret - } - pub fn get_balances(&self) -> &std::collections::HashMap { - &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(msg!(ERROR, "Invalid Block Hash")), - ValidationError::InvalidPreviousBlockHash => log(msg!(ERROR, "Invalid Previos Block Hash")), - ValidationError::InvalidBlockJson(e) => print_error_chain(e.into()), - } + pub fn get_balances(&self) -> &std::collections::HashMap { + &self.balances } - } - 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 blocks(&self) -> &[core::Block] { + &self.blocks } - 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>{ - 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) - } + 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(msg!(ERROR, "Invalid Block Hash")), + ValidationError::InvalidPreviousBlockHash => { + log(msg!(ERROR, "Invalid Previos Block Hash")) + } + ValidationError::InvalidBlockJson(e) => print_error_chain(e.into()), + }, + } } - Ok(()) - } - pub fn build(blocks: &str) -> Result { - match serde_json::from_str::>(&blocks) { - Ok(blocks) => { - let chain = Blockchain { - blocks, - balances: HashMap::new(), - mempool: vec![], - id: BLOCKCHAIN_ID.to_string(), - }; - chain.validate_chain()?; - Ok(chain) - } - Err(e) => { - Err(ValidationError::InvalidBlockJson(e)) - } + 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> { + 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(()) + } + + pub fn build(blocks: &str) -> Result { + match serde_json::from_str::>(&blocks) { + Ok(blocks) => { + let chain = Blockchain { + blocks, + balances: HashMap::new(), + mempool: vec![], + id: BLOCKCHAIN_ID.to_string(), + }; + chain.validate_chain()?; + Ok(chain) + } + Err(e) => Err(ValidationError::InvalidBlockJson(e)), + } } - } } diff --git a/node/src/core/data.rs b/node/src/core/data.rs index b1fc0ae..4c3e651 100644 --- a/node/src/core/data.rs +++ b/node/src/core/data.rs @@ -2,5 +2,5 @@ use super::Tx; #[derive(serde::Deserialize, serde::Serialize, Debug, Clone)] pub enum NetworkData { - Transaction(Tx) + Transaction(Tx), } diff --git a/node/src/core/tx.rs b/node/src/core/tx.rs index 56a8f7e..73c8e9e 100644 --- a/node/src/core/tx.rs +++ b/node/src/core/tx.rs @@ -3,24 +3,29 @@ use crate::error::TxError; #[derive(serde::Deserialize, serde::Serialize, Debug, clap::Args, Clone)] pub struct Tx { - from: Account, - to: Account, - value: u32, - data: String + from: Account, + to: Account, + value: u32, + data: String, } impl Tx { pub fn new(from: Account, to: Account, value: u32, data: String) -> Self { - Self { from, to, value, data } + Self { + from, + to, + value, + data, + } } pub fn validate(&self) -> Result<(), TxError> { if self.from.is_empty() { - return Err(TxError::FromEmpty) + return Err(TxError::FromEmpty); } else if self.to.is_empty() { - return Err(TxError::ToEmpty) + return Err(TxError::ToEmpty); } else if self.value == 0 { - return Err(TxError::ValueEmpty) + return Err(TxError::ValueEmpty); } Ok(()) } diff --git a/node/src/db/database.rs b/node/src/db/database.rs new file mode 100644 index 0000000..50bff61 --- /dev/null +++ b/node/src/db/database.rs @@ -0,0 +1,20 @@ +use sled; +use crate::log; +use vlogger::*; + +const DB_PATH: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/database"); + +fn db_init() { + match sled::open(DB_PATH) { + Ok(db) => { + if db.was_recovered() { + log(msg!(INFO, "Loaded Database from Previous state at: {}", DB_PATH)); + } else { + log(msg!(INFO, "Created Database at {}", DB_PATH)); + } + } + Err(e) => { + + } + } +} diff --git a/node/src/error.rs b/node/src/error.rs index 564aad0..f7bd2d8 100644 --- a/node/src/error.rs +++ b/node/src/error.rs @@ -1,5 +1,5 @@ -use thiserror::Error; use crate::log; +use thiserror::Error; #[allow(dead_code)] #[derive(Error, Debug)] @@ -7,7 +7,7 @@ pub enum BlockchainError { #[error("invalid account creation")] InvalidAccountCreation, #[error("Transactional error")] - Tx(#[from] TxError) + Tx(#[from] TxError), } #[allow(dead_code)] @@ -22,27 +22,27 @@ pub enum TxError { #[error("0 value transaction")] ValueEmpty, #[error("account {0} not found in database")] - UnknownAccount(String) + UnknownAccount(String), } pub fn print_error_chain(err: anyhow::Error) { - let mut err_string = String::from(format!("Error: {}\n", err)); + let mut err_string = String::from(format!("Error: {}\n", err)); - let mut source = err.source(); - let mut level = 1; + let mut source = err.source(); + let mut level = 1; - while let Some(err) = source { - err_string.push_str(format!(" {}: {}\n", level, err).as_str()); - source = err.source(); - level += 1; - } - log(err_string) + while let Some(err) = source { + err_string.push_str(format!(" {}: {}\n", level, err).as_str()); + source = err.source(); + level += 1; + } + log(err_string) } #[derive(Debug, Error)] pub enum SystemError where - T: std::fmt::Debug + T: std::fmt::Debug, { #[error("TODO")] TODO, @@ -54,5 +54,5 @@ where ChannelClosed { message: T }, #[error("Event Bus closed")] - EventBusClosed(#[from] tokio::sync::broadcast::error::RecvError) + EventBusClosed(#[from] tokio::sync::broadcast::error::RecvError), } diff --git a/node/src/event_bus.rs b/node/src/event_bus.rs deleted file mode 100644 index 5e56f38..0000000 --- a/node/src/event_bus.rs +++ /dev/null @@ -1,78 +0,0 @@ -use once_cell::sync::Lazy; -use tokio::sync::broadcast; -use std::sync::Arc; - -use crate::watcher::renderer::RenderCommand; - -static NETWORK_EVENT_BUS: Lazy>> = Lazy::new(|| Arc::new(EventBus::new())); -static SYSTEM_EVENT_BUS: Lazy>> = Lazy::new(|| Arc::new(EventBus::new())); -static RENDER_CHANNEL: Lazy>> = Lazy::new(|| Arc::new(EventBus::new())); - -pub fn publish_system_event(event: SystemEvent) { - SYSTEM_EVENT_BUS.publish(event); -} - -pub fn subscribe_system_event() -> broadcast::Receiver { - SYSTEM_EVENT_BUS.subscribe() -} - -pub fn publish_network_event(event: NetworkEvent) { - NETWORK_EVENT_BUS.publish(event); -} - -pub fn subscribe_network_event() -> broadcast::Receiver { - NETWORK_EVENT_BUS.subscribe() -} - -pub fn publish_render_event(event: RenderCommand) { - RENDER_CHANNEL.publish(event); -} - -pub fn subscribe_render_event() -> broadcast::Receiver { - RENDER_CHANNEL.subscribe() -} - -struct EventBus -where - T: Clone + std::fmt::Debug -{ - sender: broadcast::Sender, - _receiver: broadcast::Receiver -} - -impl EventBus { - pub fn new() -> Self { - let (sender, receiver) = broadcast::channel(1000); - Self { - sender, - _receiver: receiver - } - } - - pub fn publish(&self, event: T) { - if let Err(e) = self.sender.send(event) { - eprintln!("{e}") - } - } - - pub fn subscribe(&self) -> broadcast::Receiver { - self.sender.subscribe() - } -} - -#[derive(Clone, Debug)] -pub enum SystemEvent { - ExecutorStarted, - RendererStarted, - NodeStarted, - Exit, -} - -#[derive(Clone, Debug)] -pub enum NetworkEvent { - SeedConnected(String), - SeedDisconnected(String), - AllSeedsConnected, - BootstrapCompleted, - NodeReady, -} diff --git a/node/src/lib.rs b/node/src/lib.rs index ba7d484..a178704 100644 --- a/node/src/lib.rs +++ b/node/src/lib.rs @@ -1,10 +1,9 @@ -pub mod native_node { - pub mod node; - pub use node::*; - - pub mod error; - pub use error::*; +pub mod node { + pub mod node; + pub use node::*; + pub mod error; + pub use error::*; } pub mod cli; @@ -13,53 +12,67 @@ pub mod args; pub mod error; -pub mod event_bus; +pub mod db { + pub mod database; +} + +pub mod bus { + pub mod executor; + pub mod network; + pub mod render; + pub mod system; + pub mod event_bus; + + pub use executor::*; + pub use network::*; + pub use render::*; + pub use system::*; +} pub mod watcher { - pub mod executor; - pub mod parser; - pub mod renderer; - pub mod watcher; + pub mod executor; + pub mod parser; + pub mod renderer; + pub mod watcher; - pub use watcher::*; - pub use executor::*; - pub use parser::*; - pub use renderer::*; + pub use executor::*; + pub use parser::*; + pub use renderer::*; + pub use watcher::*; } pub mod protocol { - pub mod message; - pub use message::*; + pub mod message; + pub use message::*; - pub mod connection; - pub use connection::*; + pub mod connection; + pub use connection::*; - pub mod connector; - pub use connector::*; + pub mod connector; + pub use connector::*; } pub mod core { - pub mod block; - pub use block::*; + pub mod block; + pub use block::*; - pub mod blockchain; - pub use blockchain::*; + pub mod blockchain; + pub use blockchain::*; - pub mod tx; - pub use tx::*; - - pub mod data; - pub use data::*; + pub mod tx; + pub use tx::*; + pub mod data; + pub use data::*; } pub mod seeds_constants; -use crate::watcher::renderer::{RenderPane, RenderCommand}; +use crate::watcher::renderer::{RenderCommand, RenderPane}; pub fn log(msg: String) { - crate::event_bus::publish_render_event(RenderCommand::RenderStringToPane{ - pane: RenderPane::CliOutput, - str: msg - }) + crate::bus::publish_render_event(RenderCommand::RenderStringToPane { + pane: RenderPane::CliOutput, + str: msg, + }) } diff --git a/node/src/main.rs b/node/src/main.rs index d00159f..cd50783 100644 --- a/node/src/main.rs +++ b/node/src/main.rs @@ -1,5 +1,5 @@ -use blockchain::watcher::Watcher; use blockchain::args; +use blockchain::watcher::Watcher; use clap::Parser; // // src/main.rs @@ -7,40 +7,41 @@ use clap::Parser; // // #[global_allocator] // static GLOBAL: Jemalloc = Jemalloc; -// + #[tokio::main] async fn main() -> Result<(), std::io::Error> { + let args = args::CliArgs::parse(); - let args = args::CliArgs::parse(); + let mut watcher = Watcher::build() + .file(args.seed_file) + .addr(args.addr) + .seed(args.seed) + .debug(args.debug) + .render(args.render) + .bootstrap(args.bootstrap) + .start() + .await; - let mut watcher = Watcher::build() - .file(args.seed_file) - .addr(args.addr) - .seed(args.seed) - .render(args.render) - .bootstrap(args.bootstrap) - .start().await; + crossterm::execute!( + std::io::stdout(), + crossterm::event::EnableBracketedPaste, + crossterm::event::EnableFocusChange, + crossterm::event::EnableMouseCapture, + )?; - crossterm::execute!( - std::io::stdout(), - crossterm::event::EnableBracketedPaste, - crossterm::event::EnableFocusChange, - crossterm::event::EnableMouseCapture, - )?; - - loop { - if !watcher.poll().await.is_ok_and(|b| b) { - break ; + loop { + if !watcher.poll().await.is_ok_and(|b| b) { + break; + } } - } - crossterm::execute!( - std::io::stdout(), - crossterm::event::DisableBracketedPaste, - crossterm::event::DisableFocusChange, - crossterm::event::DisableMouseCapture - )?; - ratatui::restore(); - println!("Hello, world!"); - Ok(()) + crossterm::execute!( + std::io::stdout(), + crossterm::event::DisableBracketedPaste, + crossterm::event::DisableFocusChange, + crossterm::event::DisableMouseCapture + )?; + ratatui::restore(); + println!("Hello, world!"); + Ok(()) } diff --git a/node/src/native_node/node.rs b/node/src/native_node/node.rs deleted file mode 100644 index 67f150b..0000000 --- a/node/src/native_node/node.rs +++ /dev/null @@ -1,389 +0,0 @@ -use crate::core::{self, Blockchain, NetworkData, ValidationError}; -use crate::error::print_error_chain; -use crate::event_bus::{publish_system_event, SystemEvent}; -use crate::protocol::ProtocolMessage; - -use crate::seeds_constants::SEED_NODES; -use crate::protocol::{Connector, ConnectorCommand}; -use crate::watcher::executor::ExecutorCommand; - -use std::collections::HashMap; -use std::net::SocketAddr; -use vlogger::*; -use tokio::sync::mpsc; -use uuid::Uuid; - -use crate::log; - -#[derive(Debug, Clone)] -pub struct TcpPeer { - pub id: Uuid, - pub addr: SocketAddr, - pub sender: tokio::sync::mpsc::Sender -} - -impl TcpPeer { - pub fn new( - id: Uuid, - addr: SocketAddr, - sender: tokio::sync::mpsc::Sender, - ) -> Self { - Self { - id, - addr, - sender - } - } -} - -#[allow(dead_code)] -pub struct NativeNode { - pub tcp_connector: Option>, - pub id: Uuid, - pub addr: Option, - pub tcp_peers: HashMap, - pub chain: core::Blockchain, - listner_handle: Option>, - exec_tx: mpsc::Sender, - rx: mpsc::Receiver, - tx: mpsc::Sender, -} - -#[derive(Debug)] -pub enum NodeCommand { - AddPeer(TcpPeer), - RemovePeer { peer_id: Uuid }, - ProcessMessage { peer_id: Uuid, message: ProtocolMessage }, - ProcessNetworkData(NetworkData), - StartListner(SocketAddr), - PingAddr(String), - PingId(String), - CreateBlock, - ListBlocks, - ListPeers, - ShowId, - DumpBlocks(String), - ConnectToSeeds, - ConnectTcpPeer(String), - BootStrap, - Exit, -} - -impl NativeNode { - pub fn peer_addresses(&self) -> Vec { - let mut addr: Vec = self.tcp_peers.iter().map(|p| p.1.addr.to_string().parse::().unwrap()).collect(); - if let Some(a) = self.addr { - addr.push(a.clone()); - } - addr - } - - pub fn list_peers(&self) -> String { - let mut ret = String::from("Peer List\n-----------\n"); - for (i, p) in self.tcp_peers.iter().enumerate() { - ret.push_str(format!("Peer #{i}: {}\n", p.1.id).as_str()) - } - ret - } - - pub async fn show_id(&self) { - log(msg!(DEBUG, "Node Id: {}", self.id)) - } - - async fn remove_tcp_peer(&mut self, peer_id: Uuid) { - log(msg!(DEBUG, "Removing Peer {peer_id}")); - self.tcp_peers.remove_entry(&peer_id); - } - - async fn add_tcp_peer(&mut self, peer: TcpPeer) { - log(msg!(DEBUG, "Added Peer from address: {}", peer.addr)); - self.tcp_peers.insert(peer.id, peer); - } - - pub async fn new_with_id( - id: uuid::Uuid, - exec_tx: mpsc::Sender, - addr: Option, - blocks_json: &str, - ) -> Self { - let (tx, rx) = mpsc::channel::(100); - Self { - id, - tcp_peers: HashMap::new(), - chain: Blockchain::build(blocks_json).unwrap_or(Default::default()), - addr, - exec_tx, - listner_handle: None, - tcp_connector: None, - tx, - rx, - } - } - - pub async fn new( - addr: Option, - blocks_json: &str, - exec_tx: mpsc::Sender, - ) -> Self { - let (tx, rx) = mpsc::channel::(100); - let chain = Blockchain::build(blocks_json) - .unwrap_or_else(|e| { - print_error_chain(e.into()); - Default::default() - }); - Self { - id: Uuid::new_v4(), - tcp_peers: HashMap::new(), - chain, - addr, - exec_tx, - listner_handle: None, - tcp_connector: None, - tx, - rx, - } - } - - pub async fn process_message(&mut self, peer_id: uuid::Uuid, message: ProtocolMessage) { - - match message { - ProtocolMessage::BootstrapRequest { .. } => { - log(msg!(DEBUG, "Received BootstrapRequest from {peer_id}")); - let peer = &self.tcp_peers[&peer_id]; - let resp = ProtocolMessage::BootstrapResponse { - blocks: serde_json::to_string(&self.chain.blocks().to_vec()).unwrap_or_else(|e| { - log(msg!(WARNING, "Failed to serde Chain for BootstrapResponse: {e}")); - Default::default() - }) - }; - peer.sender.send(resp).await.unwrap(); - log(msg!(DEBUG, "Send BootstrapResponse to {peer_id}")); - }, - ProtocolMessage::BootstrapResponse { blocks } => { - log(msg!(DEBUG, "Received BootstrapResponse from seed")); - self.chain = core::Blockchain::build(&blocks).unwrap(); - }, - ProtocolMessage::Ping {peer_id} => { - log(msg!(DEBUG, "Received Ping from {peer_id}")); - let resp = ProtocolMessage::Pong { peer_id: self.id.clone() }; - let peer = &self.tcp_peers[&peer_id]; - peer.sender.send(resp).await.unwrap(); - }, - ProtocolMessage::GetPeersRequest { peer_id } => { - log(msg!(DEBUG, "Received GetPeersRequest from {peer_id}")); - let peers = self.peer_addresses(); - let resp = ProtocolMessage::GetPeersResponse { peer_addresses: peers }; - let peer = &self.tcp_peers[&peer_id]; - peer.sender.send(resp).await.unwrap(); - } - ProtocolMessage::Block { block, ..} => { - log(msg!(DEBUG, "Received Block from {peer_id}")); - self.chain.add_block(block.clone()) - } - ProtocolMessage::NetworkData { data, ..} => { - log(msg!(DEBUG, "Received NetworkData from {peer_id}")); - self.chain.apply(data).unwrap() - } - _ => { - log(msg!(DEBUG, "TODO: implement this message type")); - } - } - } - - pub async fn send_message_to_peer_addr(&self, addr: SocketAddr, msg: ProtocolMessage) { - if let Some((_, peer)) = self.tcp_peers.iter().find(|(_, v)| v.addr == addr) { - if let Err(e) = peer.sender.send(msg).await { - log(msg!(ERROR, "Error Sending message to peer: {e}")); - } - log(msg!(DEBUG, "Sent BootstrapRequest to seed")); - } else { - log(msg!(ERROR, "Error Sending message to peer: peer not in list")); - } - } - - pub async fn send_message_to_peer_id(&self, id: Uuid, msg: ProtocolMessage) { - if let Some(peer) = self.tcp_peers.get(&id) { - if let Err(e) = peer.sender.send(msg).await { - log(msg!(ERROR, "Error Sending message to peer: {e}")); - } - } - } - - async fn send_message_to_seed(&self, msg: ProtocolMessage) { - for seed in SEED_NODES.iter() { - if let Some(_) = self.tcp_peers.iter().find(|(_, v)| v.addr == *seed) { - self.send_message_to_peer_addr(*seed, msg).await; - return ; - } else { - self.send_message_to_peer_addr(*seed, msg).await; - return ; - } - } - log(msg!(ERROR, "No Seed Nodes Avaliable")); - } - - async fn bootstrap(&mut self) -> Result<(), ValidationError> { - log(msg!(DEBUG, "Bootstrapping")); - - let message = ProtocolMessage::BootstrapRequest{peer_id: self.id, version: "".to_string()}; - self.send_message_to_seed(message).await; - - Ok(()) - } - - async fn broadcast_network_data(&self, data: NetworkData) { - for (id, peer) in &self.tcp_peers { - let message = ProtocolMessage::NetworkData{peer_id: self.id, data: data.clone()}; - peer.sender.send(message).await.unwrap(); - log(msg!(DEBUG, "Send Transaction message to {id}")); - } - } - - async fn broadcast_block(&self, block: &core::Block) { - for (id, peer) in &self.tcp_peers { - let message = ProtocolMessage::Block { - peer_id: self.id, - height: self.chain.blocks().len() as u64, - block: block.clone() - }; - peer.sender.send(message).await.unwrap(); - log(msg!(DEBUG, "Send Block message to {id}")); - } - } - - pub fn tx(&self) -> mpsc::Sender { - return self.tx.clone() - } - - pub fn exec_tx(&self) -> mpsc::Sender { - return self.exec_tx.clone() - } - - async fn network_data(&mut self, data: NetworkData) { - match self.chain.apply(data) { - Ok(_) => log(msg!(DEBUG, "NetworkData Applied")), - Err(e) => print_error_chain(e.into()) - }; - } - - async fn connector_cmd(&self, cmd: ConnectorCommand) { - match &self.tcp_connector { - Some(t) => { - match t.send(cmd).await { - Ok(()) => {}, - Err(e) => log(msg!(ERROR, "Failed to Send Command to connector: {}", e)) - } - } - None => log(msg!(ERROR, "No Connector Availiable")) - } - } - - async fn start_connection_listner(&mut self, addr: SocketAddr) { - - log(msg!(DEBUG, "Starting Connection Listener")); - let (con_tx, con_rx) = mpsc::channel::(100); - - self.tcp_connector = Some(con_tx); - - self.listner_handle = Some(tokio::spawn({ - let mut connector = Connector::new(self.id, addr, self.exec_tx(), con_rx); - log(msg!(DEBUG, "Connector Build")); - async move { - connector.start().await - } - })); - - } - - async fn connect_to_seed(&mut self) { - self.connector_cmd(ConnectorCommand::ConnectToTcpSeed(SEED_NODES[0])).await; - } - - pub async fn run(&mut self) { - - if let Some(addr) = self.addr { - self.start_connection_listner(addr).await; - } else { - self.start_connection_listner(SocketAddr::new(std::net::IpAddr::V4(std::net::Ipv4Addr::new(0,0,0,0)), 8080)).await; - }; - - publish_system_event(SystemEvent::NodeStarted); - - while let Some(command) = self.rx.recv().await { - match command { - NodeCommand::BootStrap => { - log(msg!(DEBUG, "Received NodeCommand::BootStrap")); - let _ = self.bootstrap().await; - }, - NodeCommand::StartListner(addr) => { - self.start_connection_listner(addr).await; - }, - NodeCommand::ConnectToSeeds => { - self.connect_to_seed().await; - }, - NodeCommand::ConnectTcpPeer(addr) => { - log(msg!(DEBUG, "Received ConnectToPeer: {addr}")); - if let Ok(addr_sock) = addr.parse::() { - let mes = ConnectorCommand::ConnectToTcpPeer(addr_sock); - self.connector_cmd(mes).await; - } else { - log(msg!(ERROR, "Failed to Parse to sock_addr: {addr}")); - } - }, - NodeCommand::PingAddr(addr) => { - if let Ok(addr_sock) = addr.parse::() { - let mes = ProtocolMessage::Ping { peer_id: self.id }; - self.send_message_to_peer_addr(addr_sock, mes).await; - } else { - log(msg!(ERROR, "Failed to Parse to sock_addr: {addr}")); - } - } - NodeCommand::PingId(id) => { - if let Ok(id) = id.parse::() { - let mes = ProtocolMessage::Ping { peer_id: self.id }; - self.send_message_to_peer_id(id, mes).await; - } else { - log(msg!(ERROR, "Failed to Parse to sock_addr: {id}")); - } - } - NodeCommand::AddPeer(peer) => { - self.add_tcp_peer(peer).await; - }, - NodeCommand::RemovePeer { peer_id } => { - self.remove_tcp_peer(peer_id).await; - } - NodeCommand::ProcessMessage { peer_id, message } => { - self.process_message(peer_id, message).await; - }, - NodeCommand::ProcessNetworkData(data) => { - self.network_data(data.clone()).await; - self.broadcast_network_data(data).await; - }, - NodeCommand::CreateBlock => { - log(msg!(DEBUG, "Received CreateBlock Command")); - let block = self.chain.create_block(); - self.broadcast_block(&block).await; - }, - NodeCommand::ListBlocks => { - log(msg!(DEBUG, "Received DebugListBlocks command")); - log(self.chain.list_blocks()); - }, - NodeCommand::ListPeers => { - log(msg!(DEBUG, "Received DebugListPeers command")); - log(self.list_peers()); - }, - NodeCommand::ShowId => { - log(msg!(DEBUG, "Received DebugListBlocks command")); - self.show_id().await; - }, - NodeCommand::DumpBlocks(s) => { - self.chain.dump_blocks(s); - }, - NodeCommand::Exit => { - log(msg!(DEBUG, "Node Exit")); - break ; - } - } - } - } -} diff --git a/node/src/native_node/error.rs b/node/src/node/error.rs similarity index 100% rename from node/src/native_node/error.rs rename to node/src/node/error.rs diff --git a/node/src/node/node.rs b/node/src/node/node.rs new file mode 100644 index 0000000..ebe6a27 --- /dev/null +++ b/node/src/node/node.rs @@ -0,0 +1,413 @@ +use crate::core::{self, Blockchain, NetworkData, ValidationError}; +use crate::error::print_error_chain; +use crate::bus::{SystemEvent, publish_system_event}; +use crate::protocol::ProtocolMessage; + +use crate::protocol::{Connector, ConnectorCommand}; +use crate::seeds_constants::SEED_NODES; +use crate::watcher::executor::ExecutorCommand; + +use std::collections::HashMap; +use std::net::SocketAddr; +use tokio::sync::mpsc; +use uuid::Uuid; +use vlogger::*; + +use crate::log; + +#[derive(Debug, Clone)] +pub struct TcpPeer { + pub id: Uuid, + pub addr: SocketAddr, + pub sender: tokio::sync::mpsc::Sender, +} + +impl TcpPeer { + pub fn new( + id: Uuid, + addr: SocketAddr, + sender: tokio::sync::mpsc::Sender, + ) -> Self { + Self { id, addr, sender } + } +} + +#[allow(dead_code)] +pub struct Node { + pub tcp_connector: Option>, + pub id: Uuid, + pub addr: Option, + pub tcp_peers: HashMap, + listner_handle: Option>, + exec_tx: mpsc::Sender, + rx: mpsc::Receiver, + tx: mpsc::Sender, +} + +pub enum NodeError { + +} + +#[derive(Debug, Clone)] +pub enum NodeCommand { + AddPeer(TcpPeer), + RemovePeer { + peer_id: Uuid, + }, + ProcessMessage { + peer_id: Uuid, + message: ProtocolMessage, + }, + ProcessNetworkData(NetworkData), + StartListner(SocketAddr), + PingAddr(String), + PingId(String), + CreateBlock, + ListBlocks, + ListPeers, + ShowId, + DumpBlocks(String), + ConnectToSeeds, + ConnectTcpPeer(String), + BootStrap, + Exit, +} + +impl Node { + pub fn peer_addresses(&self) -> Vec { + let mut addr: Vec = self + .tcp_peers + .iter() + .map(|p| p.1.addr.to_string().parse::().unwrap()) + .collect(); + if let Some(a) = self.addr { + addr.push(a.clone()); + } + addr + } + + pub fn list_peers(&self) -> String { + let mut ret = String::from("Peer List\n-----------\n"); + for (i, p) in self.tcp_peers.iter().enumerate() { + ret.push_str(format!("Peer #{i}: {}\n", p.1.id).as_str()) + } + ret + } + + pub async fn show_id(&self) { + log(msg!(DEBUG, "Node Id: {}", self.id)) + } + + async fn remove_tcp_peer(&mut self, peer_id: Uuid) { + log(msg!(DEBUG, "Removing Peer {peer_id}")); + self.tcp_peers.remove_entry(&peer_id); + } + + async fn add_tcp_peer(&mut self, peer: TcpPeer) { + log(msg!(DEBUG, "Added Peer from address: {}", peer.addr)); + self.tcp_peers.insert(peer.id, peer); + } + + pub async fn new_with_id( + id: uuid::Uuid, + exec_tx: mpsc::Sender, + addr: Option, + ) -> Self { + let (tx, rx) = mpsc::channel::(100); + Self { + id, + tcp_peers: HashMap::new(), + addr, + exec_tx, + listner_handle: None, + tcp_connector: None, + tx, + rx, + } + } + + pub async fn new( + addr: Option, + blocks_json: &str, + exec_tx: mpsc::Sender, + ) -> Self { + let (tx, rx) = mpsc::channel::(100); + let chain = Blockchain::build(blocks_json).unwrap_or_else(|e| { + print_error_chain(e.into()); + Default::default() + }); + Self { + id: Uuid::new_v4(), + tcp_peers: HashMap::new(), + addr, + exec_tx, + listner_handle: None, + tcp_connector: None, + tx, + rx, + } + } + + async fn get_blocks(&mut self, ) -> Result, NodeError> { + Ok(vec![]) + } + + pub async fn process_message(&mut self, peer_id: uuid::Uuid, message: ProtocolMessage) { + match message { + ProtocolMessage::BootstrapRequest { .. } => { + log(msg!(DEBUG, "Received BootstrapRequest from {peer_id}")); + let peer = &self.tcp_peers[&peer_id]; + let blocks = self.get_blocks(); + let resp = ProtocolMessage::BootstrapResponse { + blocks: serde_json::to_string(&self.chain.blocks().to_vec()).unwrap_or_else( + |e| { + log(msg!( + WARNING, + "Failed to serde Chain for BootstrapResponse: {e}" + )); + Default::default() + }, + ), + }; + peer.sender.send(resp).await.unwrap(); + log(msg!(DEBUG, "Send BootstrapResponse to {peer_id}")); + } + ProtocolMessage::BootstrapResponse { blocks } => { + log(msg!(DEBUG, "Received BootstrapResponse from seed")); + self.chain = core::Blockchain::build(&blocks).unwrap(); + } + ProtocolMessage::Ping { peer_id } => { + log(msg!(DEBUG, "Received Ping from {peer_id}")); + let resp = ProtocolMessage::Pong { + peer_id: self.id.clone(), + }; + let peer = &self.tcp_peers[&peer_id]; + peer.sender.send(resp).await.unwrap(); + } + ProtocolMessage::GetPeersRequest { peer_id } => { + log(msg!(DEBUG, "Received GetPeersRequest from {peer_id}")); + let peers = self.peer_addresses(); + let resp = ProtocolMessage::GetPeersResponse { + peer_addresses: peers, + }; + let peer = &self.tcp_peers[&peer_id]; + peer.sender.send(resp).await.unwrap(); + } + ProtocolMessage::Block { block, .. } => { + log(msg!(DEBUG, "Received Block from {peer_id}")); + self.chain.add_block(block.clone()) + } + ProtocolMessage::NetworkData { data, .. } => { + log(msg!(DEBUG, "Received NetworkData from {peer_id}")); + self.chain.apply(data).unwrap() + } + _ => { + log(msg!(DEBUG, "TODO: implement this message type")); + } + } + } + + pub async fn send_message_to_peer_addr(&self, addr: SocketAddr, msg: ProtocolMessage) { + if let Some((_, peer)) = self.tcp_peers.iter().find(|(_, v)| v.addr == addr) { + if let Err(e) = peer.sender.send(msg).await { + log(msg!(ERROR, "Error Sending message to peer: {e}")); + } + log(msg!(DEBUG, "Sent BootstrapRequest to seed")); + } else { + log(msg!( + ERROR, + "Error Sending message to peer: peer not in list" + )); + } + } + + pub async fn send_message_to_peer_id(&self, id: Uuid, msg: ProtocolMessage) { + if let Some(peer) = self.tcp_peers.get(&id) { + if let Err(e) = peer.sender.send(msg).await { + log(msg!(ERROR, "Error Sending message to peer: {e}")); + } + } + } + + async fn send_message_to_seed(&self, msg: ProtocolMessage) { + for seed in SEED_NODES.iter() { + if let Some(_) = self.tcp_peers.iter().find(|(_, v)| v.addr == *seed) { + self.send_message_to_peer_addr(*seed, msg).await; + return; + } else { + self.send_message_to_peer_addr(*seed, msg).await; + return; + } + } + log(msg!(ERROR, "No Seed Nodes Avaliable")); + } + + async fn bootstrap(&mut self) -> Result<(), ValidationError> { + log(msg!(DEBUG, "Bootstrapping")); + + let message = ProtocolMessage::BootstrapRequest { + peer_id: self.id, + version: "".to_string(), + }; + self.send_message_to_seed(message).await; + + Ok(()) + } + + async fn broadcast_network_data(&self, data: NetworkData) { + for (id, peer) in &self.tcp_peers { + let message = ProtocolMessage::NetworkData { + peer_id: self.id, + data: data.clone(), + }; + peer.sender.send(message).await.unwrap(); + log(msg!(DEBUG, "Send Transaction message to {id}")); + } + } + + async fn broadcast_block(&self, block: &core::Block) { + for (id, peer) in &self.tcp_peers { + let message = ProtocolMessage::Block { + peer_id: self.id, + height: block.head().height as u64, + block: block.clone(), + }; + peer.sender.send(message).await.unwrap(); + log(msg!(DEBUG, "Send Block message to {id}")); + } + } + + pub fn tx(&self) -> mpsc::Sender { + return self.tx.clone(); + } + + pub fn exec_tx(&self) -> mpsc::Sender { + return self.exec_tx.clone(); + } + + async fn network_data(&mut self, data: NetworkData) { + match self.chain.apply(data) { + Ok(_) => log(msg!(DEBUG, "NetworkData Applied")), + Err(e) => print_error_chain(e.into()), + }; + } + + async fn connector_cmd(&self, cmd: ConnectorCommand) { + match &self.tcp_connector { + Some(t) => match t.send(cmd).await { + Ok(()) => {} + Err(e) => log(msg!(ERROR, "Failed to Send Command to connector: {}", e)), + }, + None => log(msg!(ERROR, "No Connector Availiable")), + } + } + + async fn start_connection_listner(&mut self, addr: SocketAddr) { + log(msg!(DEBUG, "Starting Connection Listener")); + let (con_tx, con_rx) = mpsc::channel::(100); + + self.tcp_connector = Some(con_tx); + + self.listner_handle = Some(tokio::spawn({ + let mut connector = Connector::new(self.id, addr, self.exec_tx(), con_rx); + log(msg!(DEBUG, "Connector Build")); + async move { connector.start().await } + })); + } + + async fn connect_to_seed(&mut self) { + self.connector_cmd(ConnectorCommand::ConnectToTcpSeed(SEED_NODES[0])) + .await; + } + + pub async fn run(&mut self) { + if let Some(addr) = self.addr { + self.start_connection_listner(addr).await; + } else { + self.start_connection_listner(SocketAddr::new( + std::net::IpAddr::V4(std::net::Ipv4Addr::new(0, 0, 0, 0)), + 8080, + )) + .await; + }; + + publish_system_event(SystemEvent::NodeStarted); + + while let Some(command) = self.rx.recv().await { + match command { + NodeCommand::BootStrap => { + log(msg!(DEBUG, "Received NodeCommand::BootStrap")); + let _ = self.bootstrap().await; + } + NodeCommand::StartListner(addr) => { + self.start_connection_listner(addr).await; + } + NodeCommand::ConnectToSeeds => { + self.connect_to_seed().await; + } + NodeCommand::ConnectTcpPeer(addr) => { + log(msg!(DEBUG, "Received ConnectToPeer: {addr}")); + if let Ok(addr_sock) = addr.parse::() { + let mes = ConnectorCommand::ConnectToTcpPeer(addr_sock); + self.connector_cmd(mes).await; + } else { + log(msg!(ERROR, "Failed to Parse to sock_addr: {addr}")); + } + } + NodeCommand::PingAddr(addr) => { + if let Ok(addr_sock) = addr.parse::() { + let mes = ProtocolMessage::Ping { peer_id: self.id }; + self.send_message_to_peer_addr(addr_sock, mes).await; + } else { + log(msg!(ERROR, "Failed to Parse to sock_addr: {addr}")); + } + } + NodeCommand::PingId(id) => { + if let Ok(id) = id.parse::() { + let mes = ProtocolMessage::Ping { peer_id: self.id }; + self.send_message_to_peer_id(id, mes).await; + } else { + log(msg!(ERROR, "Failed to Parse to sock_addr: {id}")); + } + } + NodeCommand::AddPeer(peer) => { + self.add_tcp_peer(peer).await; + } + NodeCommand::RemovePeer { peer_id } => { + self.remove_tcp_peer(peer_id).await; + } + NodeCommand::ProcessMessage { peer_id, message } => { + self.process_message(peer_id, message).await; + } + NodeCommand::ProcessNetworkData(data) => { + self.network_data(data.clone()).await; + self.broadcast_network_data(data).await; + } + NodeCommand::CreateBlock => { + log(msg!(DEBUG, "Received CreateBlock Command")); + let block = self.chain.create_block(); + self.broadcast_block(&block).await; + } + NodeCommand::ListBlocks => { + log(msg!(DEBUG, "Received DebugListBlocks command")); + log(self.chain.list_blocks()); + } + NodeCommand::ListPeers => { + log(msg!(DEBUG, "Received DebugListPeers command")); + log(self.list_peers()); + } + NodeCommand::ShowId => { + log(msg!(DEBUG, "Received DebugListBlocks command")); + self.show_id().await; + } + NodeCommand::DumpBlocks(s) => { + self.chain.dump_blocks(s); + } + NodeCommand::Exit => { + log(msg!(DEBUG, "Node Exit")); + break; + } + } + } + } +} diff --git a/node/src/protocol/connection.rs b/node/src/protocol/connection.rs index d0ef99c..70378bb 100644 --- a/node/src/protocol/connection.rs +++ b/node/src/protocol/connection.rs @@ -1,7 +1,7 @@ -use tokio::net; +use crate::node::node; use crate::protocol::ProtocolMessage; use crate::watcher::ExecutorCommand; -use crate::native_node::node; +use tokio::net; use tokio::sync::mpsc; use super::Connector; @@ -11,82 +11,83 @@ use vlogger::*; #[allow(dead_code)] #[derive(Debug)] pub struct Connection { - node_id: uuid::Uuid, - peer_id: uuid::Uuid, - stream: net::TcpStream, - exec_tx: mpsc::Sender, - rx: mpsc::Receiver, -} - -impl Connection { - pub fn new( node_id: uuid::Uuid, peer_id: uuid::Uuid, stream: net::TcpStream, exec_tx: mpsc::Sender, rx: mpsc::Receiver, - ) -> Self { - Self { - node_id, - peer_id, - stream, - rx, - exec_tx - } - } - - async fn log(&self, msg: String) { - let _ = self.exec_tx.send(ExecutorCommand::Print(msg)).await; - } - - pub async fn start(mut self) { - tokio::spawn(async move { - self.log(msg!(DEBUG, "Started Message Handler for {}", self.peer_id)).await; - - loop { - tokio::select! { - response_result = self.rx.recv() => { - match response_result { - Some(response) => { - if let Err(e) = Connector::send_message(&mut self.stream, &response).await { - self.log(msg!(ERROR, "Failed to send response to {}: {}", self.peer_id, e)).await; - break; - } - }, - None => { - self.log(msg!(DEBUG, "Response channel closed for {}", self.peer_id)).await; - break; - } - } - } - - message_result = Connector::receive_message(&mut self.stream) => { - match message_result { - Ok(message) => { - self.log(msg!(DEBUG, "Received Message from {}", self.peer_id)).await; - - let command = ExecutorCommand::Node(node::NodeCommand::ProcessMessage { - peer_id: self.peer_id, - message: message.clone() - }); - - if self.exec_tx.send(command).await.is_err() { - self.log(msg!(ERROR, "Failed to send command to main thread from {}", self.peer_id)).await; - break; - } - }, - Err(e) => { - self.log(msg!(WARNING, "Connection to {} closed: {}", self.peer_id, e.message)).await; - let cmd = ExecutorCommand::Node(node::NodeCommand::RemovePeer { - peer_id: self.peer_id - }); - self.exec_tx.send(cmd).await.unwrap(); - break; - } - } - } - } - } - }); - } +} + +impl Connection { + pub fn new( + node_id: uuid::Uuid, + peer_id: uuid::Uuid, + stream: net::TcpStream, + exec_tx: mpsc::Sender, + rx: mpsc::Receiver, + ) -> Self { + Self { + node_id, + peer_id, + stream, + rx, + exec_tx, + } + } + + async fn log(&self, msg: String) { + let _ = self.exec_tx.send(ExecutorCommand::Print(msg)).await; + } + + pub async fn start(mut self) { + tokio::spawn(async move { + self.log(msg!(DEBUG, "Started Message Handler for {}", self.peer_id)) + .await; + + loop { + tokio::select! { + response_result = self.rx.recv() => { + match response_result { + Some(response) => { + if let Err(e) = Connector::send_message(&mut self.stream, &response).await { + self.log(msg!(ERROR, "Failed to send response to {}: {}", self.peer_id, e)).await; + break; + } + }, + None => { + self.log(msg!(DEBUG, "Response channel closed for {}", self.peer_id)).await; + break; + } + } + } + + message_result = Connector::receive_message(&mut self.stream) => { + match message_result { + Ok(message) => { + self.log(msg!(DEBUG, "Received Message from {}", self.peer_id)).await; + + let command = ExecutorCommand::Node(node::NodeCommand::ProcessMessage { + peer_id: self.peer_id, + message: message.clone() + }); + + if self.exec_tx.send(command).await.is_err() { + self.log(msg!(ERROR, "Failed to send command to main thread from {}", self.peer_id)).await; + break; + } + }, + Err(e) => { + self.log(msg!(WARNING, "Connection to {} closed: {}", self.peer_id, e.message)).await; + let cmd = ExecutorCommand::Node(node::NodeCommand::RemovePeer { + peer_id: self.peer_id + }); + self.exec_tx.send(cmd).await.unwrap(); + break; + } + } + } + } + } + }); + } } diff --git a/node/src/protocol/connector.rs b/node/src/protocol/connector.rs index 01fde84..6a21015 100644 --- a/node/src/protocol/connector.rs +++ b/node/src/protocol/connector.rs @@ -1,31 +1,31 @@ use anyhow::Context; +use std::net::SocketAddr; use tokio::io::{AsyncReadExt, AsyncWriteExt}; use tokio::net; -use std::net::SocketAddr; use tokio::sync::mpsc; use vlogger::*; use crate::error::print_error_chain; use crate::log; -use thiserror::*; use super::Connection; -use crate::native_node::error; +use crate::bus::*; +use crate::node::error; +use crate::node::node; use crate::protocol::ProtocolMessage; use crate::watcher::ExecutorCommand; -use crate::native_node::node; -use crate::event_bus::*; +use thiserror::*; pub enum ConnectorCommand { - ConnectToTcpPeer(SocketAddr), - ConnectToTcpSeed(SocketAddr), + ConnectToTcpPeer(SocketAddr), + ConnectToTcpSeed(SocketAddr), } pub struct Connector { - node_id: uuid::Uuid, - addr: SocketAddr, - exec_tx: mpsc::Sender, - rx: mpsc::Receiver, + node_id: uuid::Uuid, + addr: SocketAddr, + exec_tx: mpsc::Sender, + rx: mpsc::Receiver, } #[derive(Error, Debug)] @@ -37,236 +37,279 @@ pub enum ConnectorError { const MAX_LISTNER_TRIES: usize = 5; impl Connector { - - pub fn new( - node_id: uuid::Uuid, - addr: SocketAddr, - exec_tx: mpsc::Sender, - rx: mpsc::Receiver, - ) -> Self { - Self { - node_id, - addr, - exec_tx, - rx - } - } - - pub async fn start(&mut self) { - let mut listner: Option = None; - let mut listner_err = None; - for _ in 0..MAX_LISTNER_TRIES { - match tokio::net::TcpListener::bind(self.addr).await { - Ok(l) => { - log(msg!(DEBUG, "Listening on address: {}", self.addr)); - listner = Some(l); - break ; + pub fn new( + node_id: uuid::Uuid, + addr: SocketAddr, + exec_tx: mpsc::Sender, + rx: mpsc::Receiver, + ) -> Self { + Self { + node_id, + addr, + exec_tx, + rx, } - Err(e) => { - self.addr.set_port(self.addr.port() + 1); - listner_err = Some(e); - } - }; } - if let Some(listener) = listner { - loop { - tokio::select! { - cmd_result = self.rx.recv() => { - match cmd_result { - Some(cmd) => { - self.execute_cmd(cmd).await; - } - None => { - log(msg!(DEBUG, "Command channel closed")); - break; - } - } - } - accept_result = listener.accept() => { - match accept_result { - Ok((stream, addr)) => { - log(msg!(DEBUG, "Accepted connection from {}", addr)); - self.establish_connection_inbound(stream, addr).await; - } - Err(e) => { - log(msg!(ERROR, "Failed to accept connection: {}", e)); - } - } - } - } - } - } else { - log(msg!(FATAL, "Failed to start TCP Listener: {}", listner_err.unwrap())); - } - } - async fn execute_cmd(&mut self, cmd: ConnectorCommand) { - match cmd { - ConnectorCommand::ConnectToTcpPeer(addr) => { - self.connect_to_peer(addr).await - } - ConnectorCommand::ConnectToTcpSeed(addr) => { - self.connect_to_seed(addr).await; - } - } - } - - pub async fn connect_to_seed(&self, addr: SocketAddr) { - match net::TcpStream::connect(addr).await - .with_context(|| format!("Connecting to {}", addr)){ - Ok(stream) => { - self.establish_connection_to_seed(stream, addr).await - } - Err(e) => { - // let err = ConnectorError::ConnectionError(e.into()); - print_error_chain(e.into()); - } - } - } - - pub async fn connect_to_peer(&self, addr: SocketAddr) { - match net::TcpStream::connect(addr).await { - Ok(stream) => { - self.establish_connection_outbound(stream, addr).await - } - Err(e) => { - let err = ConnectorError::ConnectionError(e.into()); - print_error_chain(err.into()); - } - } - } - - pub async fn establish_connection_to_seed( - &self, - mut stream: tokio::net::TcpStream, - addr: SocketAddr, - ) { - let handshake = ProtocolMessage::Handshake { - peer_id: self.node_id, - version: "".to_string() - }; - match Connector::send_message(&mut stream, &handshake).await { - Ok(()) => { - if let Ok(mes) = Connector::receive_message(&mut stream).await { - let (ch_tx, ch_rx) = mpsc::channel::(100); - let peer = match mes { - ProtocolMessage::HandshakeAck { peer_id, .. } => { - node::TcpPeer::new(peer_id, addr, ch_tx) - } - _ => { - log(msg!(ERROR, "Invalid Message On Connetion Establishment: {mes}")); - return ; - } + pub async fn start(&mut self) { + let mut listner: Option = None; + let mut listner_err = None; + for _ in 0..MAX_LISTNER_TRIES { + match tokio::net::TcpListener::bind(self.addr).await { + Ok(l) => { + log(msg!(DEBUG, "Listening on address: {}", self.addr)); + listner = Some(l); + break; + } + Err(e) => { + self.addr.set_port(self.addr.port() + 1); + listner_err = Some(e); + } }; - let cmd = ExecutorCommand::Node(node::NodeCommand::AddPeer(peer.clone())); - publish_network_event(NetworkEvent::SeedConnected(addr.to_string())); - let _ = self.exec_tx.send(cmd).await; - Connection::new(self.node_id, peer.id, stream, self.exec_tx.clone(), ch_rx).start().await; - } } - Err(e) => print_error_chain(e.into()) - } - } - - async fn establish_connection_outbound( - &self, - mut stream: tokio::net::TcpStream, - addr: SocketAddr, - ) { - let handshake = ProtocolMessage::Handshake { - peer_id: self.node_id, - version: "".to_string() - }; - match Connector::send_message(&mut stream, &handshake).await { - Ok(()) => { - if let Ok(mes) = Connector::receive_message(&mut stream).await { - let (ch_tx, ch_rx) = mpsc::channel::(100); - let peer = match mes { - ProtocolMessage::HandshakeAck { peer_id, .. } => { - node::TcpPeer::new(peer_id, addr, ch_tx) - } - _ => { - log(msg!(ERROR, "Invalid Message On Connetion Establishment: {mes}")); - return ; - } - }; - let cmd = ExecutorCommand::Node(node::NodeCommand::AddPeer(peer.clone())); - let _ = self.exec_tx.send(cmd).await; - Connection::new(self.node_id, peer.id, stream, self.exec_tx.clone(), ch_rx).start().await; - } + if let Some(listener) = listner { + loop { + tokio::select! { + cmd_result = self.rx.recv() => { + match cmd_result { + Some(cmd) => { + self.execute_cmd(cmd).await; + } + None => { + log(msg!(DEBUG, "Command channel closed")); + break; + } + } + } + accept_result = listener.accept() => { + match accept_result { + Ok((stream, addr)) => { + log(msg!(DEBUG, "Accepted connection from {}", addr)); + self.establish_connection_inbound(stream, addr).await; + } + Err(e) => { + log(msg!(ERROR, "Failed to accept connection: {}", e)); + } + } + } + } + } + } else { + log(msg!( + FATAL, + "Failed to start TCP Listener: {}", + listner_err.unwrap() + )); } - Err(e) => print_error_chain(e.into()), - } - } + } - async fn establish_connection_inbound( - &self, - mut stream: tokio::net::TcpStream, - addr: SocketAddr, - ) { - if let Ok(mes) = Connector::receive_message(&mut stream).await { - let (ch_tx, ch_rx) = mpsc::channel::(100); - let peer = match mes { - ProtocolMessage::Handshake { peer_id, .. } => { - let ack = ProtocolMessage::HandshakeAck { + async fn execute_cmd(&mut self, cmd: ConnectorCommand) { + match cmd { + ConnectorCommand::ConnectToTcpPeer(addr) => self.connect_to_peer(addr).await, + ConnectorCommand::ConnectToTcpSeed(addr) => { + self.connect_to_seed(addr).await; + } + } + } + + pub async fn connect_to_seed(&self, addr: SocketAddr) { + match net::TcpStream::connect(addr) + .await + .with_context(|| format!("Connecting to {}", addr)) + { + Ok(stream) => self.establish_connection_to_seed(stream, addr).await, + Err(e) => { + // let err = ConnectorError::ConnectionError(e.into()); + print_error_chain(e.into()); + } + } + } + + pub async fn connect_to_peer(&self, addr: SocketAddr) { + match net::TcpStream::connect(addr).await { + Ok(stream) => self.establish_connection_outbound(stream, addr).await, + Err(e) => { + let err = ConnectorError::ConnectionError(e.into()); + print_error_chain(err.into()); + } + } + } + + pub async fn establish_connection_to_seed( + &self, + mut stream: tokio::net::TcpStream, + addr: SocketAddr, + ) { + let handshake = ProtocolMessage::Handshake { peer_id: self.node_id, - version: "".to_string() - }; - match Connector::send_message(&mut stream, &ack).await { - Ok(()) => node::TcpPeer::new(peer_id, addr, ch_tx), - Err(e) => return print_error_chain(e.into()), - } + version: "".to_string(), + }; + match Connector::send_message(&mut stream, &handshake).await { + Ok(()) => { + if let Ok(mes) = Connector::receive_message(&mut stream).await { + let (ch_tx, ch_rx) = mpsc::channel::(100); + let peer = match mes { + ProtocolMessage::HandshakeAck { peer_id, .. } => { + node::TcpPeer::new(peer_id, addr, ch_tx) + } + _ => { + log(msg!( + ERROR, + "Invalid Message On Connetion Establishment: {mes}" + )); + return; + } + }; + let cmd = ExecutorCommand::Node(node::NodeCommand::AddPeer(peer.clone())); + publish_network_event(NetworkEvent::SeedConnected(addr.to_string())); + let _ = self.exec_tx.send(cmd).await; + Connection::new(self.node_id, peer.id, stream, self.exec_tx.clone(), ch_rx) + .start() + .await; + } + } + Err(e) => print_error_chain(e.into()), } - _ => { - log(msg!(ERROR, "Invalid Message On Connetion Establishment: {mes}")); - return ; - } - }; - let cmd = ExecutorCommand::Node(node::NodeCommand::AddPeer(peer.clone())); - let _ = self.exec_tx.send(cmd).await; - Connection::new(self.node_id, peer.id, stream, self.exec_tx.clone(), ch_rx).start().await; - } - } - - pub async fn send_message(stream: &mut net::TcpStream, message: &ProtocolMessage) -> Result<(), error::NetworkError> { - let json = serde_json::to_string(message) - .map_err(|e| error::NetworkError { message: format!("Failed to serialize: {}", e) })?; - let data = json.as_bytes(); - - let len = data.len() as u32; - stream.write_all(&len.to_be_bytes()).await - .map_err(|e| error::NetworkError { message: format!("Failed to write data: {}", e) })?; - - stream.write_all(data).await - .map_err(|e| error::NetworkError { message: format!("Failed to write data: {}", e) })?; - stream.flush().await - .map_err(|e| error::NetworkError { message: format!("Failed to flush stream: {}", e) })?; - Ok(()) - } - - pub async fn receive_message(stream: &mut tokio::net::TcpStream) -> Result { - let mut len_bytes = [0u8; 4]; - stream.read_exact(&mut len_bytes).await - .map_err(|e| error::NetworkError { message: format!("Failed to read length: {}", e) })?; - - let len = u32::from_be_bytes(len_bytes) as usize; - - if len >= super::message::MAX_MESSAGE_SIZE { - return Err(error::NetworkError{ - message: format!("NetworkError: Inbound Message too large: max = {}, got = {len}", super::message::MAX_MESSAGE_SIZE) - }) } - let mut data = vec![0u8; len]; - stream.read_exact(&mut data).await - .map_err(|e| error::NetworkError { message: format!("Failed to read data: {}", e) })?; + async fn establish_connection_outbound( + &self, + mut stream: tokio::net::TcpStream, + addr: SocketAddr, + ) { + let handshake = ProtocolMessage::Handshake { + peer_id: self.node_id, + version: "".to_string(), + }; + match Connector::send_message(&mut stream, &handshake).await { + Ok(()) => { + if let Ok(mes) = Connector::receive_message(&mut stream).await { + let (ch_tx, ch_rx) = mpsc::channel::(100); + let peer = match mes { + ProtocolMessage::HandshakeAck { peer_id, .. } => { + node::TcpPeer::new(peer_id, addr, ch_tx) + } + _ => { + log(msg!( + ERROR, + "Invalid Message On Connetion Establishment: {mes}" + )); + return; + } + }; + let cmd = ExecutorCommand::Node(node::NodeCommand::AddPeer(peer.clone())); + let _ = self.exec_tx.send(cmd).await; + Connection::new(self.node_id, peer.id, stream, self.exec_tx.clone(), ch_rx) + .start() + .await; + } + } + Err(e) => print_error_chain(e.into()), + } + } - let json = String::from_utf8(data) - .map_err(|e| error::NetworkError { message: format!("Invalid UTF-8: {}", e) })?; + async fn establish_connection_inbound( + &self, + mut stream: tokio::net::TcpStream, + addr: SocketAddr, + ) { + if let Ok(mes) = Connector::receive_message(&mut stream).await { + let (ch_tx, ch_rx) = mpsc::channel::(100); + let peer = match mes { + ProtocolMessage::Handshake { peer_id, .. } => { + let ack = ProtocolMessage::HandshakeAck { + peer_id: self.node_id, + version: "".to_string(), + }; + match Connector::send_message(&mut stream, &ack).await { + Ok(()) => node::TcpPeer::new(peer_id, addr, ch_tx), + Err(e) => return print_error_chain(e.into()), + } + } + _ => { + log(msg!( + ERROR, + "Invalid Message On Connetion Establishment: {mes}" + )); + return; + } + }; + let cmd = ExecutorCommand::Node(node::NodeCommand::AddPeer(peer.clone())); + let _ = self.exec_tx.send(cmd).await; + Connection::new(self.node_id, peer.id, stream, self.exec_tx.clone(), ch_rx) + .start() + .await; + } + } - let message: ProtocolMessage = serde_json::from_str(&json) - .map_err(|e| error::NetworkError { message: format!("JSON parse error: {}", e) })?; + pub async fn send_message( + stream: &mut net::TcpStream, + message: &ProtocolMessage, + ) -> Result<(), error::NetworkError> { + let json = serde_json::to_string(message).map_err(|e| error::NetworkError { + message: format!("Failed to serialize: {}", e), + })?; + let data = json.as_bytes(); - Ok(message) - } + let len = data.len() as u32; + stream + .write_all(&len.to_be_bytes()) + .await + .map_err(|e| error::NetworkError { + message: format!("Failed to write data: {}", e), + })?; + + stream + .write_all(data) + .await + .map_err(|e| error::NetworkError { + message: format!("Failed to write data: {}", e), + })?; + stream.flush().await.map_err(|e| error::NetworkError { + message: format!("Failed to flush stream: {}", e), + })?; + Ok(()) + } + + pub async fn receive_message( + stream: &mut tokio::net::TcpStream, + ) -> Result { + let mut len_bytes = [0u8; 4]; + stream + .read_exact(&mut len_bytes) + .await + .map_err(|e| error::NetworkError { + message: format!("Failed to read length: {}", e), + })?; + + let len = u32::from_be_bytes(len_bytes) as usize; + + if len >= super::message::MAX_MESSAGE_SIZE { + return Err(error::NetworkError { + message: format!( + "NetworkError: Inbound Message too large: max = {}, got = {len}", + super::message::MAX_MESSAGE_SIZE + ), + }); + } + + let mut data = vec![0u8; len]; + stream + .read_exact(&mut data) + .await + .map_err(|e| error::NetworkError { + message: format!("Failed to read data: {}", e), + })?; + + let json = String::from_utf8(data).map_err(|e| error::NetworkError { + message: format!("Invalid UTF-8: {}", e), + })?; + + let message: ProtocolMessage = + serde_json::from_str(&json).map_err(|e| error::NetworkError { + message: format!("JSON parse error: {}", e), + })?; + + Ok(message) + } } diff --git a/node/src/protocol/message.rs b/node/src/protocol/message.rs index a781e96..2b3ea0a 100644 --- a/node/src/protocol/message.rs +++ b/node/src/protocol/message.rs @@ -1,31 +1,50 @@ use crate::core::{self, NetworkData}; -use std::net::SocketAddr; use std::fmt; +use std::net::SocketAddr; pub const MAX_MESSAGE_SIZE: usize = 1_000_000; #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] pub enum ProtocolMessage { - BootstrapRequest { - peer_id: uuid::Uuid, - version: String - }, - BootstrapResponse { - blocks: String - }, - GetPeersRequest { - peer_id: uuid::Uuid - }, - GetPeersResponse { - peer_addresses: Vec - }, - Handshake { peer_id: uuid::Uuid, version: String }, - HandshakeAck { peer_id: uuid::Uuid, version: String }, - Block { peer_id: uuid::Uuid, height: u64, block: core::Block }, - NetworkData { peer_id: uuid::Uuid, data: NetworkData }, - Ping { peer_id: uuid::Uuid }, - Pong { peer_id: uuid::Uuid }, - Disconnect { peer_id: uuid::Uuid }, + BootstrapRequest { + peer_id: uuid::Uuid, + version: String, + }, + BootstrapResponse { + blocks: String, + }, + GetPeersRequest { + peer_id: uuid::Uuid, + }, + GetPeersResponse { + peer_addresses: Vec, + }, + Handshake { + peer_id: uuid::Uuid, + version: String, + }, + HandshakeAck { + peer_id: uuid::Uuid, + version: String, + }, + Block { + peer_id: uuid::Uuid, + height: u64, + block: core::Block, + }, + NetworkData { + peer_id: uuid::Uuid, + data: NetworkData, + }, + Ping { + peer_id: uuid::Uuid, + }, + Pong { + peer_id: uuid::Uuid, + }, + Disconnect { + peer_id: uuid::Uuid, + }, } impl fmt::Display for ProtocolMessage { @@ -49,7 +68,11 @@ impl fmt::Display for ProtocolMessage { ProtocolMessage::HandshakeAck { peer_id, version } => { write!(f, "HandshakeAck from {} (v{})", peer_id, version) } - ProtocolMessage::Block { peer_id, height, block: _ } => { + ProtocolMessage::Block { + peer_id, + height, + block: _, + } => { write!(f, "Block #{} from {}", height, peer_id) } ProtocolMessage::NetworkData { peer_id, data: _ } => { diff --git a/node/src/seeds_constants.rs b/node/src/seeds_constants.rs index 6fc4487..f3a092d 100644 --- a/node/src/seeds_constants.rs +++ b/node/src/seeds_constants.rs @@ -1,8 +1,10 @@ use once_cell::sync::Lazy; -use std::net::{SocketAddr, IpAddr, Ipv4Addr}; +use std::net::{IpAddr, Ipv4Addr, SocketAddr}; -pub static SEED_NODES: Lazy<[SocketAddr; 3]> = Lazy::new(|| [ - SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8333), - SocketAddr::new(IpAddr::V4(Ipv4Addr::new(192, 168, 1, 1)), 3000), - SocketAddr::new(IpAddr::V4(Ipv4Addr::new(10, 0, 0, 1)), 5432), -]); +pub static SEED_NODES: Lazy<[SocketAddr; 3]> = Lazy::new(|| { + [ + SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8333), + SocketAddr::new(IpAddr::V4(Ipv4Addr::new(192, 168, 1, 1)), 3000), + SocketAddr::new(IpAddr::V4(Ipv4Addr::new(10, 0, 0, 1)), 5432), + ] +}); diff --git a/node/src/watcher/executor.rs b/node/src/watcher/executor.rs index e83540a..8afd99a 100644 --- a/node/src/watcher/executor.rs +++ b/node/src/watcher/executor.rs @@ -1,93 +1,101 @@ -use crate::{event_bus::{publish_render_event, publish_system_event, SystemEvent}, log, native_node::node::NodeCommand, watcher::renderer::*}; +use crate::{ + bus::{SystemEvent, publish_render_event, publish_system_event}, + log, + node::node::NodeCommand, + watcher::renderer::*, +}; use thiserror::Error; use tokio::sync::mpsc; use vlogger::*; -#[derive(Debug)] -pub enum ExecutorCommand { - NodeResponse(String), - Echo(Vec), - Print(String), - InvalidCommand(String), - Node(NodeCommand), - Render(RenderCommand), - Exit -} +use super::RenderCommand; #[derive(Debug, Error)] pub enum InProcessError { - #[error("TODO: {0}")] - TODO(String), + #[error("TODO: {0}")] + TODO(String), } +#[derive(Clone, Debug)] +pub enum ExecutorCommand { + NodeResponse(String), + Echo(Vec), + Print(String), + InvalidCommand(String), + Node(NodeCommand), + Render(RenderCommand), + Exit, +} + + pub struct Executor { - node_tx: mpsc::Sender, - rx: mpsc::Receiver, - exit: bool + node_tx: mpsc::Sender, + rx: mpsc::Receiver, + exit: bool, } impl Executor { - pub fn new(node_tx: mpsc::Sender, rx: mpsc::Receiver) -> Self { - Self { - node_tx, - rx, - exit: false + pub fn new(node_tx: mpsc::Sender, rx: mpsc::Receiver) -> Self { + Self { + node_tx, + rx, + exit: false, + } } - } - pub async fn run(&mut self) { - publish_system_event(SystemEvent::ExecutorStarted); - while !self.exit { - self.listen().await; + pub async fn run(&mut self) { + publish_system_event(SystemEvent::ExecutorStarted); + while !self.exit { + self.listen().await; + } } - } - async fn exit(&mut self) { - log(msg!(DEBUG, "Executor Exit")); - self.exit = true - } - - async fn listen(&mut self) { - if let Some(cmd) = self.rx.recv().await { - let _ = self.execute(cmd).await; + async fn exit(&mut self) { + log(msg!(DEBUG, "Executor Exit")); + self.exit = true } - } - async fn send_node_cmd(&self, cmd: NodeCommand) { - self.node_tx.send(cmd).await.unwrap() - } - - async fn handle_node_cmd(&self, cmd: NodeCommand) { - self.send_node_cmd(cmd).await; - } - - async fn echo(&self, s: Vec) { - let mut str = s.join(" "); - str.push_str("\n"); - let rd_cmd = RenderCommand::RenderStringToPane{ - str, - pane: RenderPane::CliOutput - }; - publish_render_event(rd_cmd); - } - - async fn invalid_command(&self, str: String) { - let rd_cmd = RenderCommand::RenderStringToPane{ - str, - pane: RenderPane::CliOutput - }; - publish_render_event(rd_cmd); - } - - async fn execute(&mut self, cmd: ExecutorCommand) { - match cmd { - ExecutorCommand::NodeResponse(resp) => log(resp), - ExecutorCommand::Node(n) => self.handle_node_cmd(n).await, - ExecutorCommand::Render(p) => publish_render_event(p), - ExecutorCommand::Echo(s) => self.echo(s).await, - ExecutorCommand::Print(s) => log(s), - ExecutorCommand::InvalidCommand(str) => self.invalid_command(str).await, - ExecutorCommand::Exit => self.exit().await, + async fn listen(&mut self) { + if let Some(cmd) = self.rx.recv().await { + let _ = self.execute(cmd).await; + } + } + + async fn send_node_cmd(&self, cmd: NodeCommand) { + self.node_tx.send(cmd).await.unwrap() + } + + async fn handle_node_cmd(&self, cmd: NodeCommand) { + self.send_node_cmd(cmd).await; + } + + async fn echo(&self, s: Vec) { + let mut str = s.join(" "); + str.push_str("\n"); + let rd_cmd = RenderCommand::RenderStringToPane { + str, + pane: RenderPane::CliOutput, + }; + publish_render_event(rd_cmd); + } + + async fn invalid_command(&self, str: String) { + let rd_cmd = RenderCommand::RenderStringToPane { + str, + pane: RenderPane::CliOutput, + }; + publish_render_event(rd_cmd); + } + + async fn execute(&mut self, cmd: ExecutorCommand) { + match cmd { + ExecutorCommand::NodeResponse(resp) => log(resp), + ExecutorCommand::Node(n) => self.handle_node_cmd(n).await, + ExecutorCommand::Render(p) => publish_render_event(p), + ExecutorCommand::Echo(s) => self.echo(s).await, + ExecutorCommand::Print(s) => log(s), + ExecutorCommand::InvalidCommand(str) => self.invalid_command(str).await, + ExecutorCommand::Exit => self.exit().await, + } } - } } diff --git a/node/src/watcher/parser.rs b/node/src/watcher/parser.rs index e15c2bb..3d6c9e3 100644 --- a/node/src/watcher/parser.rs +++ b/node/src/watcher/parser.rs @@ -1,68 +1,63 @@ +use crate::cli::cli; use crate::watcher::executor::ExecutorCommand; use vlogger::*; -use crate::cli::cli; -use tokio::time::{timeout, Duration}; +use tokio::time::{Duration, timeout}; use tokio::sync::mpsc; #[derive(Debug)] pub struct Parser { - rx: mpsc::Receiver, - exec_tx: mpsc::Sender, - exit: bool + rx: mpsc::Receiver, + exec_tx: mpsc::Sender, + exit: bool, } pub enum ParserCommand { - ParseCmdString(String), - Exit + ParseCmdString(String), + Exit, } impl Parser { - pub fn new( - rx: mpsc::Receiver, - exec_tx: mpsc::Sender - ) -> Self { - Self { - rx, - exec_tx, - exit: false - } - } - - async fn exit(&mut self) { - self.log(msg!(DEBUG, "Parser Exit")).await; - self.exit = true; - } - - pub async fn run(&mut self) { - self.log(msg!(INFO, "Started Parser")).await; - while !self.exit { - self.listen().await; - } - } - - async fn log(&self, msg: String) { - if let Err(e) = self.exec_tx.send(ExecutorCommand::Print(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 { - match mes { - ParserCommand::ParseCmdString(s) => { - let argv: Vec<&str> = std::iter::once(" ") - .chain(s.split_whitespace()) - .collect(); - let cmd = cli(&argv); - let _ = self.exec_tx.send(cmd).await; - }, - ParserCommand::Exit => { - self.exit().await; + pub fn new(rx: mpsc::Receiver, exec_tx: mpsc::Sender) -> Self { + Self { + rx, + exec_tx, + exit: false, } - } } - } -} + async fn exit(&mut self) { + self.log(msg!(DEBUG, "Parser Exit")).await; + self.exit = true; + } + + pub async fn run(&mut self) { + self.log(msg!(INFO, "Started Parser")).await; + while !self.exit { + self.listen().await; + } + } + + async fn log(&self, msg: String) { + if let Err(e) = self.exec_tx.send(ExecutorCommand::Print(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 { + match mes { + ParserCommand::ParseCmdString(s) => { + let argv: Vec<&str> = + std::iter::once(" ").chain(s.split_whitespace()).collect(); + let cmd = cli(&argv); + let _ = self.exec_tx.send(cmd).await; + } + ParserCommand::Exit => { + self.exit().await; + } + } + } + } +} diff --git a/node/src/watcher/renderer.rs b/node/src/watcher/renderer.rs index ba9f675..9ae642a 100644 --- a/node/src/watcher/renderer.rs +++ b/node/src/watcher/renderer.rs @@ -2,414 +2,404 @@ use crossterm::event::KeyCode; use ratatui::prelude::*; use ratatui::widgets::Wrap; use ratatui::{ - buffer::Buffer, - layout::Rect, - symbols::border, - widgets::{Block, Paragraph, Widget, List}, - Frame, + Frame, + buffer::Buffer, + layout::Rect, + symbols::border, + widgets::{Block, List, Paragraph, Widget}, }; use vlogger::*; -use crate::event_bus::{publish_system_event, subscribe_render_event, SystemEvent}; -use tokio::time::{interval, timeout, Duration}; +use crate::bus::{SystemEvent, publish_system_event, subscribe_render_event}; use std::io; +use tokio::time::{Duration, interval, timeout}; #[derive(Debug)] pub struct Renderer { - buffer: String, - exit: bool, - layout: RenderLayout, + buffer: String, + exit: bool, + layout: RenderLayout, } #[derive(Debug)] pub struct Pane { - title: Option, - target: RenderPane, - buffer: RenderBuffer, - focused: bool, - scroll: i16, - max_scroll: i16, + title: Option, + target: RenderPane, + buffer: RenderBuffer, + focused: bool, + scroll: i16, + max_scroll: i16, } #[derive(Debug, PartialEq, Clone, clap::ValueEnum)] pub enum RenderPane { - #[value(name = "all", aliases = ["a"])] - All, - #[value(aliases = ["i", "in"])] - CliInput, - #[value(aliases = ["o", "out"])] - CliOutput + #[value(name = "all", aliases = ["a"])] + All, + #[value(aliases = ["i", "in"])] + CliInput, + #[value(aliases = ["o", "out"])] + CliOutput, } #[derive(Clone, Debug)] enum RenderBuffer { - List{ list: Vec, index: usize }, - String(String) + List { list: Vec, index: usize }, + String(String), } impl Pane { - fn render(&mut self, area: Rect, buf: &mut Buffer) { - let block = Block::bordered() - .title({ - if let Some(t) = &self.title { - t.clone() - } else { - Default::default() - } - }) - .border_set(border::PLAIN) - .border_style({ - if self.focused { - Style::new().green() - } else { - Style::new().white() - } - }); - let inner_area = block.inner(area); - let content_width = inner_area.width as usize; - let content_height = inner_area.height as usize; - match &self.buffer { - RenderBuffer::String(s) => { - let wrapped_lines = s - .lines() - .map(|line| { - if line.is_empty() { - 1 + fn render(&mut self, area: Rect, buf: &mut Buffer) { + let block = Block::bordered() + .title({ + if let Some(t) = &self.title { + t.clone() } else { - (line.len() + content_width - 1) / { content_width + (content_width == 0) as usize } + Default::default() } }) - .sum::(); + .border_set(border::PLAIN) + .border_style({ + if self.focused { + Style::new().green() + } else { + Style::new().white() + } + }); + let inner_area = block.inner(area); + let content_width = inner_area.width as usize; + let content_height = inner_area.height as usize; + match &self.buffer { + RenderBuffer::String(s) => { + let wrapped_lines = s + .lines() + .map(|line| { + if line.is_empty() { + 1 + } else { + (line.len() + content_width - 1) / { + content_width + (content_width == 0) as usize + } + } + }) + .sum::(); - self.max_scroll = if wrapped_lines > content_height { - (wrapped_lines - content_height) as i16 - } else { - 0 - }; + self.max_scroll = if wrapped_lines > content_height { + (wrapped_lines - content_height) as i16 + } else { + 0 + }; - let scroll_offset = self.max_scroll.saturating_sub(self.scroll) as u16; + let scroll_offset = self.max_scroll.saturating_sub(self.scroll) as u16; - Paragraph::new(s.clone()) - .wrap(Wrap::default()) - .left_aligned() - .block(block) - .scroll((scroll_offset as u16, 0)) - .render(area, buf); - } - RenderBuffer::List { list, .. } => { - let list_w = List::new(list - .iter() - .map(|s| { - format!("> {}", textwrap::fill(s, content_width.saturating_sub(2))) - })).block(block); - Widget::render(list_w, area, buf); - } + Paragraph::new(s.clone()) + .wrap(Wrap::default()) + .left_aligned() + .block(block) + .scroll((scroll_offset as u16, 0)) + .render(area, buf); + } + RenderBuffer::List { list, .. } => { + let list_w = + List::new(list.iter().map(|s| { + format!("> {}", textwrap::fill(s, content_width.saturating_sub(2))) + })) + .block(block); + Widget::render(list_w, area, buf); + } + } } - } } #[derive(Clone, Debug)] pub enum RenderCommand { - RenderStringToPane{ - str: String, - pane: RenderPane - }, - RenderInput(KeyCode), - ListMove{ - pane: RenderPane, - index: usize - }, - ChangeLayout(RenderLayoutKind), - ClearPane(RenderPane), + RenderStringToPane { + str: String, + pane: RenderPane, + }, + RenderInput(KeyCode), + ListMove { + pane: RenderPane, + index: usize, + }, + ChangeLayout(RenderLayoutKind), + ClearPane(RenderPane), - - /// Mouse Events - MouseClickLeft(u16, u16), - MouseScrollUp, - MouseScrollDown, - Exit, + /// Mouse Events + MouseClickLeft(u16, u16), + MouseScrollUp, + MouseScrollDown, + Exit, } #[derive(Debug, Clone, clap::ValueEnum)] pub enum RenderLayoutKind { - #[value(name = "horizontal", aliases = ["h"])] - CliHorizontal, - #[value(name = "vertical", aliases = ["v"])] - CliVertical + #[value(name = "horizontal", aliases = ["h"])] + CliHorizontal, + #[value(name = "vertical", aliases = ["v"])] + CliVertical, } #[derive(Debug)] pub struct RenderLayout { - kind: RenderLayoutKind, - panes: Vec, + kind: RenderLayoutKind, + panes: Vec, } impl RenderLayoutKind { - pub fn rects(&self, area: Rect) -> std::rc::Rc<[Rect]> { - match self { - Self::CliHorizontal => { - Layout::default() - .direction(Direction::Vertical) - .constraints(vec![ - Constraint::Percentage(70), - Constraint::Percentage(30), - ]) - .split(area) - } - Self::CliVertical => { - Layout::default() - .direction(Direction::Horizontal) - .constraints(vec![ - Constraint::Percentage(30), - Constraint::Percentage(70), - ]) - .split(area) - } + pub fn rects(&self, area: Rect) -> std::rc::Rc<[Rect]> { + match self { + Self::CliHorizontal => Layout::default() + .direction(Direction::Vertical) + .constraints(vec![Constraint::Percentage(70), Constraint::Percentage(30)]) + .split(area), + Self::CliVertical => Layout::default() + .direction(Direction::Horizontal) + .constraints(vec![Constraint::Percentage(30), Constraint::Percentage(70)]) + .split(area), + } } - } - pub fn generate(&self) -> RenderLayout { - match self { - RenderLayoutKind::CliVertical => { - RenderLayout { - kind: self.clone(), - panes: vec![ - Pane { - title: Some(" Input Pane ".to_string()), - target: RenderPane::CliInput, - buffer: RenderBuffer::List{ - list: vec![String::new()], - index: 0 - }, - focused: true, - scroll: 0, - max_scroll: 0, + pub fn generate(&self) -> RenderLayout { + match self { + RenderLayoutKind::CliVertical => RenderLayout { + kind: self.clone(), + panes: vec![ + Pane { + title: Some(" Input Pane ".to_string()), + target: RenderPane::CliInput, + buffer: RenderBuffer::List { + list: vec![String::new()], + index: 0, + }, + focused: true, + scroll: 0, + max_scroll: 0, + }, + Pane { + title: Some(" Output Pane ".to_string()), + target: RenderPane::CliOutput, + buffer: RenderBuffer::String(String::new()), + focused: false, + scroll: 0, + max_scroll: 0, + }, + ], }, - Pane { - title: Some(" Output Pane ".to_string()), - target: RenderPane::CliOutput, - buffer: RenderBuffer::String(String::new()), - focused: false, - scroll: 0, - max_scroll: 0, + RenderLayoutKind::CliHorizontal => RenderLayout { + kind: self.clone(), + panes: vec![ + Pane { + title: Some(" Output Pane ".to_string()), + target: RenderPane::CliOutput, + buffer: RenderBuffer::String(String::new()), + focused: false, + scroll: 0, + max_scroll: 0, + }, + Pane { + title: Some(" Input Pane ".to_string()), + target: RenderPane::CliInput, + buffer: RenderBuffer::List { + list: vec![String::new()], + index: 0, + }, + focused: true, + scroll: 0, + max_scroll: 0, + }, + ], }, - ] } - } - RenderLayoutKind::CliHorizontal => { - RenderLayout { - kind: self.clone(), - panes: vec![ - Pane { - title: Some(" Output Pane ".to_string()), - target: RenderPane::CliOutput, - buffer: RenderBuffer::String(String::new()), - focused: false, - scroll: 0, - max_scroll: 0, - }, - Pane { - title: Some(" Input Pane ".to_string()), - target: RenderPane::CliInput, - buffer: RenderBuffer::List{ - list: vec![String::new()], - index: 0 - }, - focused: true, - scroll: 0, - max_scroll: 0, - }, - ] - } - } } - } } #[allow(dead_code)] impl Renderer { - pub fn new(layout: RenderLayoutKind) -> Self { - Self { - buffer: String::new(), - exit: false, - layout: layout.generate(), + pub fn new(layout: RenderLayoutKind) -> Self { + Self { + buffer: String::new(), + exit: false, + layout: layout.generate(), + } } - } - pub async fn run(&mut self) -> io::Result<()> { - self.log(msg!(INFO, "Started Renderer")); - let mut rx = subscribe_render_event(); - let mut terminal = ratatui::init(); - publish_system_event(SystemEvent::RendererStarted); + pub async fn run(&mut self) -> io::Result<()> { + self.log(msg!(INFO, "Started Renderer")); + let mut rx = subscribe_render_event(); + let mut terminal = ratatui::init(); + publish_system_event(SystemEvent::RendererStarted); - let mut render_interval = interval(Duration::from_millis(32)); // 60 FPS + let mut render_interval = interval(Duration::from_millis(32)); // 60 FPS - while !self.exit { - tokio::select! { - _ = render_interval.tick() => { - terminal.draw(|frame| self.draw(frame))?; + while !self.exit { + tokio::select! { + _ = render_interval.tick() => { + terminal.draw(|frame| self.draw(frame))?; + } + mes = rx.recv() => { + if let Ok(mes) = mes { + let frame = terminal.get_frame(); + let rects = self.layout.kind.rects(frame.area()); + self.apply(mes, rects); + } + } } - mes = rx.recv() => { - if let Ok(mes) = mes { - let frame = terminal.get_frame(); - let rects = self.layout.kind.rects(frame.area()); - self.apply(mes, rects); + } + ratatui::restore(); + Ok(()) + } + + fn log(&mut self, msg: String) { + self.buffer.push_str(&msg) + } + + pub fn draw(&mut self, frame: &mut Frame) { + frame.render_widget(self, frame.area()); + } + + fn exit(&mut self) { + log!(DEBUG, "Renderer Exit"); + self.exit = true; + } + + fn buffer_extend>(&mut self, input: S) { + self.buffer.push_str(input.as_ref()); + } + + fn input_pane(&mut self) -> Option<&mut Pane> { + self.layout + .panes + .iter_mut() + .find(|p| p.target == RenderPane::CliInput) + } + + fn focused(&mut self) -> Option<&mut Pane> { + self.layout.panes.iter_mut().find(|p| p.focused == true) + } + + fn handle_mouse_click_left(&mut self, x: u16, y: u16, rects: std::rc::Rc<[Rect]>) { + for (i, r) in rects.iter().enumerate() { + if r.contains(layout::Position { x, y }) { + self.layout.panes[i].focused = true; + } else { + self.layout.panes[i].focused = false; + } + } + } + + fn apply(&mut self, mes: RenderCommand, rects: std::rc::Rc<[Rect]>) { + match mes { + RenderCommand::MouseClickLeft(x, y) => { + self.handle_mouse_click_left(x, y, rects); + } + RenderCommand::MouseScrollUp => { + if let Some(p) = self.focused() { + if p.scroll < p.max_scroll { + p.scroll += 1; + } + } + } + RenderCommand::MouseScrollDown => { + if let Some(p) = self.focused() { + if p.scroll > i16::MIN { + p.scroll -= 1; + } + } + } + RenderCommand::RenderInput(k) => { + if let Some(p) = self.layout.panes.iter_mut().find(|p| p.focused) { + match k { + KeyCode::Char(c) => { + if let RenderBuffer::List { list, index } = &mut p.buffer { + list[*index].push(c); + } + } + KeyCode::Backspace => { + if let RenderBuffer::List { list, index } = &mut p.buffer { + list[*index].pop(); + } + } + KeyCode::Enter => { + if let RenderBuffer::List { list, index } = &mut p.buffer { + list.push(String::new()); + *index += 1; + } + } + _ => {} + } + } + } + + RenderCommand::ListMove { pane, index } => { + if let Some(p) = self.layout.panes.iter_mut().find(|p| p.target == pane) { + if let RenderBuffer::List { list, index: idx } = &mut p.buffer { + if index > 0 && index < list.len() { + list[*idx] = list[index].clone(); + } + } + } + } + + RenderCommand::RenderStringToPane { str, pane } => { + if let Some(p) = self.layout.panes.iter_mut().find(|p| p.target == pane) { + match &mut p.buffer { + RenderBuffer::List { list, index } => { + list.push(str); + *index += 1; + } + RenderBuffer::String(s) => s.push_str(&str), + } + } + } + RenderCommand::Exit => { + self.exit(); + } + RenderCommand::ChangeLayout(l) => { + self.layout = l.generate(); + } + RenderCommand::ClearPane(pane) => { + if matches!(pane, RenderPane::All) { + for p in self.layout.panes.iter_mut() { + match &mut p.buffer { + RenderBuffer::List { list, index } => { + list.clear(); + *index = 0; + list.push(String::new()); + } + RenderBuffer::String(s) => s.clear(), + } + } + } else if let Some(p) = self.layout.panes.iter_mut().find(|p| p.target == pane) { + match &mut p.buffer { + RenderBuffer::List { list, index } => { + list.clear(); + *index = 0; + list.push(String::new()); + } + RenderBuffer::String(s) => s.clear(), + } } } } } - ratatui::restore(); - Ok(()) - } - fn log(&mut self, msg: String) { - self.buffer.push_str(&msg) - } - - pub fn draw(&mut self, frame: &mut Frame) { - frame.render_widget(self, frame.area()); - } - - fn exit(&mut self) { - log!(DEBUG, "Renderer Exit"); - self.exit = true; - } - - fn buffer_extend>(&mut self, input: S) { - self.buffer.push_str(input.as_ref()); - } - - fn input_pane(&mut self) -> Option<&mut Pane> { - self.layout.panes.iter_mut().find(|p| p.target == RenderPane::CliInput) - } - - fn focused(&mut self) -> Option<&mut Pane> { - self.layout.panes.iter_mut().find(|p| p.focused == true) - } - - fn handle_mouse_click_left(&mut self, x: u16, y: u16, rects: std::rc::Rc<[Rect]>) { - for (i, r) in rects.iter().enumerate() { - if r.contains(layout::Position{x, y}) { - self.layout.panes[i].focused = true; - } else { - self.layout.panes[i].focused = false; - } + async fn listen( + &mut self, + rx: &mut tokio::sync::broadcast::Receiver, + ) -> Result { + if let Ok(Ok(mes)) = timeout(Duration::from_millis(400), rx.recv()).await { + return Ok(mes); + } + Err(()) } - } - - fn apply(&mut self, mes: RenderCommand, rects: std::rc::Rc<[Rect]>) { - match mes { - RenderCommand::MouseClickLeft(x, y) => { - self.handle_mouse_click_left(x, y, rects); - } - RenderCommand::MouseScrollUp => { - if let Some(p) = self.focused() { - if p.scroll < p.max_scroll { - p.scroll += 1; - } - } - } - RenderCommand::MouseScrollDown => { - if let Some(p) = self.focused() { - if p.scroll > i16::MIN { - p.scroll -= 1; - } - } - } - RenderCommand::RenderInput(k) => { - if let Some(p) = self.layout.panes.iter_mut().find(|p| p.focused) { - match k { - KeyCode::Char(c) => { - if let RenderBuffer::List{list, index} = &mut p.buffer { - list[*index].push(c); - } - } - KeyCode::Backspace => { - if let RenderBuffer::List{list, index} = &mut p.buffer { - list[*index].pop(); - } - } - KeyCode::Enter => { - if let RenderBuffer::List{list, index} = &mut p.buffer { - list.push(String::new()); - *index += 1; - } - } - _ => {} - } - } - }, - - RenderCommand::ListMove{ pane, index } => { - if let Some(p) = self.layout.panes.iter_mut().find(|p| p.target == pane) { - if let RenderBuffer::List { list, index: idx } = &mut p.buffer { - if index > 0 && index < list.len() { - list[*idx] = list[index].clone(); - } - } - } - } - - RenderCommand::RenderStringToPane{ str, pane } => { - if let Some(p) = self.layout.panes.iter_mut().find(|p| p.target == pane) { - match &mut p.buffer { - RenderBuffer::List { list, index } => { - list.push(str); - *index += 1; - } - RenderBuffer::String(s) => { - s.push_str(&str) - } - } - } - } - RenderCommand::Exit => { - self.exit(); - } - RenderCommand::ChangeLayout(l) => { - self.layout = l.generate(); - } - RenderCommand::ClearPane(pane) => { - if matches!(pane, RenderPane::All) { - for p in self.layout.panes.iter_mut() { - match &mut p.buffer { - RenderBuffer::List { list, index } => { - list.clear(); - *index = 0; - list.push(String::new()); - } - RenderBuffer::String(s) => s.clear() - } - } - } else if let Some(p) = self.layout.panes.iter_mut().find(|p| p.target == pane) { - match &mut p.buffer { - RenderBuffer::List { list, index } => { - list.clear(); - *index = 0; - list.push(String::new()); - } - RenderBuffer::String(s) => s.clear() - } - } - } - } - } - - async fn listen(&mut self, rx: &mut tokio::sync::broadcast::Receiver) -> Result { - if let Ok(Ok(mes)) = timeout(Duration::from_millis(400), rx.recv()).await { - return Ok(mes); - } - Err(()) - } } impl Widget for &mut Renderer { - fn render(self, area: Rect, buf: &mut Buffer) { - - let rects = self.layout.kind.rects(area); - for (i, p) in self.layout.panes.iter_mut().enumerate() { - p.render(rects[i], buf) + fn render(self, area: Rect, buf: &mut Buffer) { + let rects = self.layout.kind.rects(area); + for (i, p) in self.layout.panes.iter_mut().enumerate() { + p.render(rects[i], buf) + } } - } } diff --git a/node/src/watcher/watcher.rs b/node/src/watcher/watcher.rs index 44b5b4f..be6e91e 100644 --- a/node/src/watcher/watcher.rs +++ b/node/src/watcher/watcher.rs @@ -1,316 +1,346 @@ use crossterm::event::{self, Event, KeyCode, KeyEventKind, MouseButton, MouseEventKind}; use memory_stats::memory_stats; +use std::{ + io::{self, Write}, + net::SocketAddr, + time::Duration, +}; use tokio::sync::mpsc; -use std::{io::{self, Write}, net::SocketAddr, time::Duration}; -use crate::{error::print_error_chain, event_bus::{subscribe_system_event, NetworkEvent, SystemEvent}, native_node::node::{NativeNode, NodeCommand}}; +use crate::{ + error::print_error_chain, + bus::{NetworkEvent, SystemEvent, subscribe_system_event}, + node::node::{Node, NodeCommand}, +}; use vlogger::*; use super::*; +use crate::bus::{ publish_render_event }; use crate::log; -use crate::event_bus::publish_render_event; #[allow(dead_code)] pub struct Watcher { - parser_tx: mpsc::Sender, - node_tx: mpsc::Sender, - exec_tx: mpsc::Sender, - cmd_buffer: String, - cmd_history: Vec, - history_index: usize, - handles: Vec> + parser_tx: mpsc::Sender, + node_tx: mpsc::Sender, + exec_tx: mpsc::Sender, + cmd_buffer: String, + cmd_history: Vec, + history_index: usize, + handles: Vec>, } impl Watcher { - pub fn build() -> WatcherBuilder { - WatcherBuilder::new() - } - - pub fn parser_tx(&self) -> mpsc::Sender { - self.parser_tx.clone() - } - - pub fn exec_tx(&self) -> mpsc::Sender { - self.exec_tx.clone() - } - - pub async fn exit(self) { - let rd_mes = RenderCommand::Exit; - let pr_mes = ParserCommand::Exit; - let exec_mes = ExecutorCommand::Exit; - let node_mes = NodeCommand::Exit; - publish_render_event(rd_mes); - let _ = self.parser_tx.send(pr_mes).await; - let _ = self.exec_tx.send(exec_mes).await; - let _ = self.node_tx.send(node_mes).await; - } - - pub async fn log_memory() { - tokio::spawn(async move { - let id = format!("{}_{}", current_timestamp(), std::process::id()); - let mut path = std::path::PathBuf::new(); - path.push("./proc/"); - path.push(id); - let mut mem_map = std::fs::OpenOptions::new().create(true).write(true).truncate(true).open(path).unwrap(); - loop { - let _ = tokio::time::sleep(Duration::from_secs(30)).await; - if let Some(usage) = memory_stats() { - let current = current_timestamp(); - let _ = mem_map.write_all(msg!(INFO, "{}: Physical memory usage: {} MB", current, usage.physical_mem / 1024 / 1024).as_bytes()); - let _ = mem_map.write_all(msg!(INFO, "{}: Virtual memory usage: {} MB", current, usage.virtual_mem / 1024 / 1024).as_bytes()); - } - } - }); - } - - - pub async fn poll(&mut self) -> io::Result { - match event::read()? { - Event::Mouse(event) => { - match event.kind { - MouseEventKind::ScrollUp => { publish_render_event(RenderCommand::MouseScrollUp); } - MouseEventKind::ScrollDown => { publish_render_event(RenderCommand::MouseScrollDown); } - MouseEventKind::Down(b) => { - match b { - MouseButton::Left => { - publish_render_event(RenderCommand::MouseClickLeft(event.column, event.row)); - } - _ => {} - } - } - _ => {} - } - } - Event::Key(k) if k.kind == KeyEventKind::Press => { - match k.code { - KeyCode::Char(c) => { - self.cmd_buffer.push(c); - let message = RenderCommand::RenderInput(k.code); - publish_render_event(message); - } - KeyCode::Backspace => { - self.cmd_buffer.pop(); - let message = RenderCommand::RenderInput(k.code); - publish_render_event(message); - }, - KeyCode::Enter => { - let rd_mes = RenderCommand::RenderInput(k.code); - let pr_mes = ParserCommand::ParseCmdString(self.cmd_buffer.clone()); - let _ = self.parser_tx.send(pr_mes).await; - publish_render_event(rd_mes); - self.cmd_buffer.clear(); - } - KeyCode::Up => { - if self.history_index > 0 { - self.history_index -= 1; - let rd_mes = RenderCommand::ListMove{ - pane: RenderPane::CliInput, - index: self.history_index, - }; - publish_render_event(rd_mes); - } - } - KeyCode::Down => { - if self.history_index < self.cmd_buffer.len() { - self.history_index += 1; - let rd_mes = RenderCommand::ListMove{ - pane: RenderPane::CliInput, - index: self.history_index, - }; - publish_render_event(rd_mes); - } - } - KeyCode::Esc => { - return Ok(false); - } - _ => {} - }; - } - _ => {} + pub fn build() -> WatcherBuilder { + WatcherBuilder::new() + } + + pub fn parser_tx(&self) -> mpsc::Sender { + self.parser_tx.clone() + } + + pub fn exec_tx(&self) -> mpsc::Sender { + self.exec_tx.clone() + } + + pub async fn exit(self) { + let rd_mes = RenderCommand::Exit; + let pr_mes = ParserCommand::Exit; + let exec_mes = ExecutorCommand::Exit; + let node_mes = NodeCommand::Exit; + publish_render_event(rd_mes); + let _ = self.parser_tx.send(pr_mes).await; + let _ = self.exec_tx.send(exec_mes).await; + let _ = self.node_tx.send(node_mes).await; + } + + pub async fn log_memory() { + tokio::spawn(async move { + let id = format!("{}_{}", current_timestamp(), std::process::id()); + let mut path = std::path::PathBuf::new(); + path.push("./proc/"); + path.push(id); + let mut mem_map = std::fs::OpenOptions::new() + .create(true) + .write(true) + .truncate(true) + .open(path) + .unwrap(); + loop { + let _ = tokio::time::sleep(Duration::from_secs(10)).await; + if let Some(usage) = memory_stats() { + let current = current_timestamp(); + let _ = mem_map.write_all( + msg!( + INFO, + "{}: Physical memory usage: {} MB", + current, + usage.physical_mem / 1024 / 1024 + ) + .as_bytes(), + ); + let _ = mem_map.write_all( + msg!( + INFO, + "{}: Virtual memory usage: {} MB", + current, + usage.virtual_mem / 1024 / 1024 + ) + .as_bytes(), + ); + } + } + }); + } + + pub async fn poll(&mut self) -> io::Result { + match event::read()? { + Event::Mouse(event) => match event.kind { + MouseEventKind::ScrollUp => { + publish_render_event(RenderCommand::MouseScrollUp); + } + MouseEventKind::ScrollDown => { + publish_render_event(RenderCommand::MouseScrollDown); + } + MouseEventKind::Down(b) => match b { + MouseButton::Left => { + publish_render_event(RenderCommand::MouseClickLeft( + event.column, + event.row, + )); + } + _ => {} + }, + _ => {} + }, + Event::Key(k) if k.kind == KeyEventKind::Press => { + match k.code { + KeyCode::Char(c) => { + self.cmd_buffer.push(c); + let message = RenderCommand::RenderInput(k.code); + publish_render_event(message); + } + KeyCode::Backspace => { + self.cmd_buffer.pop(); + let message = RenderCommand::RenderInput(k.code); + publish_render_event(message); + } + KeyCode::Enter => { + let rd_mes = RenderCommand::RenderInput(k.code); + let pr_mes = ParserCommand::ParseCmdString(self.cmd_buffer.clone()); + let _ = self.parser_tx.send(pr_mes).await; + publish_render_event(rd_mes); + self.cmd_buffer.clear(); + } + KeyCode::Up => { + if self.history_index > 0 { + self.history_index -= 1; + let rd_mes = RenderCommand::ListMove { + pane: RenderPane::CliInput, + index: self.history_index, + }; + publish_render_event(rd_mes); + } + } + KeyCode::Down => { + if self.history_index < self.cmd_buffer.len() { + self.history_index += 1; + let rd_mes = RenderCommand::ListMove { + pane: RenderPane::CliInput, + index: self.history_index, + }; + publish_render_event(rd_mes); + } + } + KeyCode::Esc => { + return Ok(false); + } + _ => {} + }; + } + _ => {} + } + Ok(true) } - Ok(true) - } } #[derive(Default)] pub struct WatcherBuilder { - addr: Option, - seed_file: Option, - bootstrap: bool, - debug: bool, - seed: bool, - render: bool, + addr: Option, + database: Option, + bootstrap: bool, + debug: bool, + seed: bool, + render: bool, } impl WatcherBuilder { - fn new() -> Self { - Self::default() - } - - pub fn addr(mut self, addr: Option) -> Self { - self.addr = addr; - self - } - - pub fn file(mut self, seed_file: Option) -> Self { - self.seed_file = seed_file; - self.seed = true; - self - } - - pub fn debug(mut self, debug: bool) -> Self { - self.debug = debug; - self - } - - pub fn bootstrap(mut self, bootstrap: bool) -> Self { - self.bootstrap = bootstrap; - self - } - - pub fn render(mut self, render: bool) -> Self { - self.render = render; - self - } - - pub fn seed(mut self, seed: bool) -> Self { - self.seed = seed; - self - } - - pub async fn start(mut self) -> Watcher { - let (parser_tx, parser_rx) = mpsc::channel::(100); - let (exec_tx, exec_rx) = mpsc::channel::(100); - let mut sys_event = subscribe_system_event(); - - if self.debug { - Watcher::log_memory().await; + fn new() -> Self { + Self::default() } - let render_handle = if self.render { - Some(tokio::spawn({ - async move { - let _ = Renderer::new(RenderLayoutKind::CliHorizontal).run().await; - } - })) - } else { - None - }; - - for i in 0..3 { - if let Ok(ev) = sys_event.recv().await { - match ev { - SystemEvent::RendererStarted => { - log(msg!(INFO, "Renderer Started")); - break; - }, - _ => { log(msg!(WARNING, "Wrong Event: {ev:?}! Retrying... (try {i})")) } - } - } + pub fn addr(mut self, addr: Option) -> Self { + self.addr = addr; + self } + pub fn database(mut self, database: Option) -> Self { + self.database = database; + self + } - let parser_handle = tokio::spawn({ - let exec_tx = exec_tx.clone(); - async move { - let _ = Parser::new(parser_rx, exec_tx).run().await; - } - }); + pub fn debug(mut self, debug: bool) -> Self { + self.debug = debug; + self + } - log(msg!(DEBUG, "Seed File: {:?}", self.seed_file)); - let blocks = self.seed_file - .as_ref() - .and_then(|path| { - log(msg!(INFO, "Reading chain data from {path}")); - match std::fs::read_to_string(path) { - Ok(s) => Some(s), - Err(e) => { - print_error_chain(e.into()); + pub fn bootstrap(mut self, bootstrap: bool) -> Self { + self.bootstrap = bootstrap; + self + } + + pub fn render(mut self, render: bool) -> Self { + self.render = render; + self + } + + pub fn seed(mut self, seed: bool) -> Self { + self.seed = seed; + self + } + + pub async fn start(mut self) -> Watcher { + let (parser_tx, parser_rx) = mpsc::channel::(100); + let (exec_tx, exec_rx) = mpsc::channel::(100); + let mut sys_event = subscribe_system_event(); + + if self.debug { + Watcher::log_memory().await; + } + + let render_handle = if self.render { + Some(tokio::spawn({ + async move { + let _ = Renderer::new(RenderLayoutKind::CliHorizontal).run().await; + } + })) + } else { None - }, - } - }) - .unwrap_or_default(); + }; - if self.seed { - self.addr = Some(crate::seeds_constants::SEED_NODES[0]); - } - - let mut node = NativeNode::new(self.addr.clone(), &blocks, exec_tx.clone()).await; - log(msg!(INFO, "Built Node")); - - let executor_handle = tokio::spawn({ - let node_tx = node.tx(); - async move { - let _ = Executor::new(node_tx, exec_rx).run().await; - } - }); - - for i in 0..3 { - if let Ok(ev) = sys_event.recv().await { - match ev { - SystemEvent::ExecutorStarted => { - log(msg!(INFO, "Executor Started")); - break; - }, - _ => { log(msg!(WARNING, "Wrong Event: {ev:?}! Retrying... (try {i})")) } - } - } - } - - let node_tx = node.tx(); - let node_handle = tokio::spawn({ - async move { - node.run().await; - } - }); - - for i in 0..3 { - if let Ok(ev) = sys_event.recv().await { - match ev { - SystemEvent::NodeStarted => { - log(msg!(INFO, "Executor Started")); - break; - }, - _ => { log(msg!(WARNING, "Wrong Event: {ev:?}! Retrying... (try {i})")) } - } - } - } - - if self.bootstrap { - let exec_tx = exec_tx.clone(); - - tokio::spawn(async move { - let seed_cmd = ExecutorCommand::Node(NodeCommand::ConnectToSeeds); - let mut ev_rx = crate::event_bus::subscribe_network_event(); - let _ = exec_tx.send(seed_cmd).await; - - while let Ok(e) = ev_rx.recv().await { - match e { - NetworkEvent::SeedConnected(_) => { - let bootstrap_cmd = ExecutorCommand::Node(NodeCommand::BootStrap); - let _ = exec_tx.send(bootstrap_cmd).await; + for i in 0..3 { + if let Ok(ev) = sys_event.recv().await { + match ev { + SystemEvent::RendererStarted => { + log(msg!(INFO, "Renderer Started")); + break; + } + _ => log(msg!(WARNING, "Wrong Event: {ev:?}! Retrying... (try {i})")), + } } - _ => {} - } } - }); - } - Watcher { - node_tx, - cmd_history: Vec::new(), - history_index: 0, - parser_tx, - exec_tx, - cmd_buffer: String::new(), - handles: { - let mut h = vec![parser_handle, executor_handle, node_handle]; - if render_handle.is_some() { - h.push(render_handle.unwrap()); + + let parser_handle = tokio::spawn({ + let exec_tx = exec_tx.clone(); + async move { + let _ = Parser::new(parser_rx, exec_tx).run().await; + } + }); + + log(msg!(DEBUG, "Database Location: {:?}", self.database)); + let db = self + .database + .as_ref() + .and_then(|path| { + log(msg!(INFO, "Reading chain data from {path}")); + match std::fs::read_to_string(path) { + Ok(s) => Some(s), + Err(e) => { + print_error_chain(e.into()); + None + } + } + }) + .unwrap_or_default(); + + if self.seed { + self.addr = Some(crate::seeds_constants::SEED_NODES[0]); + } + + let mut node = Node::new(self.addr.clone(), &blocks, exec_tx.clone()).await; + log(msg!(INFO, "Built Node")); + + let executor_handle = tokio::spawn({ + let node_tx = node.tx(); + async move { + let _ = Executor::new(node_tx, exec_rx).run().await; + } + }); + + for i in 0..3 { + if let Ok(ev) = sys_event.recv().await { + match ev { + SystemEvent::ExecutorStarted => { + log(msg!(INFO, "Executor Started")); + break; + } + _ => log(msg!(WARNING, "Wrong Event: {ev:?}! Retrying... (try {i})")), + } + } + } + + let node_tx = node.tx(); + let node_handle = tokio::spawn({ + async move { + node.run().await; + } + }); + + for i in 0..3 { + if let Ok(ev) = sys_event.recv().await { + match ev { + SystemEvent::NodeStarted => { + log(msg!(INFO, "Executor Started")); + break; + } + _ => log(msg!(WARNING, "Wrong Event: {ev:?}! Retrying... (try {i})")), + } + } + } + + if self.bootstrap { + let exec_tx = exec_tx.clone(); + + tokio::spawn(async move { + let seed_cmd = ExecutorCommand::Node(NodeCommand::ConnectToSeeds); + let mut ev_rx = crate::bus::subscribe_network_event(); + let _ = exec_tx.send(seed_cmd).await; + + while let Ok(e) = ev_rx.recv().await { + match e { + NetworkEvent::SeedConnected(_) => { + let bootstrap_cmd = ExecutorCommand::Node(NodeCommand::BootStrap); + let _ = exec_tx.send(bootstrap_cmd).await; + } + _ => {} + } + } + }); + } + Watcher { + node_tx, + cmd_history: Vec::new(), + history_index: 0, + parser_tx, + exec_tx, + cmd_buffer: String::new(), + handles: { + let mut h = vec![parser_handle, executor_handle, node_handle]; + if render_handle.is_some() { + h.push(render_handle.unwrap()); + } + h + }, } - h - } } - } }