diff --git a/Cargo.lock b/Cargo.lock index fc6e3beb..b8fb106d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -686,18 +686,19 @@ dependencies = [ [[package]] name = "clap" -version = "4.4.8" +version = "4.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2275f18819641850fa26c89acc84d465c1bf91ce57bc2748b28c420473352f64" +checksum = "41fffed7514f420abec6d183b1d3acfd9099c79c3a10a06ade4f8203f1411272" dependencies = [ "clap_builder", + "clap_derive", ] [[package]] name = "clap_builder" -version = "4.4.8" +version = "4.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07cdf1b148b25c1e1f7a42225e30a0d99a615cd4637eae7365548dd4529b95bc" +checksum = "63361bae7eef3771745f02d8d892bec2fee5f6e34af316ba556e7f97a7069ff1" dependencies = [ "anstream", "anstyle", @@ -705,6 +706,18 @@ dependencies = [ "strsim 0.10.0", ] +[[package]] +name = "clap_derive" +version = "4.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.32", +] + [[package]] name = "clap_lex" version = "0.6.0" @@ -1712,7 +1725,7 @@ dependencies = [ "futures-timer", "futures-util", "hashers", - "http", + "http 0.2.9", "instant", "jsonwebtoken", "once_cell", @@ -2141,7 +2154,7 @@ dependencies = [ "futures-core", "futures-sink", "futures-util", - "http", + "http 0.2.9", "indexmap 1.9.3", "slab", "tokio", @@ -2192,7 +2205,7 @@ dependencies = [ "base64 0.21.4", "bytes", "headers-core", - "http", + "http 0.2.9", "httpdate", "mime", "sha1", @@ -2204,7 +2217,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" dependencies = [ - "http", + "http 0.2.9", ] [[package]] @@ -2276,6 +2289,17 @@ dependencies = [ "itoa", ] +[[package]] +name = "http" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b32afd38673a8016f7c9ae69e5af41a58f81b1d31689040f2f1959594ce194ea" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + [[package]] name = "http-body" version = "0.4.5" @@ -2283,7 +2307,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" dependencies = [ "bytes", - "http", + "http 0.2.9", "pin-project-lite", ] @@ -2310,7 +2334,7 @@ dependencies = [ "futures-core", "futures-util", "h2", - "http", + "http 0.2.9", "http-body", "httparse", "httpdate", @@ -2330,7 +2354,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d78e1e73ec14cf7375674f74d7dde185c8206fd9dea6fb6295e8a98098aaa97" dependencies = [ "futures-util", - "http", + "http 0.2.9", "hyper", "rustls", "tokio", @@ -2889,7 +2913,7 @@ dependencies = [ "bytes", "encoding_rs", "futures-util", - "http", + "http 0.2.9", "httparse", "log", "memchr", @@ -3546,7 +3570,7 @@ dependencies = [ "dns-lookup", "futures-core", "futures-util", - "http", + "http 0.2.9", "hyper", "hyper-system-resolver", "pin-project-lite", @@ -3724,7 +3748,7 @@ dependencies = [ "futures-core", "futures-util", "h2", - "http", + "http 0.2.9", "http-body", "hyper", "hyper-rustls", @@ -3871,7 +3895,7 @@ dependencies = [ "bytes", "crc32fast", "futures", - "http", + "http 0.2.9", "hyper", "hyper-tls", "lazy_static", @@ -3929,7 +3953,7 @@ dependencies = [ "futures", "hex", "hmac 0.11.0", - "http", + "http 0.2.9", "hyper", "log", "md-5 0.9.1", @@ -4969,7 +4993,7 @@ dependencies = [ "base64 0.13.1", "byteorder", "bytes", - "http", + "http 0.2.9", "httparse", "log", "rand", @@ -4988,7 +5012,7 @@ dependencies = [ "byteorder", "bytes", "data-encoding", - "http", + "http 0.2.9", "httparse", "log", "rand", @@ -5121,7 +5145,7 @@ dependencies = [ "hex", "hkdf", "hmac 0.12.1", - "http", + "http 0.2.9", "jwt", "lazy_static", "log", @@ -5159,13 +5183,17 @@ dependencies = [ [[package]] name = "uqbar_process_lib" -version = "0.2.0" -source = "git+ssh://git@github.com/uqbar-dao/process_lib.git?rev=e53c124#e53c124ec95ef99c06d201d4d08dada8ec691d29" +version = "0.3.0" +source = "git+ssh://git@github.com/uqbar-dao/process_lib.git?rev=77ebb26#77ebb261bf74f2183fb81856ce9a6b66b8360a6d" dependencies = [ "anyhow", "bincode", + "http 1.0.0", "rand", "serde", + "serde_json", + "thiserror", + "url", "wit-bindgen", ] @@ -5253,7 +5281,7 @@ dependencies = [ "futures-channel", "futures-util", "headers", - "http", + "http 0.2.9", "hyper", "log", "mime", diff --git a/Cargo.toml b/Cargo.toml index 1a0113bf..a0fef50c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,8 +1,9 @@ [package] name = "uqbar" +authors = ["UqbarDAO"] version = "0.4.0" edition = "2021" -description = "a general-purpose sovereign cloud computing platform" +description = "A general-purpose sovereign cloud computing platform" homepage = "https://uqbar.network" repository = "https://github.com/uqbar-dao/uqbar" @@ -13,6 +14,9 @@ sha2 = "0.10" walkdir = "2.4" zip = "0.6" +[features] +llm = [] +simulation-mode = [] [dependencies] aes-gcm = "0.10.2" @@ -26,6 +30,7 @@ bytes = "1.4.0" cap-std = "2.0.0" chacha20poly1305 = "0.10.1" chrono = "0.4.31" +clap = { version = "4.4", features = ["derive"] } crossterm = { version = "0.26.1", features = ["event-stream", "bracketed-paste"] } dashmap = "5.5.3" digest = "0.10" @@ -44,6 +49,7 @@ http = "0.2.9" jwt = "0.16" lazy_static = "1.4.0" log = "*" +lru-mem = "0.3.0" nohash-hasher = "0.2.0" num-traits = "0.2" open = "5.0.0" @@ -66,14 +72,9 @@ thiserror = "1.0" tokio = { version = "1.28", features = ["fs", "macros", "rt-multi-thread", "sync"] } tokio-tungstenite = "0.20.1" url = "2.4.1" -uqbar_process_lib = { git = "ssh://git@github.com/uqbar-dao/process_lib.git", rev = "e53c124" } +uqbar_process_lib = { git = "ssh://git@github.com/uqbar-dao/process_lib.git", rev = "77ebb26" } uuid = { version = "1.1.2", features = ["serde", "v4"] } warp = "0.3.5" wasmtime = "14.0.4" wasmtime-wasi = "14.0.4" zip = "0.6" -lru-mem = "0.3.0" -clap = "4.4.8" - -[features] -llm = [] diff --git a/README.md b/README.md index ffe439bd..8e9e6de4 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ Get an eth-sepolia-rpc API key and pass that as an argument. You can get one for Make sure not to use the same home directory for two nodes at once! You can use any name for the home directory: here we just use `home`. ```bash -cargo +nightly run --release home --rpc wss://eth-sepolia.g.alchemy.com/v2/ +cargo +nightly run --release -- home --rpc wss://eth-sepolia.g.alchemy.com/v2/ ``` On boot you will be prompted to navigate to `localhost:8080`. Make sure your ETH wallet is connected to the Sepolia test network. Login should be straightforward, just submit the transactions and follow the flow. If you want to register a new ID you will either need [Sepolia testnet tokens](https://www.infura.io/faucet/sepolia) or an invite code. diff --git a/modules/key_value/key_value/src/lib.rs b/modules/key_value/key_value/src/lib.rs index a9486cf0..4dfd2705 100644 --- a/modules/key_value/key_value/src/lib.rs +++ b/modules/key_value/key_value/src/lib.rs @@ -104,19 +104,23 @@ fn handle_message(our: &Address, db_to_process: &mut DbToProcess) -> anyhow::Res .send_and_await_response(15)??; // (2) - let vfs_read = wit::get_capability(&vfs_address, &make_vfs_cap("read", &vfs_drive)) - .ok_or(anyhow::anyhow!( - "New failed: no vfs 'read' capability found" - ))?; - let vfs_write = - wit::get_capability(&vfs_address, &make_vfs_cap("write", &vfs_drive)).ok_or( - anyhow::anyhow!("New failed: no vfs 'write' capability found"), - )?; + let vfs_read = wit::get_capability( + &vfs_address, + &make_vfs_cap("read", &vfs_drive) + ).ok_or(anyhow::anyhow!("New failed: no vfs 'read' capability found"))?; + let vfs_write = wit::get_capability( + &vfs_address, + &make_vfs_cap("write", &vfs_drive) + ).ok_or(anyhow::anyhow!("New failed: no vfs 'write' capability found"))?; + let messaging = wit::get_capability( + &source, + &"\"messaging\"".into(), + ).ok_or(anyhow::anyhow!("New failed: no source 'messaging' capability found"))?; let spawned_process_id = match wit::spawn( None, "/key_value_worker.wasm", &wit::OnPanic::None, // TODO: notify us - &wit::Capabilities::Some(vec![vfs_read, vfs_write]), + &wit::Capabilities::Some(vec![vfs_read, vfs_write, messaging]), false, // not public ) { Ok(spawned_process_id) => spawned_process_id, diff --git a/modules/key_value/key_value_worker/src/lib.rs b/modules/key_value/key_value_worker/src/lib.rs index 572e074d..aff2ece2 100644 --- a/modules/key_value/key_value_worker/src/lib.rs +++ b/modules/key_value/key_value_worker/src/lib.rs @@ -3,7 +3,7 @@ use std::collections::HashMap; use redb::ReadableTable; use serde::{Deserialize, Serialize}; -use uqbar_process_lib::{Address, ProcessId, Response}; +use uqbar_process_lib::{Address, create_capability, ProcessId, Response}; use uqbar_process_lib::uqbar::process::standard as wit; wit_bindgen::generate!({ @@ -178,6 +178,12 @@ impl Guest for Component { let our = Address::from_str(&our).unwrap(); let mut db_handle: Option = None; + let vfs_address = ProcessId::from_str("vfs:sys:uqbar").unwrap(); + create_capability( + &vfs_address, + &"\"messaging\"".into(), + ); + loop { match handle_message(&our, &mut db_handle) { Ok(()) => {}, diff --git a/modules/sqlite/sqlite/Cargo.lock b/modules/sqlite/sqlite/Cargo.lock index f58a1c38..1f9f0043 100644 --- a/modules/sqlite/sqlite/Cargo.lock +++ b/modules/sqlite/sqlite/Cargo.lock @@ -8,12 +8,6 @@ version = "1.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - [[package]] name = "bincode" version = "1.3.3" @@ -29,12 +23,6 @@ version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - [[package]] name = "bytes" version = "1.5.0" @@ -156,21 +144,6 @@ version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" -[[package]] -name = "num-traits" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" -dependencies = [ - "autocfg", -] - -[[package]] -name = "paste" -version = "1.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" - [[package]] name = "percent-encoding" version = "2.3.1" @@ -231,28 +204,6 @@ dependencies = [ "getrandom", ] -[[package]] -name = "rmp" -version = "0.8.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f9860a6cc38ed1da53456442089b4dfa35e7cedaa326df63017af88385e6b20" -dependencies = [ - "byteorder", - "num-traits", - "paste", -] - -[[package]] -name = "rmp-serde" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bffea85eea980d8a74453e5d02a8d93028f3c34725de143085a844ebe953258a" -dependencies = [ - "byteorder", - "rmp", - "serde", -] - [[package]] name = "ryu" version = "1.0.15" @@ -317,7 +268,6 @@ version = "0.1.0" dependencies = [ "anyhow", "bincode", - "rmp-serde", "serde", "serde_json", "thiserror", diff --git a/modules/sqlite/sqlite/Cargo.toml b/modules/sqlite/sqlite/Cargo.toml index 6cb5688e..b8b00634 100644 --- a/modules/sqlite/sqlite/Cargo.toml +++ b/modules/sqlite/sqlite/Cargo.toml @@ -13,7 +13,6 @@ lto = true [dependencies] anyhow = "1.0" bincode = "1.3.3" -rmp-serde = "1.1" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" thiserror = "1.0" diff --git a/modules/sqlite/sqlite/src/lib.rs b/modules/sqlite/sqlite/src/lib.rs index 8952019f..f46c9475 100644 --- a/modules/sqlite/sqlite/src/lib.rs +++ b/modules/sqlite/sqlite/src/lib.rs @@ -124,7 +124,7 @@ fn handle_message ( let spawned_process_id = match wit::spawn( None, "/sqlite_worker.wasm", - &wit::OnPanic::None, + &wit::OnPanic::None, &wit::Capabilities::Some(vec![vfs_read, vfs_write, msg_cap]), false, // not public ) { @@ -152,7 +152,7 @@ fn handle_message ( .ipc(ipc) .send()?; }, - sq::SqliteMessage::Write { ref db, ref statement, ref tx_id } => { + sq::SqliteMessage::Write { ref db, ref statement, .. } => { let first_word = statement .split_whitespace() .next() @@ -174,7 +174,7 @@ fn handle_message ( } forward_if_have_cap(our, "read", db, ipc, db_to_process)?; }, - sq::SqliteMessage::Commit { ref db, ref tx_id } => { + sq::SqliteMessage::Commit { ref db, .. } => { forward_if_have_cap(our, "write", db, ipc, db_to_process)?; }, } diff --git a/modules/sqlite/sqlite_types.rs b/modules/sqlite/sqlite_types.rs index d0349fbc..f5a60d2f 100644 --- a/modules/sqlite/sqlite_types.rs +++ b/modules/sqlite/sqlite_types.rs @@ -8,7 +8,7 @@ pub enum SqliteMessage { Commit { db: String, tx_id: u64 }, } -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] pub enum SqlValue { Integer(i64), Real(f64), @@ -18,16 +18,6 @@ pub enum SqlValue { Null, } -pub trait Deserializable: for<'de> Deserialize<'de> + Sized { - fn from_serialized(bytes: &[u8]) -> Result { - rmp_serde::from_slice(bytes) - } -} - -impl Deserializable for Vec {} -impl Deserializable for Vec> {} - - #[derive(Debug, Serialize, Deserialize, thiserror::Error)] pub enum SqliteError { #[error("DbDoesNotExist")] diff --git a/modules/sqlite/sqlite_worker/Cargo.lock b/modules/sqlite/sqlite_worker/Cargo.lock index fcdb9fc7..2ae4609e 100644 --- a/modules/sqlite/sqlite_worker/Cargo.lock +++ b/modules/sqlite/sqlite_worker/Cargo.lock @@ -25,12 +25,6 @@ version = "1.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - [[package]] name = "base64" version = "0.13.1" @@ -52,12 +46,6 @@ version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - [[package]] name = "bytes" version = "1.5.0" @@ -223,27 +211,12 @@ version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" -[[package]] -name = "num-traits" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" -dependencies = [ - "autocfg", -] - [[package]] name = "once_cell" version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" -[[package]] -name = "paste" -version = "1.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" - [[package]] name = "percent-encoding" version = "2.3.1" @@ -310,28 +283,6 @@ dependencies = [ "getrandom", ] -[[package]] -name = "rmp" -version = "0.8.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f9860a6cc38ed1da53456442089b4dfa35e7cedaa326df63017af88385e6b20" -dependencies = [ - "byteorder", - "num-traits", - "paste", -] - -[[package]] -name = "rmp-serde" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bffea85eea980d8a74453e5d02a8d93028f3c34725de143085a844ebe953258a" -dependencies = [ - "byteorder", - "rmp", - "serde", -] - [[package]] name = "rusqlite" version = "0.29.0" @@ -410,7 +361,6 @@ dependencies = [ "anyhow", "base64", "bincode", - "rmp-serde", "rusqlite", "serde", "serde_json", diff --git a/modules/sqlite/sqlite_worker/Cargo.toml b/modules/sqlite/sqlite_worker/Cargo.toml index a7298a05..501ecba8 100644 --- a/modules/sqlite/sqlite_worker/Cargo.toml +++ b/modules/sqlite/sqlite_worker/Cargo.toml @@ -12,13 +12,12 @@ lto = true [dependencies] anyhow = "1.0" +base64 = "0.13" bincode = "1.3.3" -rmp-serde = "1.1" rusqlite = { git = "https://github.com/uqbar-dao/rusqlite", rev = "8fb20a9", features = ["bundled", "wasm32-wasi-vfs"] } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" thiserror = "1.0" -base64 = "0.13" uqbar_process_lib = { git = "ssh://git@github.com/uqbar-dao/process_lib.git", rev = "7e4065c" } wit-bindgen = { git = "https://github.com/bytecodealliance/wit-bindgen", rev = "5390bab780733f1660d14c254ec985df2816bf1d" } diff --git a/modules/sqlite/sqlite_worker/src/lib.rs b/modules/sqlite/sqlite_worker/src/lib.rs index 17eb8ee6..a8209ab9 100644 --- a/modules/sqlite/sqlite_worker/src/lib.rs +++ b/modules/sqlite/sqlite_worker/src/lib.rs @@ -4,7 +4,7 @@ use std::ffi::CString; use rusqlite::{types::FromSql, types::FromSqlError, types::ToSql, types::ValueRef}; use std::collections::HashMap; -use uqbar_process_lib::{Address, ProcessId, Response, create_capability}; +use uqbar_process_lib::{Address, create_capability, ProcessId, Response}; use uqbar_process_lib::uqbar::process::standard as wit; @@ -519,7 +519,7 @@ fn handle_message( Ok(map) })? .collect::, _>>()?; - + let results = serde_json::json!(results).to_string(); let results_bytes = results.as_bytes().to_vec(); @@ -548,7 +548,6 @@ impl Guest for Component { let mut txs: HashMap)>> = HashMap::new(); let vfs_address = ProcessId::from_str("vfs:sys:uqbar").unwrap(); - create_capability( &vfs_address, &"\"messaging\"".into(), diff --git a/modules/tester/pkg/manifest.json b/modules/tester/pkg/manifest.json new file mode 100644 index 00000000..52add7ce --- /dev/null +++ b/modules/tester/pkg/manifest.json @@ -0,0 +1,15 @@ +[ + { + "process_name": "tester", + "process_wasm_path": "/tester.wasm", + "on_panic": "Restart", + "request_networking": true, + "request_messaging": [ + "net:sys:uqbar" + ], + "grant_messaging": [ + "vfs:sys:uqbar" + ], + "public": true + } +] diff --git a/modules/tester/pkg/metadata.json b/modules/tester/pkg/metadata.json new file mode 100644 index 00000000..1b5b73d5 --- /dev/null +++ b/modules/tester/pkg/metadata.json @@ -0,0 +1,5 @@ +{ + "package": "tester", + "publisher": "uqbar", + "version": [0, 1, 0] +} diff --git a/modules/tester/test_runner/Cargo-component.lock b/modules/tester/test_runner/Cargo-component.lock new file mode 100644 index 00000000..00bc239d --- /dev/null +++ b/modules/tester/test_runner/Cargo-component.lock @@ -0,0 +1,3 @@ +# This file is automatically generated by cargo-component. +# It is not intended for manual editing. +version = 1 diff --git a/modules/tester/test_runner/Cargo.lock b/modules/tester/test_runner/Cargo.lock new file mode 100644 index 00000000..18eaa038 --- /dev/null +++ b/modules/tester/test_runner/Cargo.lock @@ -0,0 +1,411 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "anyhow" +version = "1.0.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bitflags" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "hashbrown" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "id-arena" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005" + +[[package]] +name = "indexmap" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" +dependencies = [ + "equivalent", + "hashbrown", + "serde", +] + +[[package]] +name = "itoa" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" + +[[package]] +name = "leb128" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" + +[[package]] +name = "libc" +version = "0.2.150" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" + +[[package]] +name = "log" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "proc-macro2" +version = "1.0.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "ryu" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" + +[[package]] +name = "semver" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" + +[[package]] +name = "serde" +version = "1.0.188" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.188" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.105" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "693151e1ac27563d6dbcec9dee9fbd5da8539b20fa14ad3752b2e6d363ace360" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "smallvec" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" + +[[package]] +name = "spdx" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b19b32ed6d899ab23174302ff105c1577e45a06b08d4fe0a9dd13ce804bbbf71" +dependencies = [ + "smallvec", +] + +[[package]] +name = "syn" +version = "2.0.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "718fa2415bcb8d8bd775917a1bf12a7931b6dfa890753378538118181e0cb398" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "test_runner" +version = "0.1.0" +dependencies = [ + "anyhow", + "bincode", + "serde", + "serde_json", + "thiserror", + "uqbar_process_lib", + "wit-bindgen", +] + +[[package]] +name = "thiserror" +version = "1.0.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "unicode-ident" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" + +[[package]] +name = "unicode-segmentation" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" + +[[package]] +name = "unicode-xid" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" + +[[package]] +name = "uqbar_process_lib" +version = "0.2.0" +source = "git+https://github.com/uqbar-dao/process_lib?rev=e53c124#e53c124ec95ef99c06d201d4d08dada8ec691d29" +dependencies = [ + "anyhow", + "bincode", + "rand", + "serde", + "wit-bindgen", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-encoder" +version = "0.36.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "822b645bf4f2446b949776ffca47e2af60b167209ffb70814ef8779d299cd421" +dependencies = [ + "leb128", +] + +[[package]] +name = "wasm-metadata" +version = "0.10.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2167ce53b2faa16a92c6cafd4942cff16c9a4fa0c5a5a0a41131ee4e49fc055f" +dependencies = [ + "anyhow", + "indexmap", + "serde", + "serde_derive", + "serde_json", + "spdx", + "wasm-encoder", + "wasmparser", +] + +[[package]] +name = "wasmparser" +version = "0.116.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a58e28b80dd8340cb07b8242ae654756161f6fc8d0038123d679b7b99964fa50" +dependencies = [ + "indexmap", + "semver", +] + +[[package]] +name = "wit-bindgen" +version = "0.13.1" +source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=5390bab780733f1660d14c254ec985df2816bf1d#5390bab780733f1660d14c254ec985df2816bf1d" +dependencies = [ + "bitflags", + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen-core" +version = "0.13.1" +source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=5390bab780733f1660d14c254ec985df2816bf1d#5390bab780733f1660d14c254ec985df2816bf1d" +dependencies = [ + "anyhow", + "wit-component", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.13.2" +source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=5390bab780733f1660d14c254ec985df2816bf1d#5390bab780733f1660d14c254ec985df2816bf1d" +dependencies = [ + "anyhow", + "heck", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.13.1" +source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=5390bab780733f1660d14c254ec985df2816bf1d#5390bab780733f1660d14c254ec985df2816bf1d" +dependencies = [ + "anyhow", + "proc-macro2", + "quote", + "syn", + "wit-bindgen-core", + "wit-bindgen-rust", + "wit-component", +] + +[[package]] +name = "wit-component" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "480cc1a078b305c1b8510f7c455c76cbd008ee49935f3a6c5fd5e937d8d95b1e" +dependencies = [ + "anyhow", + "bitflags", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43771ee863a16ec4ecf9da0fc65c3bbd4a1235c8e3da5f094b562894843dfa76" +dependencies = [ + "anyhow", + "id-arena", + "indexmap", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", +] diff --git a/modules/tester/test_runner/Cargo.toml b/modules/tester/test_runner/Cargo.toml new file mode 100644 index 00000000..51eed120 --- /dev/null +++ b/modules/tester/test_runner/Cargo.toml @@ -0,0 +1,31 @@ +[package] +name = "test_runner" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[profile.release] +panic = "abort" +opt-level = "s" +lto = true + +[dependencies] +anyhow = "1.0" +bincode = "1.3.3" +serde = {version = "1.0", features = ["derive"] } +serde_json = "1.0" +thiserror = "1.0" +uqbar_process_lib = { git = "https://github.com/uqbar-dao/process_lib", rev = "e53c124" } +wit-bindgen = { git = "https://github.com/bytecodealliance/wit-bindgen", rev = "5390bab780733f1660d14c254ec985df2816bf1d" } + +[lib] +crate-type = ["cdylib"] + +[package.metadata.component] +package = "uqbar:process" + +[package.metadata.component.target] +path = "wit" + +[package.metadata.component.dependencies] diff --git a/modules/tester/test_runner/src/lib.rs b/modules/tester/test_runner/src/lib.rs new file mode 100644 index 00000000..b1c6f14a --- /dev/null +++ b/modules/tester/test_runner/src/lib.rs @@ -0,0 +1,133 @@ +use serde::{Serialize, Deserialize}; +use std::collections::{HashMap, HashSet}; + +use uqbar_process_lib::{Address, ProcessId, Request, Response}; +use uqbar_process_lib::kernel_types as kt; +use uqbar_process_lib::uqbar::process::standard as wit; + +mod tester_types; +use tester_types as tt; + +wit_bindgen::generate!({ + path: "../../../wit", + world: "process", + exports: { + world: Component, + }, +}); + +fn make_vfs_address(our: &wit::Address) -> anyhow::Result
{ + Ok(wit::Address { + node: our.node.clone(), + process: ProcessId::from_str("vfs:sys:uqbar")?, + }) +} + +fn handle_message(our: &Address) -> anyhow::Result<()> { + let (source, message) = wit::receive().unwrap(); + + if our.node != source.node { + return Err(tt::TesterError::RejectForeign.into()); + } + + match message { + wit::Message::Response(_) => { + return Err(tt::TesterError::UnexpectedResponse.into()); + }, + wit::Message::Request(wit::Request { ref ipc, .. }) => { + match serde_json::from_slice(ipc)? { + tt::TesterRequest::Run(_) => { + wit::print_to_terminal(0, "test_runner: got Run"); + + let (_, response) = Request::new() + .target(make_vfs_address(&our)?)? + .ipc_bytes(serde_json::to_vec(&kt::VfsRequest { + drive: "tester:uqbar".into(), + action: kt::VfsAction::GetEntry("/".into()), + })?) + .send_and_await_response(5)??; + + let wit::Message::Response((response, _)) = response else { panic!("") }; + let kt::VfsResponse::GetEntry { children, .. } = + serde_json::from_slice(&response.ipc)? else { panic!("") }; + let mut children: HashSet<_> = children.into_iter().collect(); + children.remove("/manifest.json"); + children.remove("/metadata.json"); + children.remove("/tester.wasm"); + children.remove("/test_runner.wasm"); + + wit::print_to_terminal(0, &format!("test_runner: running {:?}...", children)); + + for child in &children { + let child_process_id = match wit::spawn( + None, + child, + &wit::OnPanic::None, // TODO: notify us + &wit::Capabilities::All, + false, // not public + ) { + Ok(child_process_id) => child_process_id, + Err(e) => { + wit::print_to_terminal(0, &format!("couldn't spawn {}: {}", child, e)); + panic!("couldn't spawn"); // TODO + } + }; + + let (_, response) = Request::new() + .target(Address { + node: our.node.clone(), + process: child_process_id, + })? + .ipc_bytes(ipc.clone()) + .send_and_await_response(5)??; + + let wit::Message::Response((response, _)) = response else { panic!("") }; + match serde_json::from_slice(&response.ipc)? { + tt::TesterResponse::Pass => {}, + tt::TesterResponse::GetFullMessage(_) => {}, + tt::TesterResponse::Fail { test, file, line, column } => { + fail!(test, file, line, column); + }, + } + } + + wit::print_to_terminal(0, &format!("test_runner: done running {:?}", children)); + + Response::new() + .ipc_bytes(serde_json::to_vec(&tt::TesterResponse::Pass).unwrap()) + .send() + .unwrap(); + }, + tt::TesterRequest::KernelMessage(_) | tt::TesterRequest::GetFullMessage(_) => { unimplemented!() }, + } + Ok(()) + }, + } +} + +struct Component; +impl Guest for Component { + fn init(our: String) { + wit::print_to_terminal(0, "test_runner: begin"); + + let our = Address::from_str(&our).unwrap(); + + wit::create_capability( + &ProcessId::new("vfs", "sys", "uqbar"), + &"\"messaging\"".into(), + ); + + loop { + match handle_message(&our) { + Ok(()) => {}, + Err(e) => { + wit::print_to_terminal(0, format!( + "test_runner: error: {:?}", + e, + ).as_str()); + fail!("test_runner"); + }, + }; + } + } +} diff --git a/modules/tester/test_runner/src/tester_types.rs b/modules/tester/test_runner/src/tester_types.rs new file mode 120000 index 00000000..24792c5a --- /dev/null +++ b/modules/tester/test_runner/src/tester_types.rs @@ -0,0 +1 @@ +../../tester_types.rs \ No newline at end of file diff --git a/modules/tester/tester/Cargo-component.lock b/modules/tester/tester/Cargo-component.lock new file mode 100644 index 00000000..00bc239d --- /dev/null +++ b/modules/tester/tester/Cargo-component.lock @@ -0,0 +1,3 @@ +# This file is automatically generated by cargo-component. +# It is not intended for manual editing. +version = 1 diff --git a/modules/tester/tester/Cargo.lock b/modules/tester/tester/Cargo.lock new file mode 100644 index 00000000..23099615 --- /dev/null +++ b/modules/tester/tester/Cargo.lock @@ -0,0 +1,411 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "anyhow" +version = "1.0.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bitflags" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "hashbrown" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156" + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "id-arena" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005" + +[[package]] +name = "indexmap" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" +dependencies = [ + "equivalent", + "hashbrown", + "serde", +] + +[[package]] +name = "itoa" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" + +[[package]] +name = "leb128" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" + +[[package]] +name = "libc" +version = "0.2.150" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" + +[[package]] +name = "log" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "proc-macro2" +version = "1.0.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "ryu" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" + +[[package]] +name = "semver" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" + +[[package]] +name = "serde" +version = "1.0.188" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.188" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.105" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "693151e1ac27563d6dbcec9dee9fbd5da8539b20fa14ad3752b2e6d363ace360" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "smallvec" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" + +[[package]] +name = "spdx" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b19b32ed6d899ab23174302ff105c1577e45a06b08d4fe0a9dd13ce804bbbf71" +dependencies = [ + "smallvec", +] + +[[package]] +name = "syn" +version = "2.0.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "718fa2415bcb8d8bd775917a1bf12a7931b6dfa890753378538118181e0cb398" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tester" +version = "0.1.0" +dependencies = [ + "anyhow", + "bincode", + "indexmap", + "serde", + "serde_json", + "thiserror", + "uqbar_process_lib", + "wit-bindgen", +] + +[[package]] +name = "thiserror" +version = "1.0.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "unicode-ident" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" + +[[package]] +name = "unicode-segmentation" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" + +[[package]] +name = "unicode-xid" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" + +[[package]] +name = "uqbar_process_lib" +version = "0.2.0" +dependencies = [ + "anyhow", + "bincode", + "rand", + "serde", + "wit-bindgen", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-encoder" +version = "0.36.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "822b645bf4f2446b949776ffca47e2af60b167209ffb70814ef8779d299cd421" +dependencies = [ + "leb128", +] + +[[package]] +name = "wasm-metadata" +version = "0.10.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2167ce53b2faa16a92c6cafd4942cff16c9a4fa0c5a5a0a41131ee4e49fc055f" +dependencies = [ + "anyhow", + "indexmap", + "serde", + "serde_derive", + "serde_json", + "spdx", + "wasm-encoder", + "wasmparser", +] + +[[package]] +name = "wasmparser" +version = "0.116.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a58e28b80dd8340cb07b8242ae654756161f6fc8d0038123d679b7b99964fa50" +dependencies = [ + "indexmap", + "semver", +] + +[[package]] +name = "wit-bindgen" +version = "0.13.1" +source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=5390bab780733f1660d14c254ec985df2816bf1d#5390bab780733f1660d14c254ec985df2816bf1d" +dependencies = [ + "bitflags", + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen-core" +version = "0.13.1" +source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=5390bab780733f1660d14c254ec985df2816bf1d#5390bab780733f1660d14c254ec985df2816bf1d" +dependencies = [ + "anyhow", + "wit-component", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.13.2" +source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=5390bab780733f1660d14c254ec985df2816bf1d#5390bab780733f1660d14c254ec985df2816bf1d" +dependencies = [ + "anyhow", + "heck", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.13.1" +source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=5390bab780733f1660d14c254ec985df2816bf1d#5390bab780733f1660d14c254ec985df2816bf1d" +dependencies = [ + "anyhow", + "proc-macro2", + "quote", + "syn", + "wit-bindgen-core", + "wit-bindgen-rust", + "wit-component", +] + +[[package]] +name = "wit-component" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "480cc1a078b305c1b8510f7c455c76cbd008ee49935f3a6c5fd5e937d8d95b1e" +dependencies = [ + "anyhow", + "bitflags", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43771ee863a16ec4ecf9da0fc65c3bbd4a1235c8e3da5f094b562894843dfa76" +dependencies = [ + "anyhow", + "id-arena", + "indexmap", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", +] diff --git a/modules/tester/tester/Cargo.toml b/modules/tester/tester/Cargo.toml new file mode 100644 index 00000000..0f325448 --- /dev/null +++ b/modules/tester/tester/Cargo.toml @@ -0,0 +1,33 @@ +[package] +name = "tester" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[profile.release] +panic = "abort" +opt-level = "s" +lto = true + +[dependencies] +anyhow = "1.0" +bincode = "1.3.3" +indexmap = "2.1" +serde = {version = "1.0", features = ["derive"] } +serde_json = "1.0" +thiserror = "1.0" +uqbar_process_lib = { path = "../../../../process_lib" } +# uqbar_process_lib = { git = "https://github.com/uqbar-dao/process_lib", rev = "9684d33" } +wit-bindgen = { git = "https://github.com/bytecodealliance/wit-bindgen", rev = "5390bab780733f1660d14c254ec985df2816bf1d" } + +[lib] +crate-type = ["cdylib"] + +[package.metadata.component] +package = "uqbar:process" + +[package.metadata.component.target] +path = "wit" + +[package.metadata.component.dependencies] diff --git a/modules/tester/tester/src/lib.rs b/modules/tester/tester/src/lib.rs new file mode 100644 index 00000000..7c86b5ad --- /dev/null +++ b/modules/tester/tester/src/lib.rs @@ -0,0 +1,130 @@ +use indexmap::map::IndexMap; + +use uqbar_process_lib::{Address, ProcessId, Request, Response}; +use uqbar_process_lib::kernel_types as kt; +use uqbar_process_lib::uqbar::process::standard as wit; + +mod tester_types; +use tester_types as tt; + +wit_bindgen::generate!({ + path: "../../../wit", + world: "process", + exports: { + world: Component, + }, +}); + +type Messages = IndexMap; + +fn make_vfs_address(our: &wit::Address) -> anyhow::Result
{ + Ok(wit::Address { + node: our.node.clone(), + process: ProcessId::from_str("vfs:sys:uqbar")?, + }) +} + +fn handle_message( + our: &Address, + _messages: &mut Messages, + node_names: &mut Vec, +) -> anyhow::Result<()> { + let (source, message) = wit::receive().unwrap(); + + match message { + wit::Message::Response((wit::Response { ipc, .. }, _)) => { + match serde_json::from_slice(&ipc)? { + tt::TesterResponse::Pass | tt::TesterResponse::Fail { .. } => { + if (source.process.package_name != "tester") + | (source.process.publisher_node != "uqbar") { + return Err(tt::TesterError::UnexpectedResponse.into()); + } + Response::new() + .ipc_bytes(ipc) + .send() + .unwrap(); + }, + tt::TesterResponse::GetFullMessage(_) => { unimplemented!() } + } + Ok(()) + }, + wit::Message::Request(wit::Request { ipc, .. }) => { + match serde_json::from_slice(&ipc)? { + tt::TesterRequest::Run(input_node_names) => { + wit::print_to_terminal(0, "tester: got Run"); + + assert!(input_node_names.len() >= 1); + *node_names = input_node_names.clone(); + + if our.node != node_names[0] { + Response::new() + .ipc_bytes(serde_json::to_vec(&tt::TesterResponse::Pass).unwrap()) + .send() + .unwrap(); + } else { + // we are master node + let child = "/test_runner.wasm"; + let child_process_id = match wit::spawn( + None, + child, + &wit::OnPanic::None, // TODO: notify us + &wit::Capabilities::All, + false, // not public + ) { + Ok(child_process_id) => child_process_id, + Err(e) => { + wit::print_to_terminal(0, &format!("couldn't spawn {}: {}", child, e)); + panic!("couldn't spawn"); // TODO + } + }; + Request::new() + .target(Address { + node: our.node.clone(), + process: child_process_id, + })? + .ipc_bytes(ipc) + .expects_response(15) + .send()?; + } + }, + tt::TesterRequest::KernelMessage(_) | tt::TesterRequest::GetFullMessage(_) => { unimplemented!() }, + } + Ok(()) + }, + } +} + +struct Component; +impl Guest for Component { + fn init(our: String) { + wit::print_to_terminal(0, "tester: begin"); + + let our = Address::from_str(&our).unwrap(); + let mut messages: Messages = IndexMap::new(); + let mut node_names: Vec = Vec::new(); + + // orchestrate tests using external scripts + // -> must give drive cap to rpc + let drive_cap = wit::get_capability( + &make_vfs_address(&our).unwrap(), + &serde_json::to_string(&serde_json::json!({ + "kind": "write", + "drive": "tester:uqbar", + })).unwrap() + ).unwrap(); + wit::share_capability(&ProcessId::from_str("http_server:sys:uqbar").unwrap(), &drive_cap); + + loop { + match handle_message(&our, &mut messages, &mut node_names) { + Ok(()) => {}, + Err(e) => { + wit::print_to_terminal(0, format!( + "tester: error: {:?}", + e, + ).as_str()); + fail!("tester"); + }, + }; + } + } +} diff --git a/modules/tester/tester/src/tester_types.rs b/modules/tester/tester/src/tester_types.rs new file mode 120000 index 00000000..24792c5a --- /dev/null +++ b/modules/tester/tester/src/tester_types.rs @@ -0,0 +1 @@ +../../tester_types.rs \ No newline at end of file diff --git a/modules/tester/tester_types.rs b/modules/tester/tester_types.rs new file mode 100644 index 00000000..43455aef --- /dev/null +++ b/modules/tester/tester_types.rs @@ -0,0 +1,77 @@ +use serde::{Serialize, Deserialize}; + +use uqbar_process_lib::Response; +use uqbar_process_lib::kernel_types as kt; +// use uqbar_process_lib::uqbar::process::standard as wit; + +type Rsvp = Option; + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct KernelMessage { + pub id: u64, + pub source: kt::Address, + pub target: kt::Address, + pub rsvp: Rsvp, + pub message: kt::Message, + pub payload: Option, + pub signed_capabilities: Option>, +} + +#[derive(Debug, Serialize, Deserialize)] +pub enum TesterRequest { + Run(Vec), + KernelMessage(KernelMessage), + GetFullMessage(kt::Message), +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct TesterFail { + pub test: String, + pub file: String, + pub line: u32, + pub column: u32, +} + +#[derive(Debug, Serialize, Deserialize)] +pub enum TesterResponse { + Pass, + Fail { test: String, file: String, line: u32, column: u32 }, + GetFullMessage(Option), +} + +#[derive(Debug, Serialize, Deserialize, thiserror::Error)] +pub enum TesterError { + #[error("RejectForeign")] + RejectForeign, + #[error("UnexpectedResponse")] + UnexpectedResponse, + #[error("FAIL {test} {message}")] + Fail { test: String, message: String }, +} + +#[macro_export] +macro_rules! fail { + ($test:expr) => { + Response::new() + .ipc_bytes(serde_json::to_vec(&tt::TesterResponse::Fail { + test: $test.into(), + file: file!().into(), + line: line!(), + column: column!(), + }).unwrap()) + .send() + .unwrap(); + }; + ($test:expr, $file:expr, $line:expr, $column:expr) => { + Response::new() + .ipc_bytes(serde_json::to_vec(&tt::TesterResponse::Fail { + test: $test.into(), + file: $file.into(), + line: $line, + column: $column, + }).unwrap()) + .send() + .unwrap(); + panic!(""); + }; +} diff --git a/src/filesystem/mod.rs b/src/filesystem/mod.rs index dd980294..d32c2643 100644 --- a/src/filesystem/mod.rs +++ b/src/filesystem/mod.rs @@ -175,6 +175,14 @@ async fn bootstrap( let mut vfs_messages = Vec::new(); for (package_name, mut package) in packages { + // special case tester: only load it in if in simulation mode + if package_name == "tester" { + #[cfg(not(feature = "simulation-mode"))] + continue; + #[cfg(feature = "simulation-mode")] + {} + } + println!("fs: handling package {package_name}...\r"); // get and read metadata.json let Ok(mut package_metadata_zip) = package.by_name("metadata.json") else { @@ -390,6 +398,7 @@ async fn bootstrap( .write(kernel_process_id, &serialized_process_map) .await; } + Ok(vfs_messages) } diff --git a/src/kernel/mod.rs b/src/kernel/mod.rs index 80b0e7a4..67690734 100644 --- a/src/kernel/mod.rs +++ b/src/kernel/mod.rs @@ -753,6 +753,9 @@ pub async fn kernel( .await .expect("fatal: kernel event loop died"); + #[cfg(feature = "simulation-mode")] + let tester_process_id = t::ProcessId::new(Some("tester"), "tester", "uqbar"); + // main event loop loop { tokio::select! { @@ -924,6 +927,7 @@ pub async fn kernel( content: format!("event loop: got message: {}", kernel_message) } ).await; + if our.name != kernel_message.target.node { send_to_net.send(kernel_message).await.expect("fatal: net module died"); } else if kernel_message.target.process.process() == "kernel" { diff --git a/src/main.rs b/src/main.rs index 5a6e08c8..774e6ca2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,7 +2,10 @@ use crate::types::*; use anyhow::Result; -use clap::{arg, Command}; +use clap::{arg, value_parser, Command}; +use ring::rand::SystemRandom; +use ring::signature; +use ring::signature::KeyPair; use std::env; use std::sync::Arc; use tokio::sync::{mpsc, oneshot}; @@ -44,29 +47,112 @@ const VERSION: &str = env!("CARGO_PKG_VERSION"); /// such that only their routers can ever see their physical networking details. const REVEAL_IP: bool = true; +async fn serve_register_fe( + home_directory_path: &str, + our_ip: String, + http_server_port: u16, + rpc_url: String, +) -> (Identity, Keyfile) { + // check if we have keys saved on disk, encrypted + // if so, prompt user for "password" to decrypt with + + // once password is received, use to decrypt local keys file, + // and pass the keys into boot process as is done in registration. + + // NOTE: when we log in, we MUST check the PKI to make sure our + // information matches what we think it should be. this includes + // username, networking key, and routing info. + // if any do not match, we should prompt user to create a "transaction" + // that updates their PKI info on-chain. + let (kill_tx, kill_rx) = oneshot::channel::(); + + let disk_keyfile = match fs::read(format!("{}/.keys", home_directory_path)).await { + Ok(keyfile) => keyfile, + Err(_) => Vec::new(), + }; + + let (tx, mut rx) = mpsc::channel::<(Identity, Keyfile, Vec)>(1); + let (our, decoded_keyfile, encoded_keyfile) = tokio::select! { + _ = register::register(tx, kill_rx, our_ip, http_server_port, rpc_url, disk_keyfile) => { + panic!("registration failed") + } + Some((our, decoded_keyfile, encoded_keyfile)) = rx.recv() => { + (our, decoded_keyfile, encoded_keyfile) + } + }; + + println!( + "saving encrypted networking keys to {}/.keys", + home_directory_path + ); + + fs::write(format!("{}/.keys", home_directory_path), encoded_keyfile) + .await + .unwrap(); + + println!("registration complete!"); + + let _ = kill_tx.send(true); + + (our, decoded_keyfile) +} + #[tokio::main] async fn main() { - let matches = Command::new("Uqbar") + let app = Command::new("Uqbar") .version(VERSION) .author("Uqbar DAO: https://github.com/uqbar-dao") .about("A General Purpose Sovereign Cloud Computing Platform") .arg(arg!([home] "Path to home directory").required(true)) - .arg(arg!(--rpc "Ethereum RPC endpoint (must be wss://)").required(true)) - .arg(arg!(--llm "LLM endpoint")) - .get_matches(); - let home_directory_path = matches.get_one::("home").unwrap(); - let rpc_url = matches.get_one::("rpc").unwrap(); - let llm_url = matches.get_one::("llm"); + .arg( + arg!(--port "First port to try binding") + .default_value("8080") + .value_parser(value_parser!(u16)), + ); + + #[cfg(not(feature = "simulation-mode"))] + let app = app.arg(arg!(--rpc "Ethereum RPC endpoint (must be wss://)").required(true)); + + #[cfg(feature = "simulation-mode")] + let app = app + .arg(arg!(--rpc "Ethereum RPC endpoint (must be wss://)")) + .arg(arg!(--password "Networking password")) + .arg(arg!(--"fake-node-name" "Name of fake node to boot")) + .arg( + arg!(--"network-router-port" "Network router port") + .default_value("9001") + .value_parser(value_parser!(u16)), + ); + + #[cfg(feature = "llm")] + let app = app.arg(arg!(--llm "LLM endpoint")); + + let matches = app.get_matches(); + + let home_directory_path = matches.get_one::("home").unwrap(); + let port = matches.get_one::("port").unwrap().clone(); + + #[cfg(not(feature = "simulation-mode"))] + let rpc_url = matches.get_one::("rpc").unwrap(); + + #[cfg(feature = "simulation-mode")] + let (rpc_url, password, network_router_port, fake_node_name) = ( + matches.get_one::("rpc"), + matches.get_one::("password"), + matches + .get_one::("network-router-port") + .unwrap() + .clone(), + matches.get_one::("fake-node-name"), + ); + + #[cfg(feature = "llm")] + let llm_url = matches.get_one::("llm").unwrap(); - // create home directory if it does not already exist if let Err(e) = fs::create_dir_all(home_directory_path).await { panic!("failed to create home directory: {:?}", e); } - - #[cfg(not(feature = "llm"))] - if let Some(llm_url) = llm_url { - panic!("You passed in --llm {:?} but you do not have the llm feature enabled. Please re-run with `--features llm`", llm_url); - } + println!("home at {}\r", home_directory_path); // kernel receives system messages via this channel, all other modules send messages let (kernel_message_sender, kernel_message_receiver): (MessageSender, MessageReceiver) = @@ -185,39 +271,111 @@ async fn main() { } }; - // check if we have keys saved on disk, encrypted - // if so, prompt user for "password" to decrypt with + let http_server_port = http::utils::find_open_port(port).await.unwrap(); + println!("runtime bound port {}\r", http_server_port); + println!( + "login or register at http://localhost:{}\r", + http_server_port + ); + #[cfg(not(feature = "simulation-mode"))] + let (our, decoded_keyfile) = serve_register_fe( + &home_directory_path, + our_ip.to_string(), + http_server_port.clone(), + rpc_url.clone(), + ) + .await; + #[cfg(feature = "simulation-mode")] + let (our, decoded_keyfile) = match fake_node_name { + None => { + match password { + None => match rpc_url { + None => panic!(""), + Some(rpc_url) => { + serve_register_fe( + &home_directory_path, + our_ip.to_string(), + http_server_port.clone(), + rpc_url.clone(), + ) + .await + } + }, + Some(password) => { + match fs::read(format!("{}/.keys", home_directory_path)).await { + Err(e) => panic!("could not read keyfile: {}", e), + Ok(keyfile) => { + match keygen::decode_keyfile(keyfile, &password) { + Err(e) => panic!("could not decode keyfile: {}", e), + Ok(decoded_keyfile) => { + let our = Identity { + name: decoded_keyfile.username.clone(), + networking_key: format!( + "0x{}", + hex::encode( + decoded_keyfile + .networking_keypair + .public_key() + .as_ref() + ) + ), + ws_routing: None, // TODO + allowed_routers: decoded_keyfile.routers.clone(), + }; + (our, decoded_keyfile) + } + } + } + } + } + } + } + Some(name) => { + let password = match password { + None => "123".to_string(), + Some(password) => password.to_string(), + }; + let (pubkey, networking_keypair) = keygen::generate_networking_key(); - // once password is received, use to decrypt local keys file, - // and pass the keys into boot process as is done in registration. + let seed = SystemRandom::new(); + let mut jwt_secret = [0u8, 32]; + ring::rand::SecureRandom::fill(&seed, &mut jwt_secret).unwrap(); - // NOTE: when we log in, we MUST check the PKI to make sure our - // information matches what we think it should be. this includes - // username, networking key, and routing info. - // if any do not match, we should prompt user to create a "transaction" - // that updates their PKI info on-chain. - let http_server_port = http::utils::find_open_port(8080).await.unwrap(); - println!("login or register at http://localhost:{}", http_server_port); - let (kill_tx, kill_rx) = oneshot::channel::(); + let our = Identity { + name: name.clone(), + networking_key: pubkey, + ws_routing: None, + allowed_routers: vec![], + }; - let disk_keyfile = match fs::read(format!("{}/.keys", home_directory_path)).await { - Ok(keyfile) => keyfile, - Err(_) => Vec::new(), + let decoded_keyfile = Keyfile { + username: name.clone(), + routers: vec![], + networking_keypair: signature::Ed25519KeyPair::from_pkcs8( + networking_keypair.as_ref(), + ) + .unwrap(), + jwt_secret_bytes: jwt_secret.to_vec(), + file_key: keygen::generate_file_key(), + }; + + let encoded_keyfile = keygen::encode_keyfile( + password, + name.clone(), + decoded_keyfile.routers.clone(), + networking_keypair, + decoded_keyfile.jwt_secret_bytes.clone(), + decoded_keyfile.file_key.clone(), + ); + + fs::write(format!("{}/.keys", home_directory_path), encoded_keyfile) + .await + .unwrap(); + + (our, decoded_keyfile) + } }; - let (tx, mut rx) = mpsc::channel::<(Identity, Keyfile, Vec)>(1); - let (our, decoded_keyfile, encoded_keyfile) = tokio::select! { - _ = register::register(tx, kill_rx, our_ip.to_string(), http_server_port, rpc_url.clone(), disk_keyfile) - => panic!("registration failed"), - (our, decoded_keyfile, encoded_keyfile) = async { - rx.recv().await.expect("registration failed") - } => (our, decoded_keyfile, encoded_keyfile), - }; - - fs::write(format!("{}/.keys", home_directory_path), encoded_keyfile) - .await - .unwrap(); - // the boolean flag determines whether the runtime module is *public* or not, // where public means that any process can always message it. #[allow(unused_mut)] @@ -255,16 +413,11 @@ async fn main() { ]; #[cfg(feature = "llm")] - { - if llm_url.is_none() { - panic!("You did not pass in --llm but you have the llm feature enabled. Please re-run with `--llm `"); - } - runtime_extensions.push(( - ProcessId::new(Some("llm"), "sys", "uqbar"), // TODO llm:extensions:uqbar ? - llm_sender, - true, - )); - } + runtime_extensions.push(( + ProcessId::new(Some("llm"), "sys", "uqbar"), // TODO llm:extensions:uqbar ? + llm_sender, + true, + )); let (kernel_process_map, manifest, vfs_messages) = filesystem::load_fs( our.name.clone(), @@ -276,8 +429,6 @@ async fn main() { .await .expect("fs load failed!"); - let _ = kill_tx.send(true); - /* * the kernel module will handle our userspace processes and receives * all "messages", the basic message format for uqbar. @@ -301,6 +452,7 @@ async fn main() { net_message_sender.clone(), runtime_extensions, )); + #[cfg(not(feature = "simulation-mode"))] tasks.spawn(net::networking( our.clone(), our_ip.to_string(), @@ -312,6 +464,13 @@ async fn main() { net_message_receiver, REVEAL_IP, )); + #[cfg(feature = "simulation-mode")] + tasks.spawn(net::mock_client( + network_router_port, + our.name.clone(), + kernel_message_sender.clone(), + net_message_receiver, + )); tasks.spawn(filesystem::fs_sender( our.name.clone(), manifest, @@ -341,6 +500,7 @@ async fn main() { timer_service_receiver, print_sender.clone(), )); + #[cfg(not(feature = "simulation-mode"))] tasks.spawn(eth_rpc::eth_rpc( our.name.clone(), rpc_url.clone(), @@ -362,7 +522,7 @@ async fn main() { our.name.clone(), kernel_message_sender.clone(), llm_receiver, - llm_url.unwrap().to_string(), + llm_url.to_string(), print_sender.clone(), )); } diff --git a/src/net/mock.rs b/src/net/mock.rs new file mode 100644 index 00000000..6fd747c1 --- /dev/null +++ b/src/net/mock.rs @@ -0,0 +1,50 @@ +use futures::{SinkExt, StreamExt}; +use tokio::net::TcpStream; +use tokio::sync::mpsc; +use tokio_tungstenite::{ + connect_async, + tungstenite::protocol::Message::{Binary, Text}, + WebSocketStream, +}; +use url::Url; + +use crate::types; + +type Sender = mpsc::Sender; +type Receiver = mpsc::Receiver; + +pub async fn mock_client( + port: u16, + node_identity: types::NodeId, + send_to_loop: Sender, + mut recv_from_loop: Receiver, +) -> anyhow::Result<()> { + let url = format!("ws://127.0.0.1:{}", port); + + let (ws_stream, _) = connect_async(url).await?; + let (mut send_to_ws, mut recv_from_ws) = ws_stream.split(); + + // Send node identity + send_to_ws.send(Text(node_identity.clone())).await?; + + loop { + tokio::select! { + Some(kernel_message) = recv_from_loop.recv() => { + if kernel_message.target.node != node_identity { + // Serialize and send the message through WebSocket + // println!("{}:mock: outgoing {}\r", node_identity ,kernel_message); + let message = Binary(rmp_serde::to_vec(&kernel_message)?); + send_to_ws.send(message).await?; + } + }, + Some(Ok(message)) = recv_from_ws.next() => { + // Deserialize and forward the message to the loop + // println!("{}:mock: incoming {}\r", node_identity, message); + if let Binary(ref bin) = message { + let kernel_message: types::KernelMessage = rmp_serde::from_slice(bin)?; + send_to_loop.send(kernel_message).await?; + } + }, + } + } +} diff --git a/src/net/mod.rs b/src/net/mod.rs index 0db53b80..9b39b955 100644 --- a/src/net/mod.rs +++ b/src/net/mod.rs @@ -16,6 +16,12 @@ use tokio_tungstenite::{ mod types; mod utils; +// Re-export for testing. +#[cfg(feature = "simulation-mode")] +mod mock; +#[cfg(feature = "simulation-mode")] +pub use mock::mock_client; + // only used in connection initialization, otherwise, nacks and Responses are only used for "timeouts" const TIMEOUT: std::time::Duration = std::time::Duration::from_secs(5); diff --git a/src/types.rs b/src/types.rs index aed13560..0876e575 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1,4 +1,5 @@ use crate::kernel::process::wit; +use clap::Parser; use ring::signature; use serde::{Deserialize, Serialize}; use std::collections::{HashMap, HashSet};