diff --git a/Cargo.lock b/Cargo.lock index 53e97328a..468248a54 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1475,16 +1475,16 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.39" +version = "0.4.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825" +checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" dependencies = [ "android-tzdata", "iana-time-zone", "js-sys", "num-traits", "wasm-bindgen", - "windows-targets 0.52.6", + "windows-link", ] [[package]] @@ -3161,7 +3161,7 @@ dependencies = [ [[package]] name = "hyperdrive" -version = "1.2.1" +version = "1.2.2" dependencies = [ "aes-gcm", "alloy", @@ -3217,22 +3217,42 @@ dependencies = [ [[package]] name = "hyperdrive_lib" -version = "1.2.1" +version = "1.3.0" dependencies = [ "lib", ] +[[package]] +name = "hypermap-cacher" +version = "0.1.0" +dependencies = [ + "alloy", + "alloy-primitives", + "alloy-sol-types", + "anyhow", + "chrono", + "hex", + "hyperware_process_lib", + "process_macros", + "rand", + "rmp-serde", + "serde", + "serde_json", + "wit-bindgen", +] + [[package]] name = "hyperware_process_lib" -version = "1.0.5" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd85e48b5f017132d52df416578fe6816b51d166b70ffd8718dbe29ae979d98b" +checksum = "414dd471dfac43943b314200b4943f38c4b08337103840e2192cfb5dc9b1bea5" dependencies = [ "alloy", "alloy-primitives", "alloy-sol-macro", "alloy-sol-types", "anyhow", + "base64 0.22.1", "bincode", "color-eyre", "http 1.2.0", @@ -3755,7 +3775,7 @@ checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" [[package]] name = "lib" -version = "1.2.1" +version = "1.2.2" dependencies = [ "alloy", "anyhow", @@ -5018,6 +5038,17 @@ dependencies = [ "wit-bindgen", ] +[[package]] +name = "reset-cache" +version = "0.1.0" +dependencies = [ + "hyperware_process_lib", + "process_macros", + "serde", + "serde_json", + "wit-bindgen", +] + [[package]] name = "reset-store" version = "0.1.0" @@ -5486,6 +5517,17 @@ dependencies = [ "serde", ] +[[package]] +name = "set-nodes" +version = "0.1.0" +dependencies = [ + "hyperware_process_lib", + "process_macros", + "serde", + "serde_json", + "wit-bindgen", +] + [[package]] name = "settings" version = "0.1.0" @@ -5722,6 +5764,17 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +[[package]] +name = "start-providing" +version = "0.1.0" +dependencies = [ + "hyperware_process_lib", + "process_macros", + "serde", + "serde_json", + "wit-bindgen", +] + [[package]] name = "state" version = "0.1.0" @@ -5756,6 +5809,17 @@ dependencies = [ "warp", ] +[[package]] +name = "stop-providing" +version = "0.1.0" +dependencies = [ + "hyperware_process_lib", + "process_macros", + "serde", + "serde_json", + "wit-bindgen", +] + [[package]] name = "strsim" version = "0.9.3" @@ -7319,6 +7383,12 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-link" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" + [[package]] name = "windows-registry" version = "0.2.0" diff --git a/Cargo.toml b/Cargo.toml index 24c920479..da3c9482b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "hyperdrive_lib" authors = ["Sybil Technologies AG"] -version = "1.2.1" +version = "1.3.0" edition = "2021" description = "A general-purpose sovereign cloud computing platform" homepage = "https://hyperware.ai" @@ -21,6 +21,8 @@ members = [ "hyperdrive/packages/homepage/homepage", "hyperdrive/packages/hns-indexer/hns-indexer", "hyperdrive/packages/hns-indexer/get-block", "hyperdrive/packages/settings/settings", "hyperdrive/packages/hns-indexer/reset", "hyperdrive/packages/hns-indexer/node-info", "hyperdrive/packages/hns-indexer/state", + "hyperdrive/packages/hypermap-cacher/hypermap-cacher", "hyperdrive/packages/hypermap-cacher/reset-cache", "hyperdrive/packages/hypermap-cacher/set-nodes", + "hyperdrive/packages/hypermap-cacher/start-providing", "hyperdrive/packages/hypermap-cacher/stop-providing", "hyperdrive/packages/sign/sign", "hyperdrive/packages/terminal/terminal", "hyperdrive/packages/terminal/alias", "hyperdrive/packages/terminal/cat", "hyperdrive/packages/terminal/echo", diff --git a/README.md b/README.md index 6b3e879d0..6c0f47ca3 100644 --- a/README.md +++ b/README.md @@ -13,8 +13,8 @@ This repo contains the core runtime and processes. Most developers need not build the runtime. Instead, check out the [Hyperware Book](https://book.hyperware.ai/), and in particular the ["My First App" tutorial](https://book.hyperware.ai/my_first_app/chapter_1.html). -If you want to get on the network, you can download a binary, rather than building it yourself, from [the releases page](https://github.com/hyperware-ai/hyperware/tags). -Then follow the instructions to [install it](https://book.hyperware.ai/install.html) and [join the network](https://book.hyperware.ai/login.html). +If you want to get on the network, you can download a binary, rather than building it yourself, from [the releases page](https://github.com/hyperware-ai/hyperdrive/tags). +Then follow the instructions to [install it](https://book.hyperware.ai/getting_started/install.html) and [join the network](https://book.hyperware.ai/getting_started/login.html). If you have questions, join the [Hyperware discord](https://discord.com/invite/KaPXX7SFTD) and drop us a line in `#dev-support`. @@ -72,7 +72,7 @@ The `--` here separates cargo arguments from binary arguments. cargo run -p hyperdrive -- home ``` -On boot you will be prompted to navigate to `localhost:8080` or whatever HTTP port your node bound to: it will try 8080 and go up from there, or use the port passed with the `--port` boot flag. Make sure your browser wallet matches the network that the node is being booted on. Follow the registration UI -- if you want to register a new ID you will either need Optimism ETH or an invite code. +On boot you will be prompted to navigate to `localhost:8080` or whatever HTTP port your node bound to: it will try 8080 and go up from there, or use the port passed with the `--port` boot flag. Make sure your browser wallet matches the network that the node is being booted on. Follow the registration UI -- if you want to register a new ID you will either need Base ETH or an invite code. #### Boot Flags @@ -169,7 +169,7 @@ Use this message format to add a provider -- this will make your node's performa m our@eth:distro:sys '{"AddProvider": {"chain_id": , "trusted": true, "provider": {"RpcUrl": ""}}}' ``` -You can also do the same thing by using the `--rpc` boot flag with an Optimism WebSockets RPC URL, or going to the Settings app once booted into a node. +You can also do the same thing by using the `--rpc` boot flag with an Base WebSockets RPC URL, or going to the Settings app once booted into a node. ## Distro and Runtime processes @@ -202,7 +202,9 @@ The distro userspace packages are: - `contacts:sys` - `homepage:sys` - `hns-indexer:sys` +- `hypermap-cacher:sys` - `settings:sys` +- `sign:sys` - `terminal:sys` - `tester:sys` (used with `kit` for running test suites, only installed in `simulation-mode`) @@ -210,6 +212,9 @@ The `sys` publisher is not a real node ID, but it's also not a special case valu Packages, whether runtime or userspace, installed from disk when a node bootstraps do not have their package ID or publisher node ID validated. Packages installed (not injected locally, as is done during development) after a node has booted will have their publisher field validated. +Distro userspace packages may have their dependencies satisfied by specifying them as local dependencies in `hyperdrive/packages-local-dependencies.json`. +For example, `hypermap-cacher:sys` depends on `sign:sys`, and so has an entry whose key is `hypermap-cacher` (the dir name) and whose value is an array with one item: `sign` (the dir name). + ## Terminal syntax - CTRL+C or CTRL+D to gracefully shutdown node diff --git a/hyperdrive/Cargo.toml b/hyperdrive/Cargo.toml index 94a6877df..2dd18c13a 100644 --- a/hyperdrive/Cargo.toml +++ b/hyperdrive/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "hyperdrive" authors = ["Sybil Technologies AG"] -version = "1.2.1" +version = "1.2.2" edition = "2021" description = "A general-purpose sovereign cloud computing platform" homepage = "https://hyperware.ai" diff --git a/hyperdrive/packages-local-dependencies.json b/hyperdrive/packages-local-dependencies.json new file mode 100644 index 000000000..0bdd104b6 --- /dev/null +++ b/hyperdrive/packages-local-dependencies.json @@ -0,0 +1,5 @@ +{ + "hypermap-cacher": [ + "sign" + ] +} diff --git a/hyperdrive/packages/app-store/Cargo.lock b/hyperdrive/packages/app-store/Cargo.lock index aa95a6080..3e36b475e 100644 --- a/hyperdrive/packages/app-store/Cargo.lock +++ b/hyperdrive/packages/app-store/Cargo.lock @@ -1639,15 +1639,16 @@ dependencies = [ [[package]] name = "hyperware_process_lib" -version = "1.0.5" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd85e48b5f017132d52df416578fe6816b51d166b70ffd8718dbe29ae979d98b" +checksum = "414dd471dfac43943b314200b4943f38c4b08337103840e2192cfb5dc9b1bea5" dependencies = [ "alloy", "alloy-primitives", "alloy-sol-macro", "alloy-sol-types", "anyhow", + "base64", "bincode", "http", "mime_guess", diff --git a/hyperdrive/packages/app-store/app-store/Cargo.toml b/hyperdrive/packages/app-store/app-store/Cargo.toml index 71603d99c..771d6a0f5 100644 --- a/hyperdrive/packages/app-store/app-store/Cargo.toml +++ b/hyperdrive/packages/app-store/app-store/Cargo.toml @@ -11,7 +11,7 @@ alloy-primitives = "0.8.15" alloy-sol-types = "0.8.15" anyhow = "1.0" bincode = "1.3.3" -hyperware_process_lib = "1.0.5" +hyperware_process_lib = "1.2.0" process_macros = "0.1" rand = "0.8" serde = { version = "1.0", features = ["derive"] } diff --git a/hyperdrive/packages/app-store/app-store/src/http_api.rs b/hyperdrive/packages/app-store/app-store/src/http_api.rs index 73553e329..5e1f8bdda 100644 --- a/hyperdrive/packages/app-store/app-store/src/http_api.rs +++ b/hyperdrive/packages/app-store/app-store/src/http_api.rs @@ -830,29 +830,29 @@ fn serve_paths( { match kind { SendErrorKind::Timeout => { - let check_reponse = MirrorCheck { + let check_response = MirrorCheck { node: node.to_string(), is_online: false, error: Some(format!("node {} timed out", node).to_string()), }; - return Ok((StatusCode::OK, None, serde_json::to_vec(&check_reponse)?)); + return Ok((StatusCode::OK, None, serde_json::to_vec(&check_response)?)); } SendErrorKind::Offline => { - let check_reponse = MirrorCheck { + let check_response = MirrorCheck { node: node.to_string(), is_online: false, error: Some(format!("node {} is offline", node).to_string()), }; - return Ok((StatusCode::OK, None, serde_json::to_vec(&check_reponse)?)); + return Ok((StatusCode::OK, None, serde_json::to_vec(&check_response)?)); } } } else { - let check_reponse = MirrorCheck { + let check_response = MirrorCheck { node: node.to_string(), is_online: true, error: None, }; - return Ok((StatusCode::OK, None, serde_json::to_vec(&check_reponse)?)); + return Ok((StatusCode::OK, None, serde_json::to_vec(&check_response)?)); } } _ => Ok(( diff --git a/hyperdrive/packages/app-store/chain/Cargo.toml b/hyperdrive/packages/app-store/chain/Cargo.toml index b18425a93..ba12ab3e5 100644 --- a/hyperdrive/packages/app-store/chain/Cargo.toml +++ b/hyperdrive/packages/app-store/chain/Cargo.toml @@ -11,7 +11,7 @@ alloy-primitives = "0.8.15" alloy-sol-types = "0.8.15" anyhow = "1.0" bincode = "1.3.3" -hyperware_process_lib = "1.0.5" +hyperware_process_lib = "1.2.0" process_macros = "0.1" rand = "0.8" serde = { version = "1.0", features = ["derive"] } diff --git a/hyperdrive/packages/app-store/chain/src/lib.rs b/hyperdrive/packages/app-store/chain/src/lib.rs index e4fc476e2..23999e579 100644 --- a/hyperdrive/packages/app-store/chain/src/lib.rs +++ b/hyperdrive/packages/app-store/chain/src/lib.rs @@ -413,7 +413,9 @@ fn init(our: Address) { eth_provider, eth::Address::from_str(HYPERMAP_ADDRESS).unwrap(), ); - let last_saved_block = db.get_last_saved_block().unwrap_or(0); + let last_saved_block = db + .get_last_saved_block() + .unwrap_or(hypermap::HYPERMAP_FIRST_BLOCK); let mut state = State { hypermap: hypermap_helper, @@ -619,8 +621,10 @@ fn handle_eth_log( state.db.delete_published(&package_id)?; state.db.delete_listing(&package_id)?; if !startup { - state.last_saved_block = block_number - 1; - state.db.set_last_saved_block(block_number - 1)?; + if block_number - 1 > state.last_saved_block { + state.last_saved_block = block_number - 1; + state.db.set_last_saved_block(block_number - 1)?; + } } return Ok(()); } @@ -834,24 +838,55 @@ pub fn fetch_and_subscribe_logs(our: &Address, state: &mut State, last_saved_blo .hypermap .provider .subscribe_loop(SUBSCRIPTION_NUMBER, filter.clone(), 1, 0); + + let mut maybe_block = None; + match state.hypermap.bootstrap( + Some(last_saved_block), + vec![filter.clone()], + Some((5, None)), + None, + ) { + Err(e) => println!("bootstrap from cache failed: {e:?}"), + Ok((block, mut logs)) => { + maybe_block = Some(block); + assert_eq!(logs.len(), 1); + if let Some(logs) = logs.pop() { + for log in logs { + if let Err(e) = handle_eth_log(our, state, log, true) { + print_to_terminal(1, &format!("error ingesting log: {e}")); + }; + } + } + } + } + + // update metadata for all cached elements: + // need to update here so we can update block number or else `fetch_logs()` + // will grab blocks we just got from cache! + update_all_metadata(state, last_saved_block); + if let Some(block) = maybe_block { + if block > state.last_saved_block { + // save updated last_saved_block + state.last_saved_block = block; + if let Err(e) = state.db.set_last_saved_block(block) { + print_to_terminal(0, &format!("error saving last block after startup: {e}")); + } + } + } + + let block_from_cache = state.last_saved_block; // println!("fetching old logs from block {last_saved_block}"); for log in fetch_logs( &state.hypermap.provider, - &filter.from_block(last_saved_block), + &filter.from_block(state.last_saved_block), ) { if let Err(e) = handle_eth_log(our, state, log, true) { print_to_terminal(1, &format!("error ingesting log: {e}")); }; } - update_all_metadata(state, last_saved_block); - // save updated last_saved_block - if let Ok(block_number) = state.hypermap.provider.get_block_number() { - state.last_saved_block = block_number; - if let Err(e) = state.db.set_last_saved_block(block_number) { - print_to_terminal(0, &format!("error saving last block after startup: {e}")); - } - } + // update metadata for any noncached elements + update_all_metadata(state, block_from_cache); } /// fetch logs from the chain with a given filter diff --git a/hyperdrive/packages/app-store/download/Cargo.toml b/hyperdrive/packages/app-store/download/Cargo.toml index 31799b733..54d2fcbc5 100644 --- a/hyperdrive/packages/app-store/download/Cargo.toml +++ b/hyperdrive/packages/app-store/download/Cargo.toml @@ -8,7 +8,7 @@ simulation-mode = [] [dependencies] anyhow = "1.0" -hyperware_process_lib = "1.0.5" +hyperware_process_lib = "1.2.0" process_macros = "0.1" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" diff --git a/hyperdrive/packages/app-store/downloads/Cargo.toml b/hyperdrive/packages/app-store/downloads/Cargo.toml index f2d49d18a..e379426ec 100644 --- a/hyperdrive/packages/app-store/downloads/Cargo.toml +++ b/hyperdrive/packages/app-store/downloads/Cargo.toml @@ -8,7 +8,7 @@ simulation-mode = [] [dependencies] anyhow = "1.0" -hyperware_process_lib = "1.0.5" +hyperware_process_lib = "1.2.0" process_macros = "0.1" rand = "0.8" serde = { version = "1.0", features = ["derive"] } diff --git a/hyperdrive/packages/app-store/ft-worker/Cargo.toml b/hyperdrive/packages/app-store/ft-worker/Cargo.toml index aa0a18d4f..23244ecb5 100644 --- a/hyperdrive/packages/app-store/ft-worker/Cargo.toml +++ b/hyperdrive/packages/app-store/ft-worker/Cargo.toml @@ -9,7 +9,7 @@ simulation-mode = [] [dependencies] anyhow = "1.0" bincode = "1.3.3" -hyperware_process_lib = "1.0.5" +hyperware_process_lib = "1.2.0" process_macros = "0.1" rand = "0.8" serde = { version = "1.0", features = ["derive"] } diff --git a/hyperdrive/packages/app-store/install/Cargo.toml b/hyperdrive/packages/app-store/install/Cargo.toml index 67918b3d5..2e3d699bc 100644 --- a/hyperdrive/packages/app-store/install/Cargo.toml +++ b/hyperdrive/packages/app-store/install/Cargo.toml @@ -8,7 +8,7 @@ simulation-mode = [] [dependencies] anyhow = "1.0" -hyperware_process_lib = "1.0.5" +hyperware_process_lib = "1.2.0" process_macros = "0.1" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" diff --git a/hyperdrive/packages/app-store/pkg/manifest.json b/hyperdrive/packages/app-store/pkg/manifest.json index 093aa2362..a2577f509 100644 --- a/hyperdrive/packages/app-store/pkg/manifest.json +++ b/hyperdrive/packages/app-store/pkg/manifest.json @@ -32,9 +32,11 @@ "request_capabilities": [ "downloads:app-store:sys", "eth:distro:sys", - "http-client:distro:sys", "hns-indexer:hns-indexer:sys", + "http-client:distro:sys", + "hypermap-cacher:hypermap-cacher:sys", "main:app-store:sys", + "sign:sign:sys", "sqlite:distro:sys", "terminal:terminal:sys", { @@ -46,8 +48,10 @@ ], "grant_capabilities": [ "eth:distro:sys", - "http-client:distro:sys", "hns-indexer:hns-indexer:sys", + "http-client:distro:sys", + "hypermap-cacher:hypermap-cacher:sys", + "sign:sign:sys", "sqlite:distro:sys", "terminal:terminal:sys", "timer:distro:sys" @@ -97,4 +101,4 @@ ], "public": false } -] \ No newline at end of file +] diff --git a/hyperdrive/packages/app-store/reset-store/Cargo.toml b/hyperdrive/packages/app-store/reset-store/Cargo.toml index dd19341d2..a55129813 100644 --- a/hyperdrive/packages/app-store/reset-store/Cargo.toml +++ b/hyperdrive/packages/app-store/reset-store/Cargo.toml @@ -8,7 +8,7 @@ simulation-mode = [] [dependencies] anyhow = "1.0" -hyperware_process_lib = "1.0.5" +hyperware_process_lib = "1.2.0" process_macros = "0.1" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" diff --git a/hyperdrive/packages/app-store/uninstall/Cargo.toml b/hyperdrive/packages/app-store/uninstall/Cargo.toml index f1a5f87b9..7b6cb9084 100644 --- a/hyperdrive/packages/app-store/uninstall/Cargo.toml +++ b/hyperdrive/packages/app-store/uninstall/Cargo.toml @@ -8,7 +8,7 @@ simulation-mode = [] [dependencies] anyhow = "1.0" -hyperware_process_lib = "1.0.5" +hyperware_process_lib = "1.2.0" process_macros = "0.1" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" diff --git a/hyperdrive/packages/contacts/Cargo.lock b/hyperdrive/packages/contacts/Cargo.lock index f75ae2c3a..51003cc54 100644 --- a/hyperdrive/packages/contacts/Cargo.lock +++ b/hyperdrive/packages/contacts/Cargo.lock @@ -1535,15 +1535,16 @@ dependencies = [ [[package]] name = "hyperware_process_lib" -version = "1.0.5" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd85e48b5f017132d52df416578fe6816b51d166b70ffd8718dbe29ae979d98b" +checksum = "414dd471dfac43943b314200b4943f38c4b08337103840e2192cfb5dc9b1bea5" dependencies = [ "alloy", "alloy-primitives", "alloy-sol-macro", "alloy-sol-types", "anyhow", + "base64", "bincode", "http", "mime_guess", diff --git a/hyperdrive/packages/contacts/contacts/Cargo.toml b/hyperdrive/packages/contacts/contacts/Cargo.toml index bd5a41711..dc2ebafff 100644 --- a/hyperdrive/packages/contacts/contacts/Cargo.toml +++ b/hyperdrive/packages/contacts/contacts/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" simulation-mode = [] [dependencies] -hyperware_process_lib = "1.0.5" +hyperware_process_lib = "1.2.0" process_macros = "0.1" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" diff --git a/hyperdrive/packages/contacts/get-names/Cargo.toml b/hyperdrive/packages/contacts/get-names/Cargo.toml index 7db76f936..a429346ea 100644 --- a/hyperdrive/packages/contacts/get-names/Cargo.toml +++ b/hyperdrive/packages/contacts/get-names/Cargo.toml @@ -6,7 +6,7 @@ publish = false [dependencies] anyhow = "1.0" -hyperware_process_lib = "1.0.5" +hyperware_process_lib = "1.2.0" process_macros = "0.1" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" diff --git a/hyperdrive/packages/hns-indexer/Cargo.lock b/hyperdrive/packages/hns-indexer/Cargo.lock index eaeb1374e..675dd0a07 100644 --- a/hyperdrive/packages/hns-indexer/Cargo.lock +++ b/hyperdrive/packages/hns-indexer/Cargo.lock @@ -894,6 +894,33 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "color-eyre" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e1761c0e16f8883bbbb8ce5990867f4f06bf11a0253da6495a04ce4b6ef0ec" +dependencies = [ + "backtrace", + "color-spantrace", + "eyre", + "indenter", + "once_cell", + "owo-colors", + "tracing-error", +] + +[[package]] +name = "color-spantrace" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ddd8d5bfda1e11a501d0a7303f3bfed9aa632ebdb859be40d0fd70478ed70d5" +dependencies = [ + "once_cell", + "owo-colors", + "tracing-core", + "tracing-error", +] + [[package]] name = "const-hex" version = "1.14.0" @@ -1121,6 +1148,16 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "eyre" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd915d99f24784cdc19fd37ef22b97e3ff0ae756c7e492e9fbfe897d61e2aec" +dependencies = [ + "indenter", + "once_cell", +] + [[package]] name = "fastrand" version = "2.3.0" @@ -1539,16 +1576,18 @@ dependencies = [ [[package]] name = "hyperware_process_lib" -version = "1.0.5" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd85e48b5f017132d52df416578fe6816b51d166b70ffd8718dbe29ae979d98b" +checksum = "414dd471dfac43943b314200b4943f38c4b08337103840e2192cfb5dc9b1bea5" dependencies = [ "alloy", "alloy-primitives", "alloy-sol-macro", "alloy-sol-types", "anyhow", + "base64", "bincode", + "color-eyre", "http", "mime_guess", "rand", @@ -1557,6 +1596,9 @@ dependencies = [ "serde", "serde_json", "thiserror 1.0.69", + "tracing", + "tracing-error", + "tracing-subscriber", "url", "wit-bindgen", ] @@ -1726,6 +1768,12 @@ dependencies = [ "syn 2.0.91", ] +[[package]] +name = "indenter" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" + [[package]] name = "indexmap" version = "2.7.0" @@ -1870,6 +1918,15 @@ dependencies = [ "hashbrown 0.15.2", ] +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata 0.1.10", +] + [[package]] name = "memchr" version = "2.7.4" @@ -1940,6 +1997,16 @@ dependencies = [ "wit-bindgen", ] +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + [[package]] name = "num-bigint" version = "0.4.6" @@ -2071,6 +2138,18 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + +[[package]] +name = "owo-colors" +version = "4.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1036865bb9422d3300cf723f657c2851d0e9ab12567854b1f4eba3d77decf564" + [[package]] name = "parity-scale-codec" version = "3.6.12" @@ -2285,7 +2364,7 @@ dependencies = [ "rand", "rand_chacha", "rand_xorshift", - "regex-syntax", + "regex-syntax 0.8.5", "rusty-fork", "tempfile", "unarray", @@ -2369,8 +2448,17 @@ checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", - "regex-automata", - "regex-syntax", + "regex-automata 0.4.9", + "regex-syntax 0.8.5", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax 0.6.29", ] [[package]] @@ -2381,9 +2469,15 @@ checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", - "regex-syntax", + "regex-syntax 0.8.5", ] +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + [[package]] name = "regex-syntax" version = "0.8.5" @@ -2764,6 +2858,15 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + [[package]] name = "shlex" version = "1.3.0" @@ -2991,6 +3094,16 @@ dependencies = [ "syn 2.0.91", ] +[[package]] +name = "thread_local" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +dependencies = [ + "cfg-if", + "once_cell", +] + [[package]] name = "threadpool" version = "1.8.1" @@ -3153,6 +3266,59 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" dependencies = [ "once_cell", + "valuable", +] + +[[package]] +name = "tracing-error" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b1581020d7a273442f5b45074a6a57d5757ad0a47dac0e9f0bd57b81936f3db" +dependencies = [ + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-serde" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "704b1aeb7be0d0a84fc9828cae51dab5970fee5088f83d1dd7ee6f6246fc6ff1" +dependencies = [ + "serde", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex", + "serde", + "serde_json", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", + "tracing-serde", ] [[package]] @@ -3404,6 +3570,28 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + [[package]] name = "windows-registry" version = "0.2.0" diff --git a/hyperdrive/packages/hns-indexer/get-block/Cargo.toml b/hyperdrive/packages/hns-indexer/get-block/Cargo.toml index 74a14da14..ec48b9197 100644 --- a/hyperdrive/packages/hns-indexer/get-block/Cargo.toml +++ b/hyperdrive/packages/hns-indexer/get-block/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" simulation-mode = [] [dependencies] -hyperware_process_lib = "1.0.5" +hyperware_process_lib = "1.2.0" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" wit-bindgen = "0.36.0" diff --git a/hyperdrive/packages/hns-indexer/hns-indexer/Cargo.toml b/hyperdrive/packages/hns-indexer/hns-indexer/Cargo.toml index f84b6e7c8..470bf8f2f 100644 --- a/hyperdrive/packages/hns-indexer/hns-indexer/Cargo.toml +++ b/hyperdrive/packages/hns-indexer/hns-indexer/Cargo.toml @@ -4,14 +4,14 @@ version = "0.2.0" edition = "2021" [features] -simulation-mode = [] +simulation-mode = ["hyperware_process_lib/simulation-mode"] [dependencies] anyhow = "1.0" alloy-primitives = "0.8.15" alloy-sol-types = "0.8.15" hex = "0.4.3" -hyperware_process_lib = "1.0.5" +hyperware_process_lib = { version = "1.2.0", features = ["logging"] } process_macros = "0.1" rmp-serde = "1.1.2" serde = { version = "1.0", features = ["derive"] } diff --git a/hyperdrive/packages/hns-indexer/hns-indexer/src/lib.rs b/hyperdrive/packages/hns-indexer/hns-indexer/src/lib.rs index 225ab3981..c7a9d6ed0 100644 --- a/hyperdrive/packages/hns-indexer/hns-indexer/src/lib.rs +++ b/hyperdrive/packages/hns-indexer/hns-indexer/src/lib.rs @@ -5,12 +5,13 @@ use crate::hyperware::process::hns_indexer::{ use alloy_primitives::keccak256; use alloy_sol_types::SolEvent; use hyperware::process::standard::clear_state; +use hyperware_process_lib::logging::{debug, error, info, init_logging, warn, Level}; use hyperware_process_lib::{ - await_message, call_init, eth, get_state, hypermap, net, print_to_terminal, println, set_state, - timer, Address, Capability, Message, Request, Response, + await_message, call_init, eth, get_state, hypermap, net, set_state, timer, Address, Capability, + Message, Request, Response, }; use std::{ - collections::{BTreeMap, HashMap}, + collections::{BTreeMap, HashMap, HashSet}, net::{IpAddr, Ipv4Addr, Ipv6Addr}, str::FromStr, }; @@ -22,24 +23,17 @@ wit_bindgen::generate!({ additional_derives: [serde::Deserialize, serde::Serialize, process_macros::SerdeJsonInto], }); -const HYPERMAP_ADDRESS: &'static str = hypermap::HYPERMAP_ADDRESS; +const MAX_PENDING_ATTEMPTS: u8 = 5; +const SUBSCRIPTION_TIMEOUT_S: u64 = 60; +// 2s: +// - compare to src/eth/mod.rs DELAY_MS of 1_000: long enough to invalidate cache +// - ~ block time on Base +const DELAY_MS: u64 = 2_000; +const CHECKPOINT_MS: u64 = 5 * 60 * 1_000; // 5 minutes -#[cfg(not(feature = "simulation-mode"))] -const CHAIN_ID: u64 = hypermap::HYPERMAP_CHAIN_ID; // base -#[cfg(feature = "simulation-mode")] -const CHAIN_ID: u64 = 31337; // local - -#[cfg(not(feature = "simulation-mode"))] -const HYPERMAP_FIRST_BLOCK: u64 = hypermap::HYPERMAP_FIRST_BLOCK; // base -#[cfg(feature = "simulation-mode")] -const HYPERMAP_FIRST_BLOCK: u64 = 1; // local +type PendingNotes = BTreeMap>; -const MAX_PENDING_ATTEMPTS: u8 = 3; -const SUBSCRIPTION_TIMEOUT: u64 = 60; -const DELAY_MS: u64 = 1_000; // 1s -const CHECKPOINT_MS: u64 = 300_000; // 5 minutes - -#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)] +#[derive(serde::Serialize, serde::Deserialize)] struct State { /// the chain id we are indexing chain_id: u64, @@ -54,13 +48,68 @@ struct State { } impl State { + fn load() -> Option { + let Some(ref state_bytes) = get_state() else { + return None; + }; + + rmp_serde::from_slice(state_bytes).ok() + } +} + +#[derive(Clone, serde::Serialize)] +struct StateV1 { + /// namehash to human readable name + names: HashMap, + /// human readable name to most recent on-chain routing information as json + nodes: HashMap, + /// last saved checkpoint block + last_block: u64, + #[serde(skip)] + hypermap: hypermap::Hypermap, + /// notes are under a mint; in case they come out of order, store till next block + // #[serde(skip)] // TODO: ? + pending_notes: PendingNotes, + #[serde(skip)] + is_checkpoint_timer_live: bool, +} + +impl<'de> serde::Deserialize<'de> for StateV1 { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + // Create a helper struct without the hypermap field + #[derive(serde::Deserialize)] + struct StateHelper { + names: HashMap, + nodes: HashMap, + last_block: u64, + pending_notes: PendingNotes, + } + + let helper = StateHelper::deserialize(deserializer)?; + + Ok(StateV1 { + names: helper.names, + nodes: helper.nodes, + last_block: helper.last_block, + hypermap: hypermap::Hypermap::default(SUBSCRIPTION_TIMEOUT_S), + pending_notes: helper.pending_notes, + is_checkpoint_timer_live: false, + }) + } +} + +impl StateV1 { fn new() -> Self { - State { - chain_id: CHAIN_ID, - contract_address: eth::Address::from_str(HYPERMAP_ADDRESS).unwrap(), + StateV1 { names: HashMap::new(), nodes: HashMap::new(), - last_checkpoint_block: HYPERMAP_FIRST_BLOCK, + last_block: hypermap::HYPERMAP_FIRST_BLOCK, + hypermap: hypermap::Hypermap::default(SUBSCRIPTION_TIMEOUT_S), + pending_notes: BTreeMap::new(), + is_checkpoint_timer_live: false, } } @@ -70,7 +119,7 @@ impl State { Some(state_bytes) => match rmp_serde::from_slice(&state_bytes) { Ok(state) => state, Err(e) => { - println!("failed to deserialize saved state: {e:?}"); + warn!("failed to deserialize saved state: {e:?}"); Self::new() } }, @@ -83,604 +132,619 @@ impl State { } /// Saves a checkpoint, serializes to the current block - fn save(&mut self, block: u64) { - self.last_checkpoint_block = block; + fn save(&mut self) { match rmp_serde::to_vec(self) { Ok(state_bytes) => set_state(&state_bytes), - Err(e) => println!("failed to serialize state: {e:?}"), + Err(e) => error!("failed to serialize state: {e:?}"), } } - /// loops through saved nodes, and sends them to net + /// sends saved nodes to net + /// /// called upon bootup fn send_nodes(&self) -> anyhow::Result<()> { - for node in self.nodes.values() { - Request::to(("our", "net", "distro", "sys")) - .body(rmp_serde::to_vec(&net::NetAction::HnsUpdate(node.clone()))?) - .send()?; - } + Request::to(("our", "net", "distro", "sys")) + .body(rmp_serde::to_vec(&net::NetAction::HnsBatchUpdate( + self.nodes.values().cloned().collect(), + ))?) + .send()?; Ok(()) } -} -impl From for WitHnsUpdate { - fn from(k: net::HnsUpdate) -> Self { - WitHnsUpdate { - name: k.name, - public_key: k.public_key, - ips: k.ips, - ports: k.ports.into_iter().map(|(k, v)| (k, v)).collect::>(), - routers: k.routers, - } - } -} - -impl From for net::HnsUpdate { - fn from(k: WitHnsUpdate) -> Self { - net::HnsUpdate { - name: k.name, - public_key: k.public_key, - ips: k.ips, - ports: BTreeMap::from_iter(k.ports), - routers: k.routers, - } - } -} + fn subscribe(&self) { + let (mints_filter, notes_filter) = make_filters(); -impl From for WitState { - fn from(s: State) -> Self { - let contract_address: [u8; 20] = s.contract_address.into(); - WitState { - chain_id: s.chain_id, - contract_address: contract_address.to_vec(), - names: s.names.into_iter().map(|(k, v)| (k, v)).collect::>(), - nodes: s - .nodes - .into_iter() - .map(|(k, v)| (k, v.into())) - .collect::>(), - last_block: s.last_checkpoint_block, - } + self.hypermap.provider.subscribe_loop(1, mints_filter, 1, 0); + self.hypermap.provider.subscribe_loop(2, notes_filter, 1, 0); } -} -#[derive(Debug, thiserror::Error)] -enum HnsError { - #[error("Parent node for note not found")] - NoParentError, -} + fn fetch_and_process_logs(&mut self, nodes: HashSet) { + let (mints_filter, notes_filter) = make_filters(); -call_init!(init); -fn init(our: Address) { - println!("started"); + // confirm or try to get networking info for bootstrap nodes + for node in nodes.iter() { + match self.handle_node_info_request(node, &None) { + Err(e) => println!("bootstrap node {node} lookup failed: {e}"), + Ok(IndexerResponse::NodeInfo(Some(WitHnsUpdate { routers, .. }))) => { + if !routers.is_empty() { + println!("bootstrap node {node} is indirect; recommend using direct bootstrap nodes"); + } + } + Ok(_) => {} + } + } - // state is checkpointed regularly (default every 5 minutes if new events are found) - let mut state = State::load(); + match self.hypermap.bootstrap( + Some(self.last_block), + vec![mints_filter, notes_filter], + Some((5, None)), + None, + ) { + Err(e) => println!("bootstrap from cache failed: {e:?}"), + Ok((block, mut logs)) => { + if block > self.last_block { + self.last_block = block; + } + // make new filters with updated `last_block` + let (mints_filter, notes_filter) = make_filters_with_from_to(Some(self.last_block)); + + assert_eq!(logs.len(), 2); + let maybe_notes_logs = logs.pop(); + let maybe_mints_logs = logs.pop(); + self.fetch_and_process_logs_filter(mints_filter, maybe_mints_logs); + self.fetch_and_process_logs_filter(notes_filter, maybe_notes_logs); + } + } - loop { - if let Err(e) = main(&our, &mut state) { - println!("fatal error: {e}"); - break; + if let Err(e) = self.handle_pending_notes() { + error!( + "fetch_and_process_logs: failed to handle {} pending notes: {e:?}", + self.pending_notes.len() + ); } } -} -fn main(our: &Address, state: &mut State) -> anyhow::Result<()> { - #[cfg(feature = "simulation-mode")] - add_temp_hardcoded_tlzs(state); + /// Get logs for a filter then process them while taking pending notes into account. + fn fetch_and_process_logs_filter( + &mut self, + filter: eth::Filter, + maybe_logs: Option>, + ) { + if let Some(logs) = maybe_logs { + debug!("cached log len: {}", logs.len()); + for log in logs { + if let Err(e) = self.handle_log(&log) { + error!("log-handling error! {e:?}"); + } + } + } - // loop through checkpointed values and send to net - if let Err(e) = state.send_nodes() { - // todo change verbosity - println!("failed to send nodes to net: {e}"); + loop { + match self.hypermap.provider.get_logs(&filter) { + Ok(logs) => { + debug!("log len: {}", logs.len()); + for log in logs { + if let Err(e) = self.handle_log(&log) { + error!("log-handling error! {e:?}"); + } + } + return; + } + Err(e) => { + error!("got eth error while fetching logs: {e:?}, trying again in 5s..."); + std::thread::sleep(std::time::Duration::from_secs(5)); + } + } + } } - // current block is only saved to state upon checkpoints, we use this to keep track of last events - // set to checkpoint-1 - let mut last_block = state.last_checkpoint_block.saturating_sub(1); - - // sub_id: 1 - // listen to all mint events in hypermap - let mints_filter = eth::Filter::new() - .address(state.contract_address) - .from_block(last_block) - .to_block(eth::BlockNumberOrTag::Latest) - .event("Mint(bytes32,bytes32,bytes,bytes)"); - - // sub_id: 2 - // listen to all note events that are relevant to the HNS protocol within hypermap - let notes_filter = eth::Filter::new() - .address(state.contract_address) - .from_block(last_block) - .to_block(eth::BlockNumberOrTag::Latest) - .event("Note(bytes32,bytes32,bytes,bytes,bytes)") - .topic3(vec![ - keccak256("~ws-port"), - keccak256("~tcp-port"), - keccak256("~net-key"), - keccak256("~routers"), - keccak256("~ip"), - ]); + fn handle_eth_message(&mut self, body: &[u8]) -> anyhow::Result<()> { + match serde_json::from_slice::(body) { + Ok(Ok(eth::EthSub { result, .. })) => { + if let Ok(eth::SubscriptionResult::Log(log)) = + serde_json::from_value::(result) + { + if let Err(e) = self.handle_log(&log) { + error!("log-handling error! {e:?}"); + } + } + } + Ok(Err(e)) => { + error!("got eth subscription error ({e:?}), resubscribing"); + let (mints_filter, notes_filter) = make_filters(); + if e.id == 1 { + self.hypermap.provider.subscribe_loop(1, mints_filter, 2, 0); + } else if e.id == 2 { + self.hypermap.provider.subscribe_loop(2, notes_filter, 2, 0); + } + } + Err(e) => { + error!("failed to deserialize message from eth:distro:sys: {e:?}") + } + } - // 60s timeout -- these calls can take a long time - // if they do time out, we try them again - let eth_provider: eth::Provider = eth::Provider::new(state.chain_id, SUBSCRIPTION_TIMEOUT); + self.handle_pending_notes()?; - // subscribe to logs first, so no logs are missed - eth_provider.subscribe_loop(1, mints_filter.clone(), 2, 0); - eth_provider.subscribe_loop(2, notes_filter.clone(), 2, 0); + Ok(()) + } - // if subscription results come back in the wrong order, we store them here - // until the right block is reached. + fn handle_log(&mut self, log: ð::Log) -> anyhow::Result<()> { + if let Some(block) = log.block_number { + if block > self.last_block { + self.last_block = block; + } + } - // pending_requests temporarily on timeout. - // very naughty. - // let mut pending_requests: BTreeMap> = BTreeMap::new(); - let mut pending_notes: BTreeMap> = BTreeMap::new(); + match log.topics()[0] { + hypermap::contract::Mint::SIGNATURE_HASH => { + let decoded = hypermap::contract::Mint::decode_log_data(log.data(), true).unwrap(); + let parent_hash = decoded.parenthash.to_string(); + let child_hash = decoded.childhash.to_string(); + let name = String::from_utf8(decoded.label.to_vec())?; - // if block in state is < current_block, get logs from that part. - print_to_terminal(2, &format!("syncing old logs from block: {}", last_block)); - fetch_and_process_logs( - ð_provider, - state, - mints_filter.clone(), - &mut pending_notes, - &mut last_block, - ); - fetch_and_process_logs( - ð_provider, - state, - notes_filter.clone(), - &mut pending_notes, - &mut last_block, - ); + self.add_mint(&parent_hash, &child_hash, &name)?; + } + hypermap::contract::Note::SIGNATURE_HASH => { + let (decoded, parent_hash, note) = decode_note(log)?; - // set a timer tick so any pending logs will be processed - timer::set_timer(DELAY_MS, None); + self.add_note(&parent_hash, ¬e, &decoded.data, log.block_number, 0)?; + } + _ => {} + }; - // set a timer tick for checkpointing - timer::set_timer(CHECKPOINT_MS, Some(b"checkpoint".to_vec())); + Ok(()) + } - print_to_terminal(2, "done syncing old logs."); + fn add_mint(&mut self, parent_hash: &str, child_hash: &str, name: &str) -> anyhow::Result<()> { + if !hypermap::valid_name(&name) { + return Err(anyhow::anyhow!("skipping invalid name: {name}")); + } - loop { - let Ok(message) = await_message() else { - continue; + let full_name = match self.names.get(parent_hash) { + Some(parent_name) => &format!("{name}.{parent_name}"), + None => name, }; + debug!("mint {full_name}"); + + self.names + .insert(child_hash.to_string(), full_name.to_string()); + self.nodes.insert( + full_name.to_string(), + net::HnsUpdate { + name: full_name.to_string(), + public_key: String::new(), + ips: Vec::new(), + ports: BTreeMap::new(), + routers: Vec::new(), + }, + ); - // if true, time to go check current block number and handle pending notes. - let tick = message.is_local() && message.source().process == "timer:distro:sys"; - let checkpoint = message.is_local() - && message.source().process == "timer:distro:sys" - && message.context() == Some(b"checkpoint"); + Ok(()) + } - let Message::Request { - source, - body, - capabilities, - expects_response, - .. - } = message - else { - if tick { - handle_eth_message( - state, - ð_provider, - tick, - checkpoint, - &mut pending_notes, - &[], - &mints_filter, - ¬es_filter, - &mut last_block, - )?; + fn add_note( + &mut self, + parent_hash: &str, + note: &str, + data: ð::Bytes, + block_number: Option, + attempt_number: u8, + ) -> anyhow::Result<()> { + if !hypermap::valid_note(note) { + return Err(anyhow::anyhow!("skipping invalid note: {note}")); + } + + let Some(parent_name) = self.names.get(parent_hash) else { + if let Some(block_number) = block_number { + self.pending_notes.entry(block_number).or_default().push(( + parent_hash.to_string(), + note.to_string(), + data.clone(), + attempt_number, + )); + debug!("note put into pending: {note}"); + } else { + error!("note should go into pending, but no block_number given. dropping note. parent_hash, note: {parent_hash}, {note}"); } - continue; + return Ok(()); }; - - if source.node() == our.node() && source.process == "eth:distro:sys" { - handle_eth_message( - state, - ð_provider, - tick, - checkpoint, - &mut pending_notes, - &body, - &mints_filter, - ¬es_filter, - &mut last_block, - )?; - } else { - let response_body = match serde_json::from_slice(&body)? { - IndexerRequest::NamehashToName(NamehashToNameRequest { ref hash, .. }) => { - // TODO: make sure we've seen the whole block, while actually - // sending a response to the proper place. - IndexerResponse::Name(state.names.get(hash).cloned()) + debug!("note {parent_name}: {note}"); + + match note { + "~ws-port" => { + let ws = bytes_to_port(data)?; + if let Some(node) = self.nodes.get_mut(parent_name) { + node.ports.insert("ws".to_string(), ws); + // port defined, -> direct + node.routers = vec![]; } - IndexerRequest::NodeInfo(NodeInfoRequest { ref name, .. }) => { - // if we don't have the node in our state, before sending a response, - // try a hypermap get to see if it exists onchain and the indexer missed it. - match state.nodes.get(name) { - Some(node) => IndexerResponse::NodeInfo(Some(node.clone().into())), - None => { - let mut response = IndexerResponse::NodeInfo(None); - if let Some(timeout) = expects_response { - if let Some(hns_update) = fetch_node(timeout, name, state) { - response = - IndexerResponse::NodeInfo(Some(hns_update.clone().into())); - // save the node to state - state.nodes.insert(name.clone(), hns_update.clone()); - // produce namehash and save in names map - state.names.insert(hypermap::namehash(name), name.clone()); - // send the node to net - Request::to(("our", "net", "distro", "sys")) - .body(rmp_serde::to_vec(&net::NetAction::HnsUpdate( - hns_update, - ))?) - .send()?; - } - } - response - } - } + } + "~tcp-port" => { + let tcp = bytes_to_port(data)?; + if let Some(node) = self.nodes.get_mut(parent_name) { + node.ports.insert("tcp".to_string(), tcp); + // port defined, -> direct + node.routers = vec![]; } - IndexerRequest::Reset => { - // check for root capability - let root_cap = Capability::new(our.clone(), "{\"root\":true}"); - if source.package_id() != our.package_id() && !capabilities.contains(&root_cap) - { - IndexerResponse::Reset(ResetResult::Err(ResetError::NoRootCap)) - } else { - // reload state fresh - this will create new db - state.reset(); - IndexerResponse::Reset(ResetResult::Success) - } + } + "~net-key" => { + if data.len() != 32 { + return Err(anyhow::anyhow!("invalid net-key length")); } - IndexerRequest::GetState(_) => IndexerResponse::GetState(state.clone().into()), - }; - - if let IndexerResponse::Reset(ResetResult::Success) = response_body { - println!("resetting state"); - if expects_response.is_some() { - Response::new() - .body(IndexerResponse::Reset(ResetResult::Success)) - .send()?; + if let Some(node) = self.nodes.get_mut(parent_name) { + node.public_key = hex::encode(data); } - return Ok(()); - } else { - if expects_response.is_some() { - Response::new().body(response_body).send()?; + } + "~routers" => { + let Some(routers) = self.decode_routers(data) else { + if let Some(block_number) = block_number { + self.pending_notes.entry(block_number).or_default().push(( + parent_hash.to_string(), + note.to_string(), + data.clone(), + attempt_number, + )); + debug!("note put into pending: {note}"); + } else { + error!("note should go into pending, but no block_number given. dropping note. parent_hash, note: {parent_hash}, {note}"); + } + return Ok(()); + }; + if let Some(node) = self.nodes.get_mut(parent_name) { + node.routers = routers; + // -> indirect + node.ports = BTreeMap::new(); + node.ips = vec![]; } } - } - } -} - -fn handle_eth_message( - state: &mut State, - eth_provider: ð::Provider, - tick: bool, - checkpoint: bool, - pending_notes: &mut BTreeMap>, - body: &[u8], - mints_filter: ð::Filter, - notes_filter: ð::Filter, - last_block: &mut u64, -) -> anyhow::Result<()> { - match serde_json::from_slice::(body) { - Ok(Ok(eth::EthSub { result, .. })) => { - if let Ok(eth::SubscriptionResult::Log(log)) = - serde_json::from_value::(result) - { - if let Err(e) = handle_log(state, pending_notes, &log, last_block) { - print_to_terminal(1, &format!("log-handling error! {e:?}")); + "~ip" => { + let ip = bytes_to_ip(data)?; + if let Some(node) = self.nodes.get_mut(parent_name) { + node.ips = vec![ip.to_string()]; + // -> direct + node.routers = vec![]; } } - } - Ok(Err(e)) => { - println!("got eth subscription error ({e:?}), resubscribing"); - if e.id == 1 { - eth_provider.subscribe_loop(1, mints_filter.clone(), 2, 0); - } else if e.id == 2 { - eth_provider.subscribe_loop(2, notes_filter.clone(), 2, 0); + _other => { + // Ignore unknown notes } } - _ => {} - } - if tick { - let block_number = eth_provider.get_block_number(); - if let Ok(block_number) = block_number { - print_to_terminal(2, &format!("new block: {}", block_number)); - *last_block = block_number; - if checkpoint { - state.save(block_number); + // only send an update if we have a *full* set of data for networking: + // a node name, plus either or + if let Some(node_info) = self.nodes.get(parent_name) { + if !node_info.public_key.is_empty() + && ((!node_info.ips.is_empty() && !node_info.ports.is_empty()) + || node_info.routers.len() > 0) + { + Request::to(("our", "net", "distro", "sys")) + .body(rmp_serde::to_vec(&net::NetAction::HnsUpdate( + node_info.clone(), + ))?) + .send()?; } } - } - handle_pending_notes(state, pending_notes, last_block)?; - if !pending_notes.is_empty() { - timer::set_timer(DELAY_MS, None); + Ok(()) } - Ok(()) -} + fn handle_pending_notes(&mut self) -> anyhow::Result<()> { + if self.pending_notes.is_empty() { + return Ok(()); + } -fn handle_pending_notes( - state: &mut State, - pending_notes: &mut BTreeMap>, - last_block: &mut u64, -) -> anyhow::Result<()> { - if pending_notes.is_empty() { - return Ok(()); - } - let mut blocks_to_remove = vec![]; - - for (block, notes) in pending_notes.iter_mut() { - if block < last_block { - let mut keep_notes = Vec::new(); - for (note, attempt) in notes.drain(..) { - if attempt >= MAX_PENDING_ATTEMPTS { - // skip notes that have exceeded max attempts - continue; - } - if let Err(e) = handle_note(state, ¬e) { - match e.downcast_ref::() { - None => { - print_to_terminal(1, &format!("pending note handling error: {e:?}")) - } - Some(HnsError::NoParentError) => { - keep_notes.push((note, attempt + 1)); - } + // walk through pending_notes + // - add_note() ones that are ripe + // - push unripe back into pending_notes + let pending_notes = std::mem::take(&mut self.pending_notes); + for (block, notes) in pending_notes { + if block >= self.last_block { + // not ripe yet: push back into pending_notes + self.pending_notes.insert(block, notes); + } else { + // ripe: call add_note() + for (parent_hash, note, data, attempt) in notes.iter() { + if attempt >= &MAX_PENDING_ATTEMPTS { + error!("pending note exceeded max attempts; dropping: parent_hash, note: {parent_hash}, {note}"); + continue; } + self.add_note(parent_hash, note, data, Some(block), attempt + 1)?; } } - if keep_notes.is_empty() { - blocks_to_remove.push(*block); - } else { - *notes = keep_notes; - } } - } - - // remove processed blocks - for block in blocks_to_remove { - pending_notes.remove(&block); - } - Ok(()) -} - -fn handle_note(state: &mut State, note: &hypermap::contract::Note) -> anyhow::Result<()> { - let note_label = String::from_utf8(note.label.to_vec())?; - let node_hash = note.parenthash.to_string(); + if !self.pending_notes.is_empty() { + timer::set_timer(DELAY_MS, None); + } - if !hypermap::valid_note(¬e_label) { - return Err(anyhow::anyhow!("skipping invalid note: {note_label}")); + Ok(()) } - let Some(node_name) = state.names.get(&node_hash) else { - return Err(HnsError::NoParentError.into()); - }; - print_to_terminal(3, &format!("note {node_name}: {note_label}")); - - match note_label.as_str() { - "~ws-port" => { - let ws = bytes_to_port(¬e.data)?; - if let Some(node) = state.nodes.get_mut(node_name) { - node.ports.insert("ws".to_string(), ws); - // port defined, -> direct - node.routers = vec![]; - } - } - "~tcp-port" => { - let tcp = bytes_to_port(¬e.data)?; - if let Some(node) = state.nodes.get_mut(node_name) { - node.ports.insert("tcp".to_string(), tcp); - // port defined, -> direct - node.routers = vec![]; - } - } - "~net-key" => { - if note.data.len() != 32 { - return Err(anyhow::anyhow!("invalid net-key length")); + fn handle_tick(&mut self, is_checkpoint: bool) -> anyhow::Result<()> { + let block_number = self.hypermap.provider.get_block_number(); + if let Ok(block_number) = block_number { + debug!("new block: {block_number}"); + if block_number > self.last_block { + self.last_block = block_number; } - if let Some(node) = state.nodes.get_mut(node_name) { - node.public_key = hex::encode(¬e.data); + if is_checkpoint { + self.is_checkpoint_timer_live = false; + self.save(); } } - "~routers" => { - let routers = decode_routers(¬e.data, state); - if let Some(node) = state.nodes.get_mut(node_name) { - node.routers = routers; - // -> indirect - node.ports = BTreeMap::new(); - node.ips = vec![]; - } + + self.handle_pending_notes()?; + + Ok(()) + } + + /// Decodes bytes under ~routers in hypermap into an array of keccak256 hashes (32 bytes each) + /// and returns the associated node identities. + fn decode_routers(&self, data: &[u8]) -> Option> { + if data.len() % 32 != 0 { + warn!("got invalid data length for router hashes: {}", data.len()); + return Some(vec![]); } - "~ip" => { - let ip = bytes_to_ip(¬e.data)?; - if let Some(node) = state.nodes.get_mut(node_name) { - node.ips = vec![ip.to_string()]; - // -> direct - node.routers = vec![]; + + let mut routers = Vec::new(); + for chunk in data.chunks(32) { + let hash_str = format!("0x{}", hex::encode(chunk)); + + match self.names.get(&hash_str) { + Some(full_name) => routers.push(full_name.clone()), + None => { + error!("no name found for router hash {hash_str}"); + return None; + } } } - _other => { - // Ignore unknown notes - } - } - // only send an update if we have a *full* set of data for networking: - // a node name, plus either or - if let Some(node_info) = state.nodes.get(node_name) { - if !node_info.public_key.is_empty() - && ((!node_info.ips.is_empty() && !node_info.ports.is_empty()) - || node_info.routers.len() > 0) - { - Request::to(("our", "net", "distro", "sys")) - .body(rmp_serde::to_vec(&net::NetAction::HnsUpdate( - node_info.clone(), - ))?) - .send()?; - } + Some(routers) } - Ok(()) -} + pub fn fetch_node(&self, timeout: &u64, name: &str) -> Option { + let hypermap = hypermap::Hypermap::default(timeout - 1); + if let Ok((_tba, _owner, _data)) = hypermap.get(name) { + let Ok(Some(public_key_bytes)) = hypermap + .get(&format!("~net-key.{name}")) + .map(|(_, _, data)| data) + else { + return None; + }; -fn handle_log( - state: &mut State, - pending_notes: &mut BTreeMap>, - log: ð::Log, - last_block: &mut u64, -) -> anyhow::Result<()> { - if let Some(block) = log.block_number { - *last_block = block; - } + let maybe_ip = hypermap + .get(&format!("~ip.{name}")) + .map(|(_, _, data)| data.map(|b| bytes_to_ip(&b))); + + let maybe_tcp_port = hypermap + .get(&format!("~tcp-port.{name}")) + .map(|(_, _, data)| data.map(|b| bytes_to_port(&b))); - match log.topics()[0] { - hypermap::contract::Mint::SIGNATURE_HASH => { - let decoded = hypermap::contract::Mint::decode_log_data(log.data(), true).unwrap(); - let parent_hash = decoded.parenthash.to_string(); - let child_hash = decoded.childhash.to_string(); - let name = String::from_utf8(decoded.label.to_vec())?; + let maybe_ws_port = hypermap + .get(&format!("~ws-port.{name}")) + .map(|(_, _, data)| data.map(|b| bytes_to_port(&b))); - if !hypermap::valid_name(&name) { - return Err(anyhow::anyhow!("skipping invalid name: {name}")); + let maybe_routers = hypermap + .get(&format!("~routers.{name}")) + .map(|(_, _, data)| data.and_then(|b| self.decode_routers(&b))); + + let mut ports = BTreeMap::new(); + if let Ok(Some(Ok(tcp_port))) = maybe_tcp_port { + ports.insert("tcp".to_string(), tcp_port); + } + if let Ok(Some(Ok(ws_port))) = maybe_ws_port { + ports.insert("ws".to_string(), ws_port); } - let full_name = match state.names.get(&parent_hash) { - Some(parent_name) => format!("{name}.{parent_name}"), - None => name, - }; - print_to_terminal(3, &format!("mint {full_name}")); - - state.names.insert(child_hash.clone(), full_name.clone()); - state.nodes.insert( - full_name.clone(), - net::HnsUpdate { - name: full_name.clone(), - public_key: String::new(), - ips: Vec::new(), - ports: BTreeMap::new(), - routers: Vec::new(), + Some(net::HnsUpdate { + name: name.to_string(), + public_key: hex::encode(public_key_bytes), + ips: if let Ok(Some(Ok(ip))) = maybe_ip { + vec![ip.to_string()] + } else { + vec![] }, - ); + ports, + routers: if let Ok(Some(routers)) = maybe_routers { + routers + } else { + vec![] + }, + }) + } else { + None } - hypermap::contract::Note::SIGNATURE_HASH => { - let decoded = hypermap::contract::Note::decode_log_data(log.data(), true).unwrap(); - let note: String = String::from_utf8(decoded.label.to_vec())?; + } + + fn handle_indexer_request(&mut self, our: &Address, message: Message) -> anyhow::Result { + let mut is_reset = false; - if !hypermap::valid_note(¬e) { - return Err(anyhow::anyhow!("skipping invalid note: {note}")); + let Message::Request { + ref expects_response, + .. + } = message + else { + return Err(anyhow::anyhow!( + "got Response input to handle_indexer_request" + )); + }; + + let response_body = match message.body().try_into()? { + IndexerRequest::NamehashToName(NamehashToNameRequest { ref hash, .. }) => { + // TODO: make sure we've seen the whole block, while actually + // sending a response to the proper place. + IndexerResponse::Name(self.names.get(hash).cloned()) } - // handle note: if it precedes parent mint event, add it to pending_notes - if let Err(e) = handle_note(state, &decoded) { - if let Some(HnsError::NoParentError) = e.downcast_ref::() { - if let Some(block_number) = log.block_number { - pending_notes - .entry(block_number) - .or_default() - .push((decoded, 0)); - } + IndexerRequest::NodeInfo(NodeInfoRequest { ref name, .. }) => { + self.handle_node_info_request(name, expects_response)? + } + IndexerRequest::Reset => { + // check for root capability + let root_cap = Capability::new(our.clone(), "{\"root\":true}"); + if message.source().package_id() != our.package_id() + || !message.capabilities().contains(&root_cap) + { + IndexerResponse::Reset(ResetResult::Err(ResetError::NoRootCap)) + } else { + // reload state fresh - this will create new db + info!("resetting state"); + self.reset(); + is_reset = true; + IndexerResponse::Reset(ResetResult::Success) } } + IndexerRequest::GetState(_) => IndexerResponse::GetState(self.clone().into()), + }; + + if expects_response.is_some() { + Response::new().body(response_body).send()?; } - _log => { - return Ok(()); - } - }; - Ok(()) -} + Ok(is_reset) + } -/// Get logs for a filter then process them while taking pending notes into account. -fn fetch_and_process_logs( - eth_provider: ð::Provider, - state: &mut State, - filter: eth::Filter, - pending_notes: &mut BTreeMap>, - last_block: &mut u64, -) { - loop { - match eth_provider.get_logs(&filter) { - Ok(logs) => { - print_to_terminal(2, &format!("log len: {}", logs.len())); - for log in logs { - if let Err(e) = handle_log(state, pending_notes, &log, last_block) { - print_to_terminal(1, &format!("log-handling error! {e:?}")); - } + fn handle_node_info_request( + &mut self, + name: &str, + timeout: &Option, + ) -> anyhow::Result { + match self.nodes.get(name) { + Some(node) => Ok(IndexerResponse::NodeInfo(Some(node.clone().into()))), + None => { + // we don't have the node in our state: try hypermap.get() + // to see if it exists onchain and the indexer missed it + let mut response = IndexerResponse::NodeInfo(None); + let timeout = timeout.unwrap_or_else(|| 5); + if let Some(hns_update) = self.fetch_node(&timeout, name) { + response = IndexerResponse::NodeInfo(Some(hns_update.clone().into())); + // save the node to state + self.nodes.insert(name.to_string(), hns_update.clone()); + // produce namehash and save in names map + self.names + .insert(hypermap::namehash(name), name.to_string()); + // send the node to net + Request::to(("our", "net", "distro", "sys")) + .body(rmp_serde::to_vec(&net::NetAction::HnsUpdate(hns_update))?) + .send()?; } - return; - } - Err(e) => { - println!("got eth error while fetching logs: {e:?}, trying again in 5s..."); - std::thread::sleep(std::time::Duration::from_secs(5)); + Ok(response) } } } } -fn fetch_node(timeout: u64, name: &str, state: &State) -> Option { - let hypermap = hypermap::Hypermap::default(timeout - 1); - if let Ok((_tba, _owner, _data)) = hypermap.get(name) { - let Ok(Some(public_key_bytes)) = hypermap - .get(&format!("~net-key.{name}")) - .map(|(_, _, data)| data) - else { - return None; - }; +fn decode_note(note_log: ð::Log) -> anyhow::Result<(hypermap::contract::Note, String, String)> { + let decoded = hypermap::contract::Note::decode_log_data(note_log.data(), true).unwrap(); + let parent_hash = decoded.parenthash.to_string(); + let note = String::from_utf8(decoded.label.to_vec())?; + Ok((decoded, parent_hash, note)) +} - let maybe_ip = hypermap - .get(&format!("~ip.{name}")) - .map(|(_, _, data)| data.map(|b| bytes_to_ip(&b))); +impl From for StateV1 { + fn from(old: State) -> Self { + StateV1 { + names: old.names, + nodes: old.nodes, + last_block: old.last_checkpoint_block, + hypermap: hypermap::Hypermap::default(SUBSCRIPTION_TIMEOUT_S), + pending_notes: BTreeMap::new(), + is_checkpoint_timer_live: false, + } + } +} - let maybe_tcp_port = hypermap - .get(&format!("~tcp-port.{name}")) - .map(|(_, _, data)| data.map(|b| bytes_to_port(&b))); +impl From for WitHnsUpdate { + fn from(k: net::HnsUpdate) -> Self { + WitHnsUpdate { + name: k.name, + public_key: k.public_key, + ips: k.ips, + ports: k.ports.into_iter().map(|(k, v)| (k, v)).collect::>(), + routers: k.routers, + } + } +} - let maybe_ws_port = hypermap - .get(&format!("~ws-port.{name}")) - .map(|(_, _, data)| data.map(|b| bytes_to_port(&b))); +impl From for net::HnsUpdate { + fn from(k: WitHnsUpdate) -> Self { + net::HnsUpdate { + name: k.name, + public_key: k.public_key, + ips: k.ips, + ports: BTreeMap::from_iter(k.ports), + routers: k.routers, + } + } +} - let maybe_routers = hypermap - .get(&format!("~routers.{name}")) - .map(|(_, _, data)| data.map(|b| decode_routers(&b, state))); +impl From for WitState { + fn from(s: StateV1) -> Self { + // TODO: store this + let contract_address: [u8; 20] = hypermap::HYPERMAP_ADDRESS.as_bytes().try_into().unwrap(); + let contract_address: Vec = contract_address.into(); - let mut ports = BTreeMap::new(); - if let Ok(Some(Ok(tcp_port))) = maybe_tcp_port { - ports.insert("tcp".to_string(), tcp_port); - } - if let Ok(Some(Ok(ws_port))) = maybe_ws_port { - ports.insert("ws".to_string(), ws_port); + WitState { + chain_id: hypermap::HYPERMAP_CHAIN_ID, + contract_address, + names: s.names.into_iter().map(|(k, v)| (k, v)).collect::>(), + nodes: s + .nodes + .into_iter() + .map(|(k, v)| (k, v.into())) + .collect::>(), + last_block: s.last_block, } + } +} - Some(net::HnsUpdate { - name: name.to_string(), - public_key: hex::encode(public_key_bytes), - ips: if let Ok(Some(Ok(ip))) = maybe_ip { - vec![ip.to_string()] - } else { - vec![] - }, - ports, - routers: if let Ok(Some(routers)) = maybe_routers { - routers - } else { - vec![] - }, +fn make_filters() -> (eth::Filter, eth::Filter) { + let hypermap_address = eth::Address::from_str(hypermap::HYPERMAP_ADDRESS).unwrap(); + // sub_id: 1 + // listen to all mint events in hypermap + let mints_filter = eth::Filter::new() + .address(hypermap_address) + .event(hypermap::contract::Mint::SIGNATURE); + + // sub_id: 2 + // listen to all note events that are relevant to the HNS protocol within hypermap + let notes_filter = eth::Filter::new() + .address(hypermap_address) + .event(hypermap::contract::Note::SIGNATURE) + .topic3(vec![ + keccak256("~ws-port"), + keccak256("~tcp-port"), + keccak256("~net-key"), + keccak256("~routers"), + keccak256("~ip"), + ]); + + (mints_filter, notes_filter) +} + +fn add_filter_from_to(from_block: Option, filters: Vec) -> Vec { + let from_block = from_block.unwrap_or_else(|| hypermap::HYPERMAP_FIRST_BLOCK); + filters + .into_iter() + .map(|filter| { + filter + .from_block(from_block) + .to_block(eth::BlockNumberOrTag::Latest) }) - } else { - None - } + .collect() +} + +fn make_filters_with_from_to(from_block: Option) -> (eth::Filter, eth::Filter) { + let (mints_filter, notes_filter) = make_filters(); + let mut filters = add_filter_from_to(from_block, vec![mints_filter, notes_filter]); + let notes_filter = filters.pop().unwrap(); + let mints_filter = filters.pop().unwrap(); + (mints_filter, notes_filter) } // TEMP. Either remove when event reimitting working with anvil, // or refactor into better structure(!) #[cfg(feature = "simulation-mode")] -fn add_temp_hardcoded_tlzs(state: &mut State) { +fn add_temp_hardcoded_tlzs(state: &mut StateV1) { // add some hardcoded top level zones state.names.insert( "0xdeeac81ae11b64e7cab86d089c306e5d223552a630f02633ce170d2786ff1bbd".to_string(), @@ -692,33 +756,6 @@ fn add_temp_hardcoded_tlzs(state: &mut State) { ); } -/// Decodes bytes under ~routers in hypermap into an array of keccak256 hashes (32 bytes each) -/// and returns the associated node identities. -fn decode_routers(data: &[u8], state: &State) -> Vec { - if data.len() % 32 != 0 { - print_to_terminal( - 1, - &format!("got invalid data length for router hashes: {}", data.len()), - ); - return vec![]; - } - - let mut routers = Vec::new(); - for chunk in data.chunks(32) { - let hash_str = format!("0x{}", hex::encode(chunk)); - - match state.names.get(&hash_str) { - Some(full_name) => routers.push(full_name.clone()), - None => print_to_terminal( - 1, - &format!("error: no name found for router hash {hash_str}"), - ), - } - } - - routers -} - /// convert IP address stored at ~ip in hypermap to IpAddr pub fn bytes_to_ip(bytes: &[u8]) -> anyhow::Result { match bytes.len() { @@ -743,3 +780,103 @@ pub fn bytes_to_port(bytes: &[u8]) -> anyhow::Result { _ => Err(anyhow::anyhow!("Invalid byte length for port")), } } + +fn main(our: &Address, state: &mut StateV1) -> anyhow::Result<()> { + #[cfg(feature = "simulation-mode")] + add_temp_hardcoded_tlzs(state); + + // loop through checkpointed values and send to net + if let Err(e) = state.send_nodes() { + error!("failed to send nodes to net: {e}"); + } + + state.subscribe(); + + // if block in state is < current_block, get logs from that part. + info!("syncing old logs from block: {}", state.last_block); + + let nodes: HashSet = ["nick.hypr".to_string()].into_iter().collect(); + state.fetch_and_process_logs(nodes); + + // set a timer tick so any pending logs will be processed + timer::set_timer(DELAY_MS, None); + + // set a timer tick for checkpointing + state.is_checkpoint_timer_live = true; + timer::set_timer(CHECKPOINT_MS, Some(b"checkpoint".to_vec())); + + debug!("done syncing old logs"); + + loop { + let mut is_checkpoint = false; + let mut is_reset = false; + + let Ok(message) = await_message() else { + continue; + }; + + if !message.is_local() { + info!( + "rejecting unexpected non-local message from {}", + message.source() + ); + } + + if !message.is_request() { + // only expect to hear Response from timer + if message.source().process == "timer:distro:sys" { + is_checkpoint = message.context() == Some(b"checkpoint"); + state.handle_tick(is_checkpoint)?; + } else { + info!("rejecting unexpected response from {}", message.source()); + } + } else { + if message.source().process == "eth:distro:sys" { + state.handle_eth_message(message.body())?; + } else { + is_reset = state.handle_indexer_request(our, message)?; + } + } + + if state.pending_notes.is_empty() && !state.is_checkpoint_timer_live && !is_checkpoint { + // set checkpoint timer + debug!("set checkpoint timer"); + state.is_checkpoint_timer_live = true; + timer::set_timer(CHECKPOINT_MS, Some(b"checkpoint".to_vec())); + } + + if is_reset { + // reset state works like: + // 1. call `state.reset()` to clear state on disk (happens in + // `handle_indexer_request()` + // 2. return from `main()`, causing `init()` to loop + // and call `main()` again + // 3. `main()` attempts to load state from disk, sees it is empty, + // and loads it from scratch from the chain + return Ok(()); + } + } +} + +call_init!(init); +fn init(our: Address) { + init_logging(Level::DEBUG, Level::INFO, None, None, None).unwrap(); + info!("begin"); + + // state is checkpointed regularly (default every 5 minutes if new events are found) + // + // to maintain backwards compatibility, try loading old version of state first + // (and convert to current version) + let mut state: StateV1 = if let Some(old) = State::load() { + old.into() + } else { + StateV1::load() + }; + + loop { + if let Err(e) = main(&our, &mut state) { + error!("fatal error: {e}"); + break; + } + } +} diff --git a/hyperdrive/packages/hns-indexer/node-info/Cargo.toml b/hyperdrive/packages/hns-indexer/node-info/Cargo.toml index e775065c7..a70f965ec 100644 --- a/hyperdrive/packages/hns-indexer/node-info/Cargo.toml +++ b/hyperdrive/packages/hns-indexer/node-info/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" simulation-mode = [] [dependencies] -hyperware_process_lib = "1.0.5" +hyperware_process_lib = "1.2.0" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" process_macros = "0.1" diff --git a/hyperdrive/packages/hns-indexer/pkg/manifest.json b/hyperdrive/packages/hns-indexer/pkg/manifest.json index ab71cdfa1..ef859d1fb 100644 --- a/hyperdrive/packages/hns-indexer/pkg/manifest.json +++ b/hyperdrive/packages/hns-indexer/pkg/manifest.json @@ -7,15 +7,21 @@ "request_capabilities": [ "eth:distro:sys", "http-server:distro:sys", + "hypermap-cacher:hypermap-cacher:sys", + "kv:distro:sys", "net:distro:sys", + "sign:sign:sys", "timer:distro:sys", - "kv:distro:sys" + "vfs:distro:sys" ], "grant_capabilities": [ "eth:distro:sys", "http-server:distro:sys", + "hypermap-cacher:hypermap-cacher:sys", + "kv:distro:sys", + "sign:sign:sys", "timer:distro:sys", - "kv:distro:sys" + "vfs:distro:sys" ], "public": false } diff --git a/hyperdrive/packages/hns-indexer/reset/Cargo.toml b/hyperdrive/packages/hns-indexer/reset/Cargo.toml index 61930503c..5a82f081a 100644 --- a/hyperdrive/packages/hns-indexer/reset/Cargo.toml +++ b/hyperdrive/packages/hns-indexer/reset/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" simulation-mode = [] [dependencies] -hyperware_process_lib = "1.0.5" +hyperware_process_lib = "1.2.0" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" process_macros = "0.1" diff --git a/hyperdrive/packages/hns-indexer/state/Cargo.toml b/hyperdrive/packages/hns-indexer/state/Cargo.toml index b38c6679a..c2b80f654 100644 --- a/hyperdrive/packages/hns-indexer/state/Cargo.toml +++ b/hyperdrive/packages/hns-indexer/state/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" simulation-mode = [] [dependencies] -hyperware_process_lib = "1.0.5" +hyperware_process_lib = "1.2.0" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" process_macros = "0.1" diff --git a/hyperdrive/packages/homepage/Cargo.lock b/hyperdrive/packages/homepage/Cargo.lock index cba4da3f2..95e6d23ef 100644 --- a/hyperdrive/packages/homepage/Cargo.lock +++ b/hyperdrive/packages/homepage/Cargo.lock @@ -1524,15 +1524,16 @@ dependencies = [ [[package]] name = "hyperware_process_lib" -version = "1.0.5" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd85e48b5f017132d52df416578fe6816b51d166b70ffd8718dbe29ae979d98b" +checksum = "414dd471dfac43943b314200b4943f38c4b08337103840e2192cfb5dc9b1bea5" dependencies = [ "alloy", "alloy-primitives", "alloy-sol-macro", "alloy-sol-types", "anyhow", + "base64", "bincode", "http", "mime_guess", diff --git a/hyperdrive/packages/homepage/homepage/Cargo.toml b/hyperdrive/packages/homepage/homepage/Cargo.toml index 727cc0965..fd71abab7 100644 --- a/hyperdrive/packages/homepage/homepage/Cargo.toml +++ b/hyperdrive/packages/homepage/homepage/Cargo.toml @@ -9,7 +9,7 @@ simulation-mode = [] [dependencies] anyhow = "1.0" bincode = "1.3.3" -hyperware_process_lib = "1.0.5" +hyperware_process_lib = "1.2.0" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" wit-bindgen = "0.36.0" diff --git a/hyperdrive/packages/hypermap-cacher/Cargo.lock b/hyperdrive/packages/hypermap-cacher/Cargo.lock new file mode 100644 index 000000000..02f0971e3 --- /dev/null +++ b/hyperdrive/packages/hypermap-cacher/Cargo.lock @@ -0,0 +1,4209 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "addr2line" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + +[[package]] +name = "ahash" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" +dependencies = [ + "cfg-if", + "getrandom 0.3.3", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + +[[package]] +name = "alloy" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59febb24956a41c29bb5f450978fbe825bd6456b3f80586c8bd558dc882e7b6a" +dependencies = [ + "alloy-consensus", + "alloy-core", + "alloy-eips", + "alloy-genesis", + "alloy-json-rpc", + "alloy-provider", + "alloy-rpc-client", + "alloy-rpc-types", + "alloy-serde", + "alloy-transport", + "alloy-transport-http", +] + +[[package]] +name = "alloy-chains" +version = "0.1.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28e2652684758b0d9b389d248b209ed9fd9989ef489a550265fe4bb8454fe7eb" +dependencies = [ + "alloy-primitives", + "num_enum", + "strum", +] + +[[package]] +name = "alloy-consensus" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e88e1edea70787c33e11197d3f32ae380f3db19e6e061e539a5bcf8184a6b326" +dependencies = [ + "alloy-eips", + "alloy-primitives", + "alloy-rlp", + "alloy-serde", + "alloy-trie", + "auto_impl", + "c-kzg", + "derive_more 1.0.0", + "serde", +] + +[[package]] +name = "alloy-consensus-any" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57b1bb53f40c0273cd1975573cd457b39213e68584e36d1401d25fd0398a1d65" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-primitives", + "alloy-rlp", + "alloy-serde", + "serde", +] + +[[package]] +name = "alloy-core" +version = "0.8.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d8bcce99ad10fe02640cfaec1c6bc809b837c783c1d52906aa5af66e2a196f6" +dependencies = [ + "alloy-dyn-abi", + "alloy-json-abi", + "alloy-primitives", + "alloy-rlp", + "alloy-sol-types", +] + +[[package]] +name = "alloy-dyn-abi" +version = "0.8.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb8e762aefd39a397ff485bc86df673465c4ad3ec8819cc60833a8a3ba5cdc87" +dependencies = [ + "alloy-json-abi", + "alloy-primitives", + "alloy-sol-type-parser", + "alloy-sol-types", + "const-hex", + "itoa", + "serde", + "serde_json", + "winnow", +] + +[[package]] +name = "alloy-eip2930" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0069cf0642457f87a01a014f6dc29d5d893cd4fd8fddf0c3cdfad1bb3ebafc41" +dependencies = [ + "alloy-primitives", + "alloy-rlp", + "serde", +] + +[[package]] +name = "alloy-eip7702" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c986539255fb839d1533c128e190e557e52ff652c9ef62939e233a81dd93f7e" +dependencies = [ + "alloy-primitives", + "alloy-rlp", + "derive_more 1.0.0", + "serde", +] + +[[package]] +name = "alloy-eips" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f9fadfe089e9ccc0650473f2d4ef0a28bc015bbca5631d9f0f09e49b557fdb3" +dependencies = [ + "alloy-eip2930", + "alloy-eip7702", + "alloy-primitives", + "alloy-rlp", + "alloy-serde", + "c-kzg", + "derive_more 1.0.0", + "once_cell", + "serde", + "sha2", +] + +[[package]] +name = "alloy-genesis" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b2a4cf7b70f3495788e74ce1c765260ffe38820a2a774ff4aacb62e31ea73f9" +dependencies = [ + "alloy-primitives", + "alloy-serde", + "alloy-trie", + "serde", +] + +[[package]] +name = "alloy-json-abi" +version = "0.8.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe6beff64ad0aa6ad1019a3db26fef565aefeb011736150ab73ed3366c3cfd1b" +dependencies = [ + "alloy-primitives", + "alloy-sol-type-parser", + "serde", + "serde_json", +] + +[[package]] +name = "alloy-json-rpc" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e29040b9d5fe2fb70415531882685b64f8efd08dfbd6cc907120650504821105" +dependencies = [ + "alloy-primitives", + "alloy-sol-types", + "serde", + "serde_json", + "thiserror 2.0.12", + "tracing", +] + +[[package]] +name = "alloy-network" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "510cc00b318db0dfccfdd2d032411cfae64fc144aef9679409e014145d3dacc4" +dependencies = [ + "alloy-consensus", + "alloy-consensus-any", + "alloy-eips", + "alloy-json-rpc", + "alloy-network-primitives", + "alloy-primitives", + "alloy-rpc-types-any", + "alloy-rpc-types-eth", + "alloy-serde", + "alloy-signer", + "alloy-sol-types", + "async-trait", + "auto_impl", + "futures-utils-wasm", + "serde", + "serde_json", + "thiserror 2.0.12", +] + +[[package]] +name = "alloy-network-primitives" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9081c099e798b8a2bba2145eb82a9a146f01fc7a35e9ab6e7b43305051f97550" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-primitives", + "alloy-serde", + "serde", +] + +[[package]] +name = "alloy-primitives" +version = "0.8.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c77490fe91a0ce933a1f219029521f20fc28c2c0ca95d53fa4da9c00b8d9d4e" +dependencies = [ + "alloy-rlp", + "bytes", + "cfg-if", + "const-hex", + "derive_more 2.0.1", + "foldhash", + "hashbrown 0.15.3", + "indexmap", + "itoa", + "k256", + "keccak-asm", + "paste", + "proptest", + "rand 0.8.5", + "ruint", + "rustc-hash", + "serde", + "sha3", + "tiny-keccak", +] + +[[package]] +name = "alloy-provider" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc2dfaddd9a30aa870a78a4e1316e3e115ec1e12e552cbc881310456b85c1f24" +dependencies = [ + "alloy-chains", + "alloy-consensus", + "alloy-eips", + "alloy-json-rpc", + "alloy-network", + "alloy-network-primitives", + "alloy-primitives", + "alloy-rpc-client", + "alloy-rpc-types-eth", + "alloy-transport", + "alloy-transport-http", + "async-stream", + "async-trait", + "auto_impl", + "dashmap", + "futures", + "futures-utils-wasm", + "lru", + "parking_lot", + "pin-project", + "reqwest", + "schnellru", + "serde", + "serde_json", + "thiserror 2.0.12", + "tokio", + "tracing", + "url", + "wasmtimer", +] + +[[package]] +name = "alloy-rlp" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6c1d995bff8d011f7cd6c81820d51825e6e06d6db73914c1630ecf544d83d6" +dependencies = [ + "alloy-rlp-derive", + "arrayvec", + "bytes", +] + +[[package]] +name = "alloy-rlp-derive" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a40e1ef334153322fd878d07e86af7a529bcb86b2439525920a88eba87bcf943" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "alloy-rpc-client" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "531137b283547d5b9a5cafc96b006c64ef76810c681d606f28be9781955293b6" +dependencies = [ + "alloy-json-rpc", + "alloy-primitives", + "alloy-transport", + "alloy-transport-http", + "futures", + "pin-project", + "reqwest", + "serde", + "serde_json", + "tokio", + "tokio-stream", + "tower", + "tracing", + "url", + "wasmtimer", +] + +[[package]] +name = "alloy-rpc-types" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3410a472ce26c457e9780f708ee6bd540b30f88f1f31fdab7a11d00bd6aa1aee" +dependencies = [ + "alloy-primitives", + "alloy-rpc-types-eth", + "alloy-serde", + "serde", +] + +[[package]] +name = "alloy-rpc-types-any" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed98e1af55a7d856bfa385f30f63d8d56be2513593655c904a8f4a7ec963aa3e" +dependencies = [ + "alloy-consensus-any", + "alloy-rpc-types-eth", + "alloy-serde", +] + +[[package]] +name = "alloy-rpc-types-eth" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8737d7a6e37ca7bba9c23e9495c6534caec6760eb24abc9d5ffbaaba147818e1" +dependencies = [ + "alloy-consensus", + "alloy-consensus-any", + "alloy-eips", + "alloy-network-primitives", + "alloy-primitives", + "alloy-rlp", + "alloy-serde", + "alloy-sol-types", + "derive_more 1.0.0", + "itertools 0.13.0", + "serde", + "serde_json", +] + +[[package]] +name = "alloy-serde" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5851bf8d5ad33014bd0c45153c603303e730acc8a209450a7ae6b4a12c2789e2" +dependencies = [ + "alloy-primitives", + "serde", + "serde_json", +] + +[[package]] +name = "alloy-signer" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e10ca565da6500cca015ba35ee424d59798f2e1b85bc0dd8f81dafd401f029a" +dependencies = [ + "alloy-primitives", + "async-trait", + "auto_impl", + "elliptic-curve", + "k256", + "thiserror 2.0.12", +] + +[[package]] +name = "alloy-sol-macro" +version = "0.8.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e10ae8e9a91d328ae954c22542415303919aabe976fe7a92eb06db1b68fd59f2" +dependencies = [ + "alloy-sol-macro-expander", + "alloy-sol-macro-input", + "proc-macro-error2", + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "alloy-sol-macro-expander" +version = "0.8.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83ad5da86c127751bc607c174d6c9fe9b85ef0889a9ca0c641735d77d4f98f26" +dependencies = [ + "alloy-sol-macro-input", + "const-hex", + "heck", + "indexmap", + "proc-macro-error2", + "proc-macro2", + "quote", + "syn 2.0.101", + "syn-solidity", + "tiny-keccak", +] + +[[package]] +name = "alloy-sol-macro-input" +version = "0.8.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3d30f0d3f9ba3b7686f3ff1de9ee312647aac705604417a2f40c604f409a9e" +dependencies = [ + "const-hex", + "dunce", + "heck", + "macro-string", + "proc-macro2", + "quote", + "syn 2.0.101", + "syn-solidity", +] + +[[package]] +name = "alloy-sol-type-parser" +version = "0.8.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d162f8524adfdfb0e4bd0505c734c985f3e2474eb022af32eef0d52a4f3935c" +dependencies = [ + "serde", + "winnow", +] + +[[package]] +name = "alloy-sol-types" +version = "0.8.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d43d5e60466a440230c07761aa67671d4719d46f43be8ea6e7ed334d8db4a9ab" +dependencies = [ + "alloy-json-abi", + "alloy-primitives", + "alloy-sol-macro", + "const-hex", + "serde", +] + +[[package]] +name = "alloy-transport" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "538a04a37221469cac0ce231b737fd174de2fdfcdd843bdd068cb39ed3e066ad" +dependencies = [ + "alloy-json-rpc", + "base64", + "futures-util", + "futures-utils-wasm", + "serde", + "serde_json", + "thiserror 2.0.12", + "tokio", + "tower", + "tracing", + "url", + "wasmtimer", +] + +[[package]] +name = "alloy-transport-http" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ed40eb1e1265b2911512f6aa1dcece9702d078f5a646730c45e39e2be00ac1c" +dependencies = [ + "alloy-json-rpc", + "alloy-transport", + "reqwest", + "serde_json", + "tower", + "tracing", + "url", +] + +[[package]] +name = "alloy-trie" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d95a94854e420f07e962f7807485856cde359ab99ab6413883e15235ad996e8b" +dependencies = [ + "alloy-primitives", + "alloy-rlp", + "arrayvec", + "derive_more 1.0.0", + "nybbles", + "serde", + "smallvec", + "tracing", +] + +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anyhow" +version = "1.0.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" + +[[package]] +name = "ark-ff" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b3235cc41ee7a12aaaf2c575a2ad7b46713a8a50bda2fc3b003a04845c05dd6" +dependencies = [ + "ark-ff-asm 0.3.0", + "ark-ff-macros 0.3.0", + "ark-serialize 0.3.0", + "ark-std 0.3.0", + "derivative", + "num-bigint", + "num-traits", + "paste", + "rustc_version 0.3.3", + "zeroize", +] + +[[package]] +name = "ark-ff" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" +dependencies = [ + "ark-ff-asm 0.4.2", + "ark-ff-macros 0.4.2", + "ark-serialize 0.4.2", + "ark-std 0.4.0", + "derivative", + "digest 0.10.7", + "itertools 0.10.5", + "num-bigint", + "num-traits", + "paste", + "rustc_version 0.4.1", + "zeroize", +] + +[[package]] +name = "ark-ff-asm" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db02d390bf6643fb404d3d22d31aee1c4bc4459600aef9113833d17e786c6e44" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-asm" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-macros" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fd794a08ccb318058009eefdf15bcaaaaf6f8161eb3345f907222bac38b20" +dependencies = [ + "num-bigint", + "num-traits", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-macros" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" +dependencies = [ + "num-bigint", + "num-traits", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-serialize" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d6c2b318ee6e10f8c2853e73a83adc0ccb88995aa978d8a3408d492ab2ee671" +dependencies = [ + "ark-std 0.3.0", + "digest 0.9.0", +] + +[[package]] +name = "ark-serialize" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" +dependencies = [ + "ark-std 0.4.0", + "digest 0.10.7", + "num-bigint", +] + +[[package]] +name = "ark-std" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1df2c09229cbc5a028b1d70e00fdb2acee28b1055dfb5ca73eea49c5a25c4e7c" +dependencies = [ + "num-traits", + "rand 0.8.5", +] + +[[package]] +name = "ark-std" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" +dependencies = [ + "num-traits", + "rand 0.8.5", +] + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" +dependencies = [ + "serde", +] + +[[package]] +name = "async-stream" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" +dependencies = [ + "async-stream-impl", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-stream-impl" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "async-trait" +version = "0.1.88" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "auto_impl" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffdcb70bdbc4d478427380519163274ac86e52916e10f0a8889adf0f96d3fee7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "autocfg" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[package]] +name = "backtrace" +version = "0.3.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-targets 0.52.6", +] + +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "base64ct" +version = "1.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89e25b6adfb930f02d1981565a6e5d9c547ac15a96606256d3b59040e5cd4ca3" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bit-set" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" + +[[package]] +name = "bitflags" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "blst" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47c79a94619fade3c0b887670333513a67ac28a6a7e653eb260bf0d4103db38d" +dependencies = [ + "cc", + "glob", + "threadpool", + "zeroize", +] + +[[package]] +name = "bumpalo" +version = "3.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" + +[[package]] +name = "byte-slice-cast" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7575182f7272186991736b70173b0ea045398f984bf5ebbb3804736ce1330c9d" + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" +dependencies = [ + "serde", +] + +[[package]] +name = "c-kzg" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0307f72feab3300336fb803a57134159f6e20139af1357f36c54cb90d8e8928" +dependencies = [ + "blst", + "cc", + "glob", + "hex", + "libc", + "once_cell", + "serde", +] + +[[package]] +name = "cc" +version = "1.2.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32db95edf998450acc7881c932f94cd9b05c87b4b2599e8bab064753da4acfd1" +dependencies = [ + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "wasm-bindgen", + "windows-link", +] + +[[package]] +name = "color-eyre" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e1761c0e16f8883bbbb8ce5990867f4f06bf11a0253da6495a04ce4b6ef0ec" +dependencies = [ + "backtrace", + "color-spantrace", + "eyre", + "indenter", + "once_cell", + "owo-colors", + "tracing-error", +] + +[[package]] +name = "color-spantrace" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ddd8d5bfda1e11a501d0a7303f3bfed9aa632ebdb859be40d0fd70478ed70d5" +dependencies = [ + "once_cell", + "owo-colors", + "tracing-core", + "tracing-error", +] + +[[package]] +name = "const-hex" +version = "1.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83e22e0ed40b96a48d3db274f72fd365bd78f67af39b6bbd47e8a15e1c6207ff" +dependencies = [ + "cfg-if", + "cpufeatures", + "hex", + "proptest", + "serde", +] + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "const_format" +version = "0.2.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "126f97965c8ad46d6d9163268ff28432e8f6a1196a55578867832e3049df63dd" +dependencies = [ + "const_format_proc_macros", +] + +[[package]] +name = "const_format_proc_macros" +version = "0.2.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d57c2eccfb16dbac1f4e61e206105db5820c9d26c3c472bc17c774259ef7744" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crunchy" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929" + +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "dashmap" +version = "6.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" +dependencies = [ + "cfg-if", + "crossbeam-utils", + "hashbrown 0.14.5", + "lock_api", + "once_cell", + "parking_lot_core", +] + +[[package]] +name = "der" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" +dependencies = [ + "const-oid", + "zeroize", +] + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "derive_more" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05" +dependencies = [ + "derive_more-impl 1.0.0", +] + +[[package]] +name = "derive_more" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678" +dependencies = [ + "derive_more-impl 2.0.1", +] + +[[package]] +name = "derive_more-impl" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", + "unicode-xid", +] + +[[package]] +name = "derive_more-impl" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", + "unicode-xid", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "const-oid", + "crypto-common", + "subtle", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der", + "digest 0.10.7", + "elliptic-curve", + "rfc6979", + "signature", + "spki", +] + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest 0.10.7", + "ff", + "generic-array", + "group", + "pkcs8", + "rand_core 0.6.4", + "sec1", + "subtle", + "zeroize", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] + +[[package]] +name = "eyre" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd915d99f24784cdc19fd37ef22b97e3ff0ae756c7e492e9fbfe897d61e2aec" +dependencies = [ + "indenter", + "once_cell", +] + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "fastrlp" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139834ddba373bbdd213dffe02c8d110508dcf1726c2be27e8d1f7d7e1856418" +dependencies = [ + "arrayvec", + "auto_impl", + "bytes", +] + +[[package]] +name = "fastrlp" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce8dba4714ef14b8274c371879b175aa55b16b30f269663f19d576f380018dc4" +dependencies = [ + "arrayvec", + "auto_impl", + "bytes", +] + +[[package]] +name = "ff" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" +dependencies = [ + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "fixed-hash" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" +dependencies = [ + "byteorder", + "rand 0.8.5", + "rustc-hex", + "static_assertions", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "futures" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-executor" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" + +[[package]] +name = "futures-macro" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "futures-sink" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" + +[[package]] +name = "futures-task" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" + +[[package]] +name = "futures-util" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "futures-utils-wasm" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42012b0f064e01aa58b545fe3727f90f7dd4020f4a3ea735b50344965f5a57e9" + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", + "zeroize", +] + +[[package]] +name = "getrandom" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasi 0.14.2+wasi-0.2.4", +] + +[[package]] +name = "gimli" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" + +[[package]] +name = "glob" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "ahash", +] + +[[package]] +name = "hashbrown" +version = "0.15.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash", + "serde", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +dependencies = [ + "serde", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "http" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "hyper" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "httparse", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-tls" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" +dependencies = [ + "bytes", + "http-body-util", + "hyper", + "hyper-util", + "native-tls", + "tokio", + "tokio-native-tls", + "tower-service", +] + +[[package]] +name = "hyper-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "497bbc33a26fdd4af9ed9c70d63f61cf56a938375fbb32df34db9b1cd6d643f2" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "hyper", + "libc", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", +] + +[[package]] +name = "hypermap-cacher" +version = "0.1.0" +dependencies = [ + "alloy", + "alloy-primitives", + "alloy-sol-types", + "anyhow", + "chrono", + "hex", + "hyperware_process_lib", + "process_macros", + "rand 0.8.5", + "rmp-serde", + "serde", + "serde_json", + "wit-bindgen", +] + +[[package]] +name = "hyperware_process_lib" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "414dd471dfac43943b314200b4943f38c4b08337103840e2192cfb5dc9b1bea5" +dependencies = [ + "alloy", + "alloy-primitives", + "alloy-sol-macro", + "alloy-sol-types", + "anyhow", + "base64", + "bincode", + "color-eyre", + "http", + "mime_guess", + "rand 0.8.5", + "regex", + "rmp-serde", + "serde", + "serde_json", + "thiserror 1.0.69", + "tracing", + "tracing-error", + "tracing-subscriber", + "url", + "wit-bindgen", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "icu_collections" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" +dependencies = [ + "displaydoc", + "potential_utf", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" + +[[package]] +name = "icu_properties" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2549ca8c7241c82f59c80ba2a6f415d931c5b58d24fb8412caa1a1f02c49139a" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "potential_utf", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8197e866e47b68f8f7d95249e172903bec06004b18b2937f1095d40a0c57de04" + +[[package]] +name = "icu_provider" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" +dependencies = [ + "displaydoc", + "icu_locale_core", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "id-arena" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005" + +[[package]] +name = "idna" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "impl-codec" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" +dependencies = [ + "parity-scale-codec", +] + +[[package]] +name = "impl-trait-for-tuples" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0eb5a3343abf848c0984fe4604b2b105da9539376e24fc0a3b0007411ae4fd9" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "indenter" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" + +[[package]] +name = "indexmap" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" +dependencies = [ + "equivalent", + "hashbrown 0.15.3", + "serde", +] + +[[package]] +name = "ipnet" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "js-sys" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "k256" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b" +dependencies = [ + "cfg-if", + "ecdsa", + "elliptic-curve", + "once_cell", + "sha2", +] + +[[package]] +name = "keccak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "keccak-asm" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "505d1856a39b200489082f90d897c3f07c455563880bc5952e38eabf731c83b6" +dependencies = [ + "digest 0.10.7", + "sha3-asm", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[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.172" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" + +[[package]] +name = "libm" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" + +[[package]] +name = "linux-raw-sys" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" + +[[package]] +name = "litemap" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" + +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" + +[[package]] +name = "lru" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" +dependencies = [ + "hashbrown 0.15.3", +] + +[[package]] +name = "macro-string" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b27834086c65ec3f9387b096d66e99f221cf081c2b738042aa252bcd41204e3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata 0.1.10", +] + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "mime_guess" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" +dependencies = [ + "mime", + "unicase", +] + +[[package]] +name = "miniz_oxide" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" +dependencies = [ + "adler2", +] + +[[package]] +name = "mio" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" +dependencies = [ + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys 0.52.0", +] + +[[package]] +name = "native-tls" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "num_enum" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" +dependencies = [ + "num_enum_derive", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "nybbles" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8983bb634df7248924ee0c4c3a749609b5abcb082c28fffe3254b3eb3602b307" +dependencies = [ + "alloy-rlp", + "const-hex", + "proptest", + "serde", + "smallvec", +] + +[[package]] +name = "object" +version = "0.36.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "openssl" +version = "0.10.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fedfea7d58a1f73118430a55da6a286e7b044961736ce96a16a17068ea25e5da" +dependencies = [ + "bitflags", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "openssl-probe" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" + +[[package]] +name = "openssl-sys" +version = "0.9.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e145e1651e858e820e4860f7b9c5e169bc1d8ce1c86043be79fa7b7634821847" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + +[[package]] +name = "owo-colors" +version = "4.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1036865bb9422d3300cf723f657c2851d0e9ab12567854b1f4eba3d77decf564" + +[[package]] +name = "parity-scale-codec" +version = "3.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9fde3d0718baf5bc92f577d652001da0f8d54cd03a7974e118d04fc888dc23d" +dependencies = [ + "arrayvec", + "bitvec", + "byte-slice-cast", + "const_format", + "impl-trait-for-tuples", + "parity-scale-codec-derive", + "rustversion", + "serde", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "3.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581c837bb6b9541ce7faa9377c20616e4fb7650f6b0f68bc93c827ee504fb7b3" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "parking_lot" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.52.6", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "pest" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "198db74531d58c70a361c42201efde7e2591e976d518caf7662a47dc5720e7b6" +dependencies = [ + "memchr", + "thiserror 2.0.12", + "ucd-trie", +] + +[[package]] +name = "pin-project" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "pkg-config" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + +[[package]] +name = "potential_utf" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" +dependencies = [ + "zerovec", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "prettyplease" +version = "0.2.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "664ec5419c51e34154eec046ebcba56312d5a2fc3b09a06da188e1ad21afadf6" +dependencies = [ + "proc-macro2", + "syn 2.0.101", +] + +[[package]] +name = "primitive-types" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" +dependencies = [ + "fixed-hash", + "impl-codec", + "uint", +] + +[[package]] +name = "proc-macro-crate" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edce586971a4dfaa28950c6f18ed55e0406c1ab88bbce2c6f6293a7aaba73d35" +dependencies = [ + "toml_edit", +] + +[[package]] +name = "proc-macro-error-attr2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "proc-macro-error2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" +dependencies = [ + "proc-macro-error-attr2", + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "proc-macro2" +version = "1.0.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "process_macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ecfcd7b51a1b9249fb47359a9f8d57a9e9dbc71857c5cfd08f98764f7106a3d" +dependencies = [ + "quote", + "syn 2.0.101", +] + +[[package]] +name = "proptest" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14cae93065090804185d3b75f0bf93b8eeda30c7a9b4a33d3bdb3988d6229e50" +dependencies = [ + "bit-set", + "bit-vec", + "bitflags", + "lazy_static", + "num-traits", + "rand 0.8.5", + "rand_chacha 0.3.1", + "rand_xorshift", + "regex-syntax 0.8.5", + "rusty-fork", + "tempfile", + "unarray", +] + +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", + "serde", +] + +[[package]] +name = "rand" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.3", +] + +[[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 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.3", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.16", +] + +[[package]] +name = "rand_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +dependencies = [ + "getrandom 0.3.3", +] + +[[package]] +name = "rand_xorshift" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" +dependencies = [ + "rand_core 0.6.4", +] + +[[package]] +name = "redox_syscall" +version = "0.5.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata 0.4.9", + "regex-syntax 0.8.5", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax 0.6.29", +] + +[[package]] +name = "regex-automata" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.8.5", +] + +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "reqwest" +version = "0.12.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d19c46a6fdd48bc4dab94b6103fccc55d34c67cc0ad04653aad4ea2a07cd7bbb" +dependencies = [ + "base64", + "bytes", + "futures-core", + "futures-util", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-tls", + "hyper-util", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls-pemfile", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tokio-native-tls", + "tower", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "windows-registry", +] + +[[package]] +name = "reset-cache" +version = "0.1.0" +dependencies = [ + "hyperware_process_lib", + "process_macros", + "serde", + "serde_json", + "wit-bindgen", +] + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + +[[package]] +name = "rlp" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" +dependencies = [ + "bytes", + "rustc-hex", +] + +[[package]] +name = "rmp" +version = "0.8.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "228ed7c16fa39782c3b3468e974aec2795e9089153cd08ee2e9aefb3613334c4" +dependencies = [ + "byteorder", + "num-traits", + "paste", +] + +[[package]] +name = "rmp-serde" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52e599a477cf9840e92f2cde9a7189e67b42c57532749bf90aea6ec10facd4db" +dependencies = [ + "byteorder", + "rmp", + "serde", +] + +[[package]] +name = "ruint" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78a46eb779843b2c4f21fac5773e25d6d5b7c8f0922876c91541790d2ca27eef" +dependencies = [ + "alloy-rlp", + "ark-ff 0.3.0", + "ark-ff 0.4.2", + "bytes", + "fastrlp 0.3.1", + "fastrlp 0.4.0", + "num-bigint", + "num-integer", + "num-traits", + "parity-scale-codec", + "primitive-types", + "proptest", + "rand 0.8.5", + "rand 0.9.1", + "rlp", + "ruint-macro", + "serde", + "valuable", + "zeroize", +] + +[[package]] +name = "ruint-macro" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48fd7bd8a6377e15ad9d42a8ec25371b94ddc67abe7c8b9127bec79bebaaae18" + +[[package]] +name = "rustc-demangle" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + +[[package]] +name = "rustc-hash" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" + +[[package]] +name = "rustc-hex" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" + +[[package]] +name = "rustc_version" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" +dependencies = [ + "semver 0.11.0", +] + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver 1.0.26", +] + +[[package]] +name = "rustix" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.59.0", +] + +[[package]] +name = "rustls-pemfile" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" +dependencies = [ + "zeroize", +] + +[[package]] +name = "rustversion" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" + +[[package]] +name = "rusty-fork" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f" +dependencies = [ + "fnv", + "quick-error", + "tempfile", + "wait-timeout", +] + +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + +[[package]] +name = "schannel" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "schnellru" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "356285bbf17bea63d9e52e96bd18f039672ac92b55b8cb997d6162a2a37d1649" +dependencies = [ + "ahash", + "cfg-if", + "hashbrown 0.13.2", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + +[[package]] +name = "security-framework" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "semver" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" + +[[package]] +name = "semver-parser" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9900206b54a3527fdc7b8a938bffd94a568bac4f4aa8113b209df75a09c0dec2" +dependencies = [ + "pest", +] + +[[package]] +name = "serde" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "serde_json" +version = "1.0.140" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "set-nodes" +version = "0.1.0" +dependencies = [ + "hyperware_process_lib", + "process_macros", + "serde", + "serde_json", + "wit-bindgen", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest 0.10.7", + "keccak", +] + +[[package]] +name = "sha3-asm" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28efc5e327c837aa837c59eae585fc250715ef939ac32881bcc11677cd02d46" +dependencies = [ + "cc", + "cfg-if", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest 0.10.7", + "rand_core 0.6.4", +] + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" +dependencies = [ + "serde", +] + +[[package]] +name = "socket2" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f5fd57c80058a56cf5c777ab8a126398ece8e442983605d280a44ce79d0edef" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "spdx" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58b69356da67e2fc1f542c71ea7e654a361a79c938e4424392ecf4fa065d2193" +dependencies = [ + "smallvec", +] + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "start-providing" +version = "0.1.0" +dependencies = [ + "hyperware_process_lib", + "process_macros", + "serde", + "serde_json", + "wit-bindgen", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "stop-providing" +version = "0.1.0" +dependencies = [ + "hyperware_process_lib", + "process_macros", + "serde", + "serde_json", + "wit-bindgen", +] + +[[package]] +name = "strum" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f64def088c51c9510a8579e3c5d67c65349dcf755e5479ad3d010aa6454e2c32" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c77a8c5abcaf0f9ce05d62342b7d298c346515365c36b673df4ebe3ced01fde8" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.101", +] + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn-solidity" +version = "0.8.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4560533fbd6914b94a8fb5cc803ed6801c3455668db3b810702c57612bac9412" +dependencies = [ + "paste", + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "tempfile" +version = "3.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1" +dependencies = [ + "fastrand", + "getrandom 0.3.3", + "once_cell", + "rustix", + "windows-sys 0.59.0", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +dependencies = [ + "thiserror-impl 2.0.12", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "thread_local" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +dependencies = [ + "cfg-if", + "once_cell", +] + +[[package]] +name = "threadpool" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" +dependencies = [ + "num_cpus", +] + +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + +[[package]] +name = "tinystr" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tokio" +version = "1.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2513ca694ef9ede0fb23fe71a4ee4107cb102b9dc1930f6d0fd77aae068ae165" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "pin-project-lite", + "socket2", + "tokio-macros", + "windows-sys 0.52.0", +] + +[[package]] +name = "tokio-macros" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-stream" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", + "tokio-util", +] + +[[package]] +name = "tokio-util" +version = "0.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66a539a9ad6d5d281510d5bd368c973d636c02dbf8a67300bfb6b950696ad7df" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "toml_datetime" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3da5db5a963e24bc68be8b17b6fa82814bb22ee8660f192bb182771d498f09a3" + +[[package]] +name = "toml_edit" +version = "0.22.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "310068873db2c5b3e7659d2cc35d21855dbafa50d1ce336397c666e3cb08137e" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow", +] + +[[package]] +name = "tower" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper", + "tokio", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "tracing-core" +version = "0.1.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-error" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b1581020d7a273442f5b45074a6a57d5757ad0a47dac0e9f0bd57b81936f3db" +dependencies = [ + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-serde" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "704b1aeb7be0d0a84fc9828cae51dab5970fee5088f83d1dd7ee6f6246fc6ff1" +dependencies = [ + "serde", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex", + "serde", + "serde_json", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", + "tracing-serde", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "typenum" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" + +[[package]] +name = "ucd-trie" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" + +[[package]] +name = "uint" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" +dependencies = [ + "byteorder", + "crunchy", + "hex", + "static_assertions", +] + +[[package]] +name = "unarray" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" + +[[package]] +name = "unicase" +version = "2.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" + +[[package]] +name = "unicode-ident" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "url" +version = "2.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "wait-timeout" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ac3b126d3914f9849036f826e054cbabdc8519970b8998ddaf3b5bd3c65f11" +dependencies = [ + "libc", +] + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasi" +version = "0.14.2+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +dependencies = [ + "wit-bindgen-rt 0.39.0", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" +dependencies = [ + "bumpalo", + "log", + "proc-macro2", + "quote", + "syn 2.0.101", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" +dependencies = [ + "cfg-if", + "js-sys", + "once_cell", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "wasm-encoder" +version = "0.220.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e913f9242315ca39eff82aee0e19ee7a372155717ff0eb082c741e435ce25ed1" +dependencies = [ + "leb128", + "wasmparser", +] + +[[package]] +name = "wasm-metadata" +version = "0.220.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "185dfcd27fa5db2e6a23906b54c28199935f71d9a27a1a27b3a88d6fee2afae7" +dependencies = [ + "anyhow", + "indexmap", + "serde", + "serde_derive", + "serde_json", + "spdx", + "wasm-encoder", + "wasmparser", +] + +[[package]] +name = "wasmparser" +version = "0.220.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d07b6a3b550fefa1a914b6d54fc175dd11c3392da11eee604e6ffc759805d25" +dependencies = [ + "ahash", + "bitflags", + "hashbrown 0.14.5", + "indexmap", + "semver 1.0.26", +] + +[[package]] +name = "wasmtimer" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0048ad49a55b9deb3953841fa1fc5858f0efbcb7a18868c899a360269fac1b23" +dependencies = [ + "futures", + "js-sys", + "parking_lot", + "pin-utils", + "slab", + "wasm-bindgen", +] + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-core" +version = "0.61.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46ec44dc15085cea82cf9c78f85a9114c463a369786585ad2882d1ff0b0acf40" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings 0.4.1", +] + +[[package]] +name = "windows-implement" +version = "0.60.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "windows-interface" +version = "0.59.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "windows-link" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" + +[[package]] +name = "windows-registry" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4286ad90ddb45071efd1a66dfa43eb02dd0dfbae1545ad6cc3c51cf34d7e8ba3" +dependencies = [ + "windows-result", + "windows-strings 0.3.1", + "windows-targets 0.53.0", +] + +[[package]] +name = "windows-result" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b895b5356fc36103d0f64dd1e94dfa7ac5633f1c9dd6e80fe9ec4adef69e09d" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a7ab927b2637c19b3dbe0965e75d8f2d30bdd697a1516191cad2ec4df8fb28a" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b" +dependencies = [ + "windows_aarch64_gnullvm 0.53.0", + "windows_aarch64_msvc 0.53.0", + "windows_i686_gnu 0.53.0", + "windows_i686_gnullvm 0.53.0", + "windows_i686_msvc 0.53.0", + "windows_x86_64_gnu 0.53.0", + "windows_x86_64_gnullvm 0.53.0", + "windows_x86_64_msvc 0.53.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_i686_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" + +[[package]] +name = "winnow" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06928c8748d81b05c9be96aad92e1b6ff01833332f281e8cfca3be4b35fc9ec" +dependencies = [ + "memchr", +] + +[[package]] +name = "wit-bindgen" +version = "0.36.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a2b3e15cd6068f233926e7d8c7c588b2ec4fb7cc7bf3824115e7c7e2a8485a3" +dependencies = [ + "wit-bindgen-rt 0.36.0", + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen-core" +version = "0.36.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b632a5a0fa2409489bd49c9e6d99fcc61bb3d4ce9d1907d44662e75a28c71172" +dependencies = [ + "anyhow", + "heck", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rt" +version = "0.36.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7947d0131c7c9da3f01dfde0ab8bd4c4cf3c5bd49b6dba0ae640f1fa752572ea" +dependencies = [ + "bitflags", +] + +[[package]] +name = "wit-bindgen-rt" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" +dependencies = [ + "bitflags", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.36.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4329de4186ee30e2ef30a0533f9b3c123c019a237a7c82d692807bf1b3ee2697" +dependencies = [ + "anyhow", + "heck", + "indexmap", + "prettyplease", + "syn 2.0.101", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.36.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "177fb7ee1484d113b4792cc480b1ba57664bbc951b42a4beebe573502135b1fc" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn 2.0.101", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.220.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b505603761ed400c90ed30261f44a768317348e49f1864e82ecdc3b2744e5627" +dependencies = [ + "anyhow", + "bitflags", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.220.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae2a7999ed18efe59be8de2db9cb2b7f84d88b27818c79353dfc53131840fe1a" +dependencies = [ + "anyhow", + "id-arena", + "indexmap", + "log", + "semver 1.0.26", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", +] + +[[package]] +name = "writeable" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[package]] +name = "yoke" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", + "synstructure", +] + +[[package]] +name = "zerocopy" +version = "0.8.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", + "synstructure", +] + +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "zerotrie" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] diff --git a/hyperdrive/packages/hypermap-cacher/Cargo.toml b/hyperdrive/packages/hypermap-cacher/Cargo.toml new file mode 100644 index 000000000..ff6b64639 --- /dev/null +++ b/hyperdrive/packages/hypermap-cacher/Cargo.toml @@ -0,0 +1,14 @@ +[workspace] +resolver = "2" +members = [ + "hypermap-cacher", + "reset-cache", + "set-nodes", + "start-providing", + "stop-providing" +] + +[profile.release] +panic = "abort" +opt-level = "s" +lto = true diff --git a/hyperdrive/packages/hypermap-cacher/api/hypermap-cacher:sys-v0.wit b/hyperdrive/packages/hypermap-cacher/api/hypermap-cacher:sys-v0.wit new file mode 100644 index 000000000..21a3652ae --- /dev/null +++ b/hyperdrive/packages/hypermap-cacher/api/hypermap-cacher:sys-v0.wit @@ -0,0 +1,83 @@ +interface hypermap-cacher { + // Metadata associated with a batch of Ethereum logs. + record logs-metadata { + chain-id: string, + from-block: string, + to-block: string, + time-created: string, + created-by: string, + signature: string, + } + + // Represents an item in the manifest, detailing a single log cache file. + record manifest-item { + metadata: logs-metadata, + is-empty: bool, + file-hash: string, + file-name: string, + } + + // The main manifest structure, listing all available log cache files. + // WIT does not support direct map types, so a list of key-value tuples is used. + record manifest { + // The key is the filename of the log cache. + items: list>, + manifest-filename: string, + chain-id: string, + protocol-version: string, + } + + record get-logs-by-range-request { + from-block: u64, + to-block: option, // If None, signifies to the latest available/relevant cached block. + } + + variant get-logs-by-range-ok-response { + logs(tuple), + latest(u64), + } + + // Defines the types of requests that can be sent to the Hypermap Cacher process. + variant cacher-request { + get-manifest, + get-log-cache-content(string), + get-status, + get-logs-by-range(get-logs-by-range-request), + start-providing, + stop-providing, + set-nodes(list), + reset(option>), + } + + // Represents the operational status of the cacher. + record cacher-status { + last-cached-block: u64, + chain-id: string, + protocol-version: string, + next-cache-attempt-in-seconds: option, + manifest-filename: string, + log-files-count: u32, + our-address: string, + is-providing: bool, + } + + // Defines the types of responses the Hypermap Cacher process can send. + variant cacher-response { + get-manifest(option), + get-log-cache-content(result, string>), + get-status(cacher-status), + get-logs-by-range(result), + start-providing(result), + stop-providing(result), + set-nodes(result), + reset(result), + rejected, + is-starting, + } +} + +world hypermap-cacher-sys-v0 { + import sign; + import hypermap-cacher; + include process-v1; +} diff --git a/hyperdrive/packages/hypermap-cacher/hypermap-cacher/Cargo.toml b/hyperdrive/packages/hypermap-cacher/hypermap-cacher/Cargo.toml new file mode 100644 index 000000000..10c3c7bad --- /dev/null +++ b/hyperdrive/packages/hypermap-cacher/hypermap-cacher/Cargo.toml @@ -0,0 +1,30 @@ +[package] +name = "hypermap-cacher" +version = "0.1.0" +edition = "2021" +publish = false + +[dependencies] +anyhow = "1.0" +alloy-primitives = "0.8.15" +alloy-sol-types = "0.8.15" +alloy = { version = "0.8.1", features = [ + "json-rpc", + "rpc-client", + "rpc-types", +] } +chrono = "0.4.41" +hex = "0.4.3" +hyperware_process_lib = { version = "1.2.0", features = ["logging"] } +process_macros = "0.1.0" +rand = "0.8" +rmp-serde = "1.1.2" +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +wit-bindgen = "0.36.0" + +[lib] +crate-type = ["cdylib"] + +[package.metadata.component] +package = "hyperware:process" diff --git a/hyperdrive/packages/hypermap-cacher/hypermap-cacher/src/lib.rs b/hyperdrive/packages/hypermap-cacher/hypermap-cacher/src/lib.rs new file mode 100644 index 000000000..ac9985c3a --- /dev/null +++ b/hyperdrive/packages/hypermap-cacher/hypermap-cacher/src/lib.rs @@ -0,0 +1,1310 @@ +use std::{ + cmp::{max, min}, + collections::HashMap, + str::FromStr, +}; + +use alloy::hex; +use alloy_primitives::keccak256; +use rand::seq::SliceRandom; +use rand::thread_rng; +use serde::{Deserialize, Serialize}; + +use crate::hyperware::process::hypermap_cacher::{ + CacherRequest, CacherResponse, CacherStatus, GetLogsByRangeOkResponse, GetLogsByRangeRequest, + LogsMetadata as WitLogsMetadata, Manifest as WitManifest, ManifestItem as WitManifestItem, +}; + +use hyperware_process_lib::{ + await_message, call_init, eth, get_state, http, hypermap, + logging::{debug, error, info, init_logging, warn, Level}, + net::{NetAction, NetResponse}, + our, set_state, sign, timer, vfs, Address, ProcessId, Request, Response, +}; + +wit_bindgen::generate!({ + path: "target/wit", + world: "hypermap-cacher-sys-v0", + generate_unused_types: true, + additional_derives: [serde::Deserialize, serde::Serialize, process_macros::SerdeJsonInto], +}); + +const PROTOCOL_VERSION: &str = "0"; +const DEFAULT_BLOCK_BATCH_SIZE: u64 = 500; +const DEFAULT_CACHE_INTERVAL_S: u64 = 2 * 500; // 500 blocks, 2s / block = 1000s; +const MAX_LOG_RETRIES: u8 = 3; +const RETRY_DELAY_S: u64 = 10; +const LOG_ITERATION_DELAY_MS: u64 = 200; + +const DEFAULT_NODES: &[&str] = &["nick.hypr", "nick1udwig.os"]; + +// Internal representation of LogsMetadata, similar to WIT but for Rust logic. +#[derive(Serialize, Deserialize, Debug, Clone)] +struct LogsMetadataInternal { + #[serde(rename = "chainId")] + chain_id: String, + #[serde(rename = "fromBlock")] + from_block: String, + #[serde(rename = "toBlock")] + to_block: String, + #[serde(rename = "timeCreated")] + time_created: String, + #[serde(rename = "createdBy")] + created_by: String, + signature: String, // Keccak256 hash of the log file content. +} + +// Internal representation of a LogCache, containing metadata and actual logs. +#[derive(Serialize, Deserialize, Debug, Clone)] +struct LogCacheInternal { + metadata: LogsMetadataInternal, + logs: Vec, // The actual Ethereum logs. +} + +// Internal representation of a ManifestItem. +#[derive(Serialize, Deserialize, Debug, Clone)] +struct ManifestItemInternal { + metadata: LogsMetadataInternal, + #[serde(rename = "isEmpty")] + is_empty: bool, + #[serde(rename = "fileHash")] + file_hash: String, + #[serde(rename = "fileName")] + file_name: String, +} + +// Internal representation of the Manifest. +#[derive(Serialize, Deserialize, Debug, Clone, Default)] +struct ManifestInternal { + items: HashMap, + manifest_filename: String, + chain_id: String, + protocol_version: String, +} + +// The main state structure for the Hypermap Cacher process. +#[derive(Serialize, Deserialize, Debug)] +struct State { + hypermap_address: eth::Address, + manifest: ManifestInternal, + last_cached_block: u64, + chain_id: String, + protocol_version: String, + cache_interval_s: u64, + block_batch_size: u64, + is_cache_timer_live: bool, + drive_path: String, + is_providing: bool, + nodes: Vec, + #[serde(skip)] + is_starting: bool, +} + +// Generates a timestamp string. +fn get_current_timestamp_str() -> String { + let datetime = chrono::Utc::now(); + datetime.format("%Y%m%dT%H%M%SZ").to_string() +} + +fn is_local_request(our: &Address, source: &Address) -> bool { + our.node == source.node +} + +impl State { + fn new(drive_path: &str) -> Self { + let chain_id = hypermap::HYPERMAP_CHAIN_ID.to_string(); + let hypermap_address = eth::Address::from_str(hypermap::HYPERMAP_ADDRESS) + .expect("Failed to parse HYPERMAP_ADDRESS"); + + let manifest_filename = format!( + "manifest-chain{}-protocol{}.json", + chain_id, PROTOCOL_VERSION + ); + let initial_manifest = ManifestInternal { + items: HashMap::new(), + manifest_filename: manifest_filename.clone(), + chain_id: chain_id.clone(), + protocol_version: PROTOCOL_VERSION.to_string(), + }; + + State { + hypermap_address, + manifest: initial_manifest, + last_cached_block: hypermap::HYPERMAP_FIRST_BLOCK, + chain_id, + protocol_version: PROTOCOL_VERSION.to_string(), + cache_interval_s: DEFAULT_CACHE_INTERVAL_S, + block_batch_size: DEFAULT_BLOCK_BATCH_SIZE, + is_cache_timer_live: false, + drive_path: drive_path.to_string(), + is_providing: false, + nodes: DEFAULT_NODES.iter().map(|s| s.to_string()).collect(), + is_starting: true, + } + } + + fn load(drive_path: &str) -> Self { + match get_state() { + Some(state_bytes) => match serde_json::from_slice::(&state_bytes) { + Ok(mut loaded_state) => { + info!("Successfully loaded state from checkpoint."); + // Always start in starting mode to bootstrap from other nodes + // is_starting is not serialized, so it defaults to false and we set it to true + loaded_state.is_starting = true; + loaded_state.drive_path = drive_path.to_string(); + + // Validate state against manifest file on disk + if let Err(e) = loaded_state.validate_state_against_manifest() { + warn!("State validation failed: {:?}. Clearing drive and creating fresh state.", e); + if let Err(clear_err) = loaded_state.clear_drive() { + error!("Failed to clear drive: {:?}", clear_err); + } + return Self::new(drive_path); + } + + loaded_state + } + Err(e) => { + warn!( + "Failed to deserialize saved state: {:?}. Creating new state.", + e + ); + Self::new(drive_path) + } + }, + None => { + info!("No saved state found. Creating new state."); + Self::new(drive_path) + } + } + } + + fn save(&self) { + match serde_json::to_vec(self) { + Ok(state_bytes) => set_state(&state_bytes), + Err(e) => error!("Fatal: Failed to serialize state for saving: {:?}", e), + } + info!( + "State checkpoint saved. Last cached block: {}", + self.last_cached_block + ); + } + + // Core logic for fetching logs, creating cache files, and updating the manifest. + fn cache_logs_and_update_manifest( + &mut self, + hypermap: &hypermap::Hypermap, + ) -> anyhow::Result<()> { + let current_chain_head = match hypermap.provider.get_block_number() { + Ok(block_num) => block_num, + Err(e) => { + error!( + "Failed to get current block number: {:?}. Skipping cycle.", + e + ); + return Err(anyhow::anyhow!("Failed to get block number: {:?}", e)); + } + }; + + if self.last_cached_block >= current_chain_head { + info!( + "Already caught up to chain head ({}). Nothing to cache.", + current_chain_head + ); + return Ok(()); + } + + while self.last_cached_block != current_chain_head { + self.cache_logs_and_update_manifest_step(hypermap, Some(current_chain_head))?; + + std::thread::sleep(std::time::Duration::from_millis(LOG_ITERATION_DELAY_MS)); + } + + Ok(()) + } + + fn cache_logs_and_update_manifest_step( + &mut self, + hypermap: &hypermap::Hypermap, + to_block: Option, + ) -> anyhow::Result<()> { + info!( + "Starting caching cycle. From block: {}", + self.last_cached_block + 1 + ); + + let current_chain_head = match to_block { + Some(b) => b, + None => match hypermap.provider.get_block_number() { + Ok(block_num) => block_num, + Err(e) => { + error!( + "Failed to get current block number: {:?}. Skipping cycle.", + e + ); + return Err(anyhow::anyhow!("Failed to get block number: {:?}", e)); + } + }, + }; + + if self.last_cached_block >= current_chain_head { + info!( + "Already caught up to chain head ({}). Nothing to cache.", + current_chain_head + ); + return Ok(()); + } + + let from_block = self.last_cached_block + 1; + let mut to_block = from_block + self.block_batch_size - 1; + if to_block > current_chain_head { + to_block = current_chain_head; + } + + if from_block > to_block { + info!("From_block {} is greater than to_block {}. Chain might not have advanced enough. Skipping.", from_block, to_block); + return Ok(()); + } + + let filter = eth::Filter::new() + .address(self.hypermap_address) + .from_block(from_block) + .to_block(eth::BlockNumberOrTag::Number(to_block)); + + let logs = { + let mut attempt = 0; + loop { + match hypermap.provider.get_logs(&filter) { + Ok(logs) => break logs, + Err(e) => { + attempt += 1; + if attempt >= MAX_LOG_RETRIES { + error!( + "Failed to get logs after {} retries: {:?}", + MAX_LOG_RETRIES, e + ); + return Err(anyhow::anyhow!("Failed to get logs: {:?}", e)); + } + warn!( + "Error getting logs (attempt {}/{}): {:?}. Retrying in {}s...", + attempt, MAX_LOG_RETRIES, e, RETRY_DELAY_S + ); + std::thread::sleep(std::time::Duration::from_secs(RETRY_DELAY_S)); + } + } + } + }; + + info!( + "Fetched {} logs from block {} to {}.", + logs.len(), + from_block, + to_block + ); + + let our = our(); + + let metadata = LogsMetadataInternal { + chain_id: self.chain_id.clone(), + from_block: from_block.to_string(), + to_block: to_block.to_string(), + time_created: get_current_timestamp_str(), + created_by: our.to_string(), + signature: "".to_string(), + }; + + let mut log_cache = LogCacheInternal { + metadata, + logs: logs.clone(), + }; + + let mut logs_bytes_for_sig = serde_json::to_vec(&log_cache.logs).unwrap_or_default(); + logs_bytes_for_sig.extend_from_slice(&from_block.to_be_bytes()); + logs_bytes_for_sig.extend_from_slice(&to_block.to_be_bytes()); + let logs_hash_for_sig = keccak256(&logs_bytes_for_sig); + + let signature = sign::net_key_sign(logs_hash_for_sig.to_vec())?; + + log_cache.metadata.signature = format!("0x{}", hex::encode(signature)); + + // Final serialization of LogCacheInternal with the signature. + let final_log_cache_bytes = match serde_json::to_vec(&log_cache) { + Ok(bytes) => bytes, + Err(e) => { + error!( + "Failed to re-serialize LogCacheInternal with signature: {:?}", + e + ); + return Err(e.into()); + } + }; + + let file_hash_for_manifest = + format!("0x{}", hex::encode(keccak256(&final_log_cache_bytes))); + + let log_cache_filename = format!( + "{}-chain{}-from{}-to{}-protocol{}.json", + log_cache + .metadata + .time_created + .replace(":", "") + .replace("-", ""), // Make timestamp filename-safe + self.chain_id, + from_block, + to_block, + self.protocol_version + ); + + if !logs.is_empty() { + let log_cache_path = format!("{}/{}", self.drive_path, log_cache_filename); + let mut log_cache_file = vfs::open_file(&log_cache_path, true, None)?; + + if let Err(e) = log_cache_file.write_all(&final_log_cache_bytes) { + error!("Failed to write log cache file {}: {:?}", log_cache_path, e); + return Err(e.into()); + } + info!("Successfully wrote log cache file: {}", log_cache_path); + } + + let manifest_item = ManifestItemInternal { + metadata: log_cache.metadata.clone(), + is_empty: logs.is_empty(), + file_hash: file_hash_for_manifest, + file_name: if logs.is_empty() { + "".to_string() + } else { + log_cache_filename.clone() + }, + }; + self.manifest + .items + .insert(log_cache_filename.clone(), manifest_item); + self.manifest.chain_id = self.chain_id.clone(); + self.manifest.protocol_version = self.protocol_version.clone(); + + let manifest_bytes = match serde_json::to_vec(&self.manifest) { + Ok(bytes) => bytes, + Err(e) => { + error!("Failed to serialize manifest: {:?}", e); + return Err(e.into()); + } + }; + + let manifest_path = format!("{}/{}", self.drive_path, self.manifest.manifest_filename); + let manifest_file = vfs::open_file(&manifest_path, true, None)?; + + if let Err(e) = manifest_file.write(&manifest_bytes) { + error!("Failed to write manifest file {}: {:?}", manifest_path, e); + return Err(e.into()); + } + info!( + "Successfully updated and wrote manifest file: {}", + manifest_path + ); + + self.last_cached_block = to_block; + self.save(); + + Ok(()) + } + + // Validate that the in-memory state matches the manifest file on disk + fn validate_state_against_manifest(&self) -> anyhow::Result<()> { + let manifest_path = format!("{}/{}", self.drive_path, self.manifest.manifest_filename); + + // Check if manifest file exists + match vfs::open_file(&manifest_path, false, None) { + Ok(manifest_file) => { + match manifest_file.read() { + Ok(disk_manifest_bytes) => { + match serde_json::from_slice::(&disk_manifest_bytes) { + Ok(disk_manifest) => { + // Compare key aspects of the manifests + if self.manifest.chain_id != disk_manifest.chain_id { + return Err(anyhow::anyhow!( + "Chain ID mismatch: state has {}, disk has {}", + self.manifest.chain_id, + disk_manifest.chain_id + )); + } + + if self.manifest.protocol_version != disk_manifest.protocol_version + { + return Err(anyhow::anyhow!( + "Protocol version mismatch: state has {}, disk has {}", + self.manifest.protocol_version, + disk_manifest.protocol_version + )); + } + + // Check if all files mentioned in state manifest exist on disk + for (_filename, item) in &self.manifest.items { + if !item.file_name.is_empty() { + let file_path = + format!("{}/{}", self.drive_path, item.file_name); + if vfs::metadata(&file_path, None).is_err() { + return Err(anyhow::anyhow!( + "File {} mentioned in state manifest does not exist on disk", + item.file_name + )); + } + } + } + + // Check if disk manifest has more recent data than our state + let disk_max_block = disk_manifest + .items + .values() + .filter_map(|item| item.metadata.to_block.parse::().ok()) + .max() + .unwrap_or(0); + + let state_max_block = self + .manifest + .items + .values() + .filter_map(|item| item.metadata.to_block.parse::().ok()) + .max() + .unwrap_or(0); + + if disk_max_block > state_max_block { + return Err(anyhow::anyhow!( + "Disk manifest has more recent data (block {}) than state (block {})", + disk_max_block, state_max_block + )); + } + + info!("State validation passed - state matches manifest file"); + Ok(()) + } + Err(e) => { + Err(anyhow::anyhow!("Failed to parse manifest file: {:?}", e)) + } + } + } + Err(e) => Err(anyhow::anyhow!("Failed to read manifest file: {:?}", e)), + } + } + Err(_) => { + // Manifest file doesn't exist - this is okay for new installs + if self.manifest.items.is_empty() { + info!("No manifest file found, but state is also empty - validation passed"); + Ok(()) + } else { + Err(anyhow::anyhow!( + "State has manifest items but no manifest file exists on disk" + )) + } + } + } + } + + // Clear all files from the drive + fn clear_drive(&self) -> anyhow::Result<()> { + info!("Clearing all files from drive: {}", self.drive_path); + + // Remove the manifest file + let manifest_path = format!("{}/{}", self.drive_path, self.manifest.manifest_filename); + match vfs::remove_file(&manifest_path, None) { + Ok(_) => info!("Removed manifest file: {}", manifest_path), + Err(e) => warn!("Failed to remove manifest file {}: {:?}", manifest_path, e), + } + + // Remove all files mentioned in the manifest + for (_, item) in &self.manifest.items { + if !item.file_name.is_empty() { + let file_path = format!("{}/{}", self.drive_path, item.file_name); + match vfs::remove_file(&file_path, None) { + Ok(_) => info!("Removed cache file: {}", file_path), + Err(e) => warn!("Failed to remove cache file {}: {:?}", file_path, e), + } + } + } + + info!("Drive clearing completed"); + Ok(()) + } + + // Bootstrap state from other nodes, then fallback to RPC + fn bootstrap_state(&mut self, hypermap: &hypermap::Hypermap) -> anyhow::Result<()> { + info!("Starting state bootstrap process..."); + + // Try to bootstrap from other nodes first + if let Ok(()) = self.try_bootstrap_from_nodes() { + info!("Successfully bootstrapped from other nodes"); + } + + self.try_bootstrap_from_rpc(hypermap)?; + + // Mark as no longer starting + self.is_starting = false; + self.save(); + info!("Bootstrap process completed, cacher is now ready"); + Ok(()) + } + + // Try to bootstrap from other hypermap-cacher nodes + fn try_bootstrap_from_nodes(&mut self) -> anyhow::Result<()> { + if self.nodes.is_empty() { + info!("No nodes configured for bootstrap, will fallback to RPC"); + return Err(anyhow::anyhow!("No nodes configured for bootstrap")); + } + + info!("Attempting to bootstrap from {} nodes", self.nodes.len()); + + let mut nodes = self.nodes.clone(); + + // If using default nodes, shuffle them for random order + let default_nodes: Vec = DEFAULT_NODES.iter().map(|s| s.to_string()).collect(); + if nodes == default_nodes { + nodes.shuffle(&mut thread_rng()); + } + + let mut nodes_not_yet_in_net = nodes.clone(); + let num_retries = 10; + for _ in 0..num_retries { + nodes_not_yet_in_net.retain(|node| { + let Ok(Ok(response)) = Request::new() + .target(("our", "net", "distro", "sys")) + .body(rmp_serde::to_vec(&NetAction::GetPeer(node.clone())).unwrap()) + .send_and_await_response(1) + else { + return true; // keep the node + }; + + !matches!( + rmp_serde::from_slice::(response.body()), + Ok(NetResponse::Peer(Some(_))), + ) + }); + if nodes_not_yet_in_net.is_empty() { + break; + } + std::thread::sleep(std::time::Duration::from_secs(1)); + } + if !nodes_not_yet_in_net.is_empty() { + error!("failed to get peering info for {nodes_not_yet_in_net:?}"); + } + + for node in nodes { + info!("Requesting logs from node: {}", node); + + let cacher_process_address = + Address::new(&node, ("hypermap-cacher", "hypermap-cacher", "sys")); + + if cacher_process_address == our() { + continue; + } + + // ping node for quicker failure if not online/providing/... + let Ok(Ok(response)) = Request::to(cacher_process_address.clone()) + .body(CacherRequest::GetStatus) + .send_and_await_response(3) + else { + warn!("Node {node} failed to respond to ping; trying next one..."); + continue; + }; + let Ok(CacherResponse::GetStatus(_)) = response.body().try_into() else { + warn!("Node {node} failed to respond to ping with expected GetStatus; trying next one..."); + continue; + }; + + // get the logs + let get_logs_request = GetLogsByRangeRequest { + from_block: self.last_cached_block + 1, + to_block: None, // Get all available logs + }; + + match Request::to(cacher_process_address.clone()) + .body(CacherRequest::GetLogsByRange(get_logs_request)) + .send_and_await_response(15) + { + Ok(Ok(response_msg)) => match response_msg.body().try_into() { + Ok(CacherResponse::GetLogsByRange(Ok(get_logs))) => { + match get_logs { + GetLogsByRangeOkResponse::Logs((block, json_string)) => { + if let Ok(log_caches) = + serde_json::from_str::>(&json_string) + { + self.process_received_log_caches(log_caches)?; + } + if block > self.last_cached_block { + self.last_cached_block = block; + } + } + GetLogsByRangeOkResponse::Latest(block) => { + if block > self.last_cached_block { + self.last_cached_block = block; + } + } + } + return Ok(()); + } + Ok(CacherResponse::GetLogsByRange(Err(e))) => { + warn!("Node {} returned error: {}", cacher_process_address, e); + } + Ok(CacherResponse::IsStarting) => { + info!( + "Node {} is still starting, trying next node", + cacher_process_address + ); + } + Ok(CacherResponse::Rejected) => { + warn!("Node {} rejected our request", cacher_process_address); + } + Ok(_) => { + warn!( + "Node {} returned unexpected response type", + cacher_process_address + ); + } + Err(e) => { + warn!( + "Failed to parse response from {}: {:?}", + cacher_process_address, e + ); + } + }, + Ok(Err(e)) => { + warn!("Error response from {}: {:?}", cacher_process_address, e); + } + Err(e) => { + warn!( + "Failed to send request to {}: {:?}", + cacher_process_address, e + ); + } + } + } + + Err(anyhow::anyhow!("Failed to bootstrap from any node")) + } + + // Process received log caches and write them to VFS + fn process_received_log_caches( + &mut self, + log_caches: Vec, + ) -> anyhow::Result<()> { + info!("Processing {} received log caches", log_caches.len()); + + for log_cache in log_caches { + // Validate the log cache signature + if !self.validate_log_cache(&log_cache)? { + warn!("Invalid log cache signature, skipping"); + continue; + } + + // Generate filename from metadata + let filename = format!( + "{}-chain{}-from{}-to{}-protocol{}.json", + log_cache + .metadata + .time_created + .replace(":", "") + .replace("-", ""), + log_cache.metadata.chain_id, + log_cache.metadata.from_block, + log_cache.metadata.to_block, + PROTOCOL_VERSION + ); + + // Write log cache to VFS + let file_path = format!("{}/{}", self.drive_path, filename); + let log_cache_bytes = serde_json::to_vec(&log_cache)?; + + let mut file = vfs::open_file(&file_path, true, None)?; + file.write_all(&log_cache_bytes)?; + + info!("Wrote log cache file: {}", file_path); + + // Update manifest + let file_hash = format!("0x{}", hex::encode(keccak256(&log_cache_bytes))); + let manifest_item = ManifestItemInternal { + metadata: log_cache.metadata.clone(), + is_empty: log_cache.logs.is_empty(), + file_hash, + file_name: filename.clone(), + }; + + self.manifest.items.insert(filename, manifest_item); + + // Update last cached block if this cache goes beyond it + if let Ok(to_block) = log_cache.metadata.to_block.parse::() { + if to_block > self.last_cached_block { + self.last_cached_block = to_block; + } + } + } + + // Write updated manifest + self.write_manifest()?; + + Ok(()) + } + + // Validate a log cache signature + fn validate_log_cache(&self, log_cache: &LogCacheInternal) -> anyhow::Result { + let from_block = log_cache.metadata.from_block.parse::()?; + let to_block = log_cache.metadata.to_block.parse::()?; + + let mut bytes_to_verify = serde_json::to_vec(&log_cache.logs)?; + bytes_to_verify.extend_from_slice(&from_block.to_be_bytes()); + bytes_to_verify.extend_from_slice(&to_block.to_be_bytes()); + let hashed_data = keccak256(&bytes_to_verify); + + let signature_hex = log_cache.metadata.signature.trim_start_matches("0x"); + let signature_bytes = hex::decode(signature_hex)?; + + let created_by_address = log_cache.metadata.created_by.parse::
()?; + + Ok(sign::net_key_verify( + hashed_data.to_vec(), + &created_by_address, + signature_bytes, + )?) + } + + // Write manifest to VFS + fn write_manifest(&self) -> anyhow::Result<()> { + let manifest_bytes = serde_json::to_vec(&self.manifest)?; + let manifest_path = format!("{}/{}", self.drive_path, self.manifest.manifest_filename); + let manifest_file = vfs::open_file(&manifest_path, true, None)?; + manifest_file.write(&manifest_bytes)?; + info!("Updated manifest file: {}", manifest_path); + Ok(()) + } + + // Fallback to RPC bootstrap - catch up from where we left off + fn try_bootstrap_from_rpc(&mut self, hypermap: &hypermap::Hypermap) -> anyhow::Result<()> { + info!( + "Bootstrapping from RPC, starting from block {}", + self.last_cached_block + 1 + ); + + // Only run RPC bootstrap if we're behind the current chain head + let current_chain_head = hypermap.provider.get_block_number()?; + if self.last_cached_block < current_chain_head { + self.cache_logs_and_update_manifest(hypermap)?; + + // run it twice for fresh boot case: + // - initial bootstrap takes much time + // - in that time, the block you are updating to is no longer the head of the chain + // - so run again to get to the head of the chain + self.cache_logs_and_update_manifest(hypermap)?; + } else { + info!( + "Already caught up to chain head ({}), no RPC bootstrap needed", + current_chain_head + ); + } + Ok(()) + } + + fn to_wit_manifest(&self) -> WitManifest { + let items = self + .manifest + .items + .iter() + .map(|(k, v)| { + let wit_meta = WitLogsMetadata { + chain_id: v.metadata.chain_id.clone(), + from_block: v.metadata.from_block.clone(), + to_block: v.metadata.to_block.clone(), + time_created: v.metadata.time_created.clone(), + created_by: v.metadata.created_by.clone(), + signature: v.metadata.signature.clone(), + }; + let wit_item = WitManifestItem { + metadata: wit_meta, + is_empty: v.is_empty, + file_hash: v.file_hash.clone(), + file_name: v.file_name.clone(), + }; + (k.clone(), wit_item) + }) + .collect::>(); + + WitManifest { + items, + manifest_filename: self.manifest.manifest_filename.clone(), + chain_id: self.manifest.chain_id.clone(), + protocol_version: self.manifest.protocol_version.clone(), + } + } +} + +#[derive(Debug, Serialize, Deserialize)] +enum HttpApi { + GetManifest, + GetLogCacheFile(String), + GetStatus, +} + +fn http_handler( + state: &mut State, + path: &str, +) -> anyhow::Result<(http::server::HttpResponse, Vec)> { + let response = http::server::HttpResponse::new(http::StatusCode::OK) + .header("Content-Type", "application/json"); + + // Basic routing based on path + Ok(if path == "/manifest" || path == "/manifest.json" { + let manifest_path = format!("{}/{}", state.drive_path, state.manifest.manifest_filename); + let manifest_file = vfs::open_file(&manifest_path, true, None)?; + match manifest_file.read() { + Ok(content) => (response, content), + Err(e) => { + error!( + "HTTP: Failed to read manifest file {}: {:?}", + manifest_path, e + ); + ( + http::server::HttpResponse::new(http::StatusCode::NOT_FOUND), + b"Manifest not found".to_vec(), + ) + } + } + } else if path.starts_with("/log-cache/") { + let filename = path.trim_start_matches("/log-cache/"); + if filename.is_empty() || filename.contains("..") { + // Basic security check + return Ok(( + http::server::HttpResponse::new(http::StatusCode::BAD_REQUEST), + b"Invalid filename".to_vec(), + )); + } + let log_cache_path = format!("{}/{}", state.drive_path, filename); + let log_cache_file = vfs::open_file(&log_cache_path, true, None)?; + match log_cache_file.read() { + Ok(content) => (response, content), + Err(e) => { + error!( + "HTTP: Failed to read log cache file {}: {:?}", + log_cache_path, e + ); + ( + http::server::HttpResponse::new(http::StatusCode::NOT_FOUND), + b"Log cache file not found".to_vec(), + ) + } + } + } else if path == "/status" { + let status_info = CacherStatus { + last_cached_block: state.last_cached_block, + chain_id: state.chain_id.clone(), + protocol_version: state.protocol_version.clone(), + next_cache_attempt_in_seconds: if state.is_cache_timer_live { + Some(state.cache_interval_s) + } else { + None + }, + manifest_filename: state.manifest.manifest_filename.clone(), + log_files_count: state.manifest.items.len() as u32, + our_address: our().to_string(), + is_providing: state.is_providing, + }; + match serde_json::to_vec(&status_info) { + Ok(body) => (response, body), + Err(e) => { + error!("HTTP: Failed to serialize status: {:?}", e); + ( + http::server::HttpResponse::new(http::StatusCode::INTERNAL_SERVER_ERROR), + b"Error serializing status".to_vec(), + ) + } + } + } else { + ( + http::server::HttpResponse::new(http::StatusCode::NOT_FOUND), + b"Not Found".to_vec(), + ) + }) +} + +fn handle_request( + our: &Address, + source: &Address, + state: &mut State, + request: CacherRequest, +) -> anyhow::Result<()> { + let is_local = is_local_request(our, source); + + // If we're still starting, respond with IsStarting to all requests + if state.is_starting { + Response::new().body(CacherResponse::IsStarting).send()?; + return Ok(()); + } + + if !is_local && source.process.to_string() != "hypermap-cacher:hypermap-cacher:sys" { + warn!("Rejecting remote request from non-hypermap-cacher: {source}"); + Response::new().body(CacherResponse::Rejected).send()?; + return Ok(()); + } + + if !is_local + && !state.is_providing + && source.process.to_string() == "hypermap-cacher:hypermap-cacher:sys" + { + warn!("Rejecting remote request from {source} - not in provider mode"); + Response::new().body(CacherResponse::Rejected).send()?; + return Ok(()); + } + let response_body = match request { + CacherRequest::GetManifest => { + let manifest_path = + format!("{}/{}", state.drive_path, state.manifest.manifest_filename); + if state.manifest.items.is_empty() && vfs::metadata(&manifest_path, None).is_err() { + CacherResponse::GetManifest(None) + } else { + // Ensure manifest is loaded from VFS if state is fresh and manifest file exists + // This is usually handled by State::load, but as a fallback: + if state.manifest.items.is_empty() { + // If manifest in memory is empty, try to load it + let manifest_file = vfs::open_file(&manifest_path, true, None)?; + if let Ok(bytes) = manifest_file.read() { + if let Ok(disk_manifest) = + serde_json::from_slice::(&bytes) + { + state.manifest = disk_manifest; + } + } + } + CacherResponse::GetManifest(Some(state.to_wit_manifest())) + } + } + CacherRequest::GetLogCacheContent(filename) => { + let log_cache_path = format!("{}/{}", state.drive_path, filename); + let log_cache_file = vfs::open_file(&log_cache_path, true, None)?; + match log_cache_file.read() { + Ok(content_bytes) => { + // Content is raw JSON bytes of LogCacheInternal. + // The WIT expects a string. + match String::from_utf8(content_bytes) { + Ok(content_str) => { + CacherResponse::GetLogCacheContent(Ok(Some(content_str))) + } + Err(e) => { + error!("Failed to convert log cache content to UTF-8 string: {}", e); + CacherResponse::GetLogCacheContent(Err(format!( + "File content not valid UTF-8: {}", + e + ))) + } + } + } + Err(_) => CacherResponse::GetLogCacheContent(Ok(None)), + } + } + CacherRequest::GetStatus => { + let status = CacherStatus { + last_cached_block: state.last_cached_block, + chain_id: state.chain_id.clone(), + protocol_version: state.protocol_version.clone(), + next_cache_attempt_in_seconds: if state.is_cache_timer_live { + Some(state.cache_interval_s) + } else { + None + }, + manifest_filename: state.manifest.manifest_filename.clone(), + log_files_count: state.manifest.items.len() as u32, + our_address: our.to_string(), + is_providing: state.is_providing, + }; + CacherResponse::GetStatus(status) + } + CacherRequest::GetLogsByRange(req_params) => { + let mut relevant_caches: Vec = Vec::new(); + let req_from_block = req_params.from_block; + // If req_params.to_block is None, we effectively want to go up to the highest block available in caches. + // For simplicity in overlap calculation, we can treat None as u64::MAX here. + let effective_req_to_block = req_params.to_block.unwrap_or(u64::MAX); + + for item in state.manifest.items.values() { + // Skip items that don't have an actual file (e.g., empty log ranges not written to disk). + if item.file_name.is_empty() { + continue; + } + + let cache_from = match item.metadata.from_block.parse::() { + Ok(b) => b, + Err(_) => { + warn!( + "Could not parse from_block for cache item {}: {}", + item.file_name, item.metadata.from_block + ); + continue; + } + }; + let cache_to = match item.metadata.to_block.parse::() { + Ok(b) => b, + Err(_) => { + warn!( + "Could not parse to_block for cache item {}: {}", + item.file_name, item.metadata.to_block + ); + continue; + } + }; + + // Check for overlap: max(start1, start2) <= min(end1, end2) + if max(req_from_block, cache_from) <= min(effective_req_to_block, cache_to) { + // This cache file overlaps with the requested range. + let file_vfs_path = format!("{}/{}", state.drive_path, item.file_name); + match vfs::open_file(&file_vfs_path, false, None) { + Ok(file) => match file.read() { + Ok(content_bytes) => { + match serde_json::from_slice::(&content_bytes) { + Ok(log_cache) => relevant_caches.push(log_cache), + Err(e) => { + error!( + "Failed to deserialize LogCacheInternal from {}: {:?}", + item.file_name, e + ); + // Decide: return error or skip this cache? For now, skip. + } + } + } + Err(e) => error!("Failed to read VFS file {}: {:?}", item.file_name, e), + }, + Err(e) => error!("Failed to open VFS file {}: {e:?}", item.file_name), + } + } + } + + // Sort caches by their from_block. + relevant_caches + .sort_by_key(|cache| cache.metadata.from_block.parse::().unwrap_or(0)); + + if relevant_caches.is_empty() { + CacherResponse::GetLogsByRange(Ok(GetLogsByRangeOkResponse::Latest( + state.last_cached_block, + ))) + } else { + match serde_json::to_string(&relevant_caches) { + Ok(json_string) => CacherResponse::GetLogsByRange(Ok( + GetLogsByRangeOkResponse::Logs((state.last_cached_block, json_string)), + )), + Err(e) => CacherResponse::GetLogsByRange(Err(format!( + "Failed to serialize relevant caches: {e}" + ))), + } + } + } + CacherRequest::StartProviding => { + if !is_local { + // should never happen: should be caught in check above + Response::new().body(CacherResponse::Rejected).send()?; + return Ok(()); + } + state.is_providing = true; + state.save(); + info!("Provider mode enabled"); + CacherResponse::StartProviding(Ok("Provider mode enabled".to_string())) + } + CacherRequest::StopProviding => { + if !is_local { + Response::new().body(CacherResponse::Rejected).send()?; + warn!("Rejecting remote request from {source} to alter provider mode"); + return Ok(()); + } + state.is_providing = false; + state.save(); + info!("Provider mode disabled"); + CacherResponse::StopProviding(Ok("Provider mode disabled".to_string())) + } + CacherRequest::SetNodes(new_nodes) => { + if !is_local { + Response::new().body(CacherResponse::Rejected).send()?; + warn!("Rejecting remote request from {source} to set nodes"); + return Ok(()); + } + state.nodes = new_nodes; + state.save(); + info!("Nodes updated to: {:?}", state.nodes); + CacherResponse::SetNodes(Ok("Nodes updated successfully".to_string())) + } + CacherRequest::Reset(custom_nodes) => { + if !is_local { + Response::new().body(CacherResponse::Rejected).send()?; + warn!("Rejecting remote request from {source} to reset"); + return Ok(()); + } + + info!("Resetting hypermap-cacher state and clearing VFS..."); + + // Clear all files from the drive + if let Err(e) = state.clear_drive() { + error!("Failed to clear drive during reset: {:?}", e); + CacherResponse::Reset(Err(format!("Failed to clear drive: {:?}", e))) + } else { + // Create new state with custom nodes if provided, otherwise use defaults + let nodes = match custom_nodes { + Some(nodes) => nodes, + None => DEFAULT_NODES.iter().map(|s| s.to_string()).collect(), + }; + + *state = State::new(&state.drive_path); + state.nodes = nodes; + state.save(); + + info!( + "Hypermap-cacher reset complete. New nodes: {:?}", + state.nodes + ); + CacherResponse::Reset(Ok( + "Reset completed successfully. Cacher will restart with new settings." + .to_string(), + )) + } + } + }; + + Response::new().body(response_body).send()?; + Ok(()) +} + +fn main_loop( + our: &Address, + state: &mut State, + hypermap: &hypermap::Hypermap, + server: &http::server::HttpServer, +) -> anyhow::Result<()> { + info!("Hypermap Cacher main_loop started. Our address: {}", our); + info!( + "Monitoring Hypermap contract: {}", + state.hypermap_address.to_string() + ); + info!( + "Chain ID: {}, Protocol Version: {}", + state.chain_id, state.protocol_version + ); + info!("Last cached block: {}", state.last_cached_block); + + // Always bootstrap on start to get latest state from other nodes or RPC + if state.is_starting { + match state.bootstrap_state(hypermap) { + Ok(_) => info!("Bootstrap process completed successfully."), + Err(e) => error!("Error during bootstrap process: {:?}", e), + } + } + + // Set up the main caching timer. + info!( + "Setting cache timer for {} seconds.", + state.cache_interval_s + ); + timer::set_timer(state.cache_interval_s * 1000, Some(b"cache_cycle".to_vec())); + state.is_cache_timer_live = true; + state.save(); + + loop { + let Ok(message) = await_message() else { + warn!("Failed to get message, continuing loop."); + continue; + }; + let source = message.source(); + + if message.is_request() { + if source.process == ProcessId::from_str("http-server:distro:sys").unwrap() { + // HTTP request from the system's HTTP server process + let Ok(http::server::HttpServerRequest::Http(http_request)) = + server.parse_request(message.body()) + else { + error!("Failed to parse HTTP request from http-server:distro:sys"); + // Potentially send an error response back if possible/expected + continue; + }; + let (http_response, body) = http_handler(state, &http_request.path()?)?; + Response::new() + .body(serde_json::to_vec(&http_response).unwrap()) + .blob_bytes(body) + .send()?; + } else { + // Standard process-to-process request + match serde_json::from_slice::(message.body()) { + Ok(request) => { + if let Err(e) = handle_request(our, &source, state, request) { + error!("Error handling request from {:?}: {:?}", source, e); + } + } + Err(e) => { + error!( + "Failed to deserialize CacherRequest from {:?}: {:?}", + source, e + ); + } + } + } + } else { + // It's a Response or other kind of message + if source.process == ProcessId::from_str("timer:distro:sys").unwrap() { + if message.context() == Some(b"cache_cycle") { + info!("Cache timer triggered."); + state.is_cache_timer_live = false; + match state.cache_logs_and_update_manifest(hypermap) { + Ok(_) => info!("Periodic cache cycle complete."), + Err(e) => error!("Error during periodic cache cycle: {:?}", e), + } + // Reset the timer for the next cycle + if !state.is_cache_timer_live { + timer::set_timer( + state.cache_interval_s * 1000, + Some(b"cache_cycle".to_vec()), + ); + state.is_cache_timer_live = true; + state.save(); + } + } + } else { + debug!( + "Received unhandled response or other message from {:?}.", + source + ); + } + } + } +} + +call_init!(init); +fn init(our: Address) { + init_logging(Level::INFO, Level::DEBUG, None, None, None).unwrap(); + info!("Hypermap Cacher process starting..."); + + let drive_path = vfs::create_drive(our.package_id(), "cache", None).unwrap(); + + let bind_config = http::server::HttpBindingConfig::default().authenticated(false); + let mut server = http::server::HttpServer::new(5); + + let hypermap_provider = hypermap::Hypermap::default(60); + + server + .bind_http_path("/manifest", bind_config.clone()) + .expect("Failed to bind /manifest"); + server + .bind_http_path("/manifest.json", bind_config.clone()) + .expect("Failed to bind /manifest.json"); + server + .bind_http_path("/log-cache/*", bind_config.clone()) + .expect("Failed to bind /log-cache/*"); + server + .bind_http_path("/status", bind_config.clone()) + .expect("Failed to bind /status"); + info!("Bound HTTP paths: /manifest, /log-cache/*, /status"); + + let mut state = State::load(&drive_path); + + loop { + match main_loop(&our, &mut state, &hypermap_provider, &server) { + Ok(()) => { + // main_loop should not exit with Ok in normal operation as it's an infinite loop. + error!("main_loop exited unexpectedly with Ok. Restarting."); + } + Err(e) => { + error!("main_loop exited with error: {:?}. Restarting.", e); + std::thread::sleep(std::time::Duration::from_secs(5)); + } + } + // Reload state in case of restart, or re-initialize if necessary. + state = State::load(&drive_path); + } +} diff --git a/hyperdrive/packages/hypermap-cacher/metadata.json b/hyperdrive/packages/hypermap-cacher/metadata.json new file mode 100644 index 000000000..93f2ccdbf --- /dev/null +++ b/hyperdrive/packages/hypermap-cacher/metadata.json @@ -0,0 +1,21 @@ +{ + "name": "hypermap-cacher", + "description": "", + "image": "", + "properties": { + "package_name": "hypermap-cacher", + "current_version": "0.1.0", + "publisher": "sys", + + "mirrors": [], + "code_hashes": { + "0.1.0": "" + }, + "wit_version": 1, + "dependencies": [ + "sign:sys" + ] + }, + "external_url": "", + "animation_url": "" +} diff --git a/hyperdrive/packages/hypermap-cacher/pkg/manifest.json b/hyperdrive/packages/hypermap-cacher/pkg/manifest.json new file mode 100644 index 000000000..ec498453e --- /dev/null +++ b/hyperdrive/packages/hypermap-cacher/pkg/manifest.json @@ -0,0 +1,28 @@ +[ + { + "process_name": "hypermap-cacher", + "process_wasm_path": "/hypermap-cacher.wasm", + "on_exit": "Restart", + "request_networking": true, + "request_capabilities": [ + "eth:distro:sys", + "http-server:distro:sys", + "net:distro:sys", + "sign:sign:sys", + "terminal:terminal:sys", + "timer:distro:sys", + "vfs:distro:sys" + ], + "grant_capabilities": [ + "eth:distro:sys", + "http-server:distro:sys", + "net:distro:sys", + "sign:sign:sys", + "terminal:terminal:sys", + "timer:distro:sys", + "vfs:distro:sys" + ], + "public": false, + "wit_version": 1 + } +] diff --git a/hyperdrive/packages/hypermap-cacher/pkg/scripts.json b/hyperdrive/packages/hypermap-cacher/pkg/scripts.json new file mode 100644 index 000000000..aab9de842 --- /dev/null +++ b/hyperdrive/packages/hypermap-cacher/pkg/scripts.json @@ -0,0 +1,50 @@ +{ + "start-providing.wasm": { + "root": false, + "public": false, + "request_networking": false, + "request_capabilities": [ + "hypermap-cacher:hypermap-cacher:sys" + ], + "grant_capabilities": [ + "hypermap-cacher:hypermap-cacher:sys" + ], + "wit_version": 1 + }, + "stop-providing.wasm": { + "root": false, + "public": false, + "request_networking": false, + "request_capabilities": [ + "hypermap-cacher:hypermap-cacher:sys" + ], + "grant_capabilities": [ + "hypermap-cacher:hypermap-cacher:sys" + ], + "wit_version": 1 + }, + "set-nodes.wasm": { + "root": false, + "public": false, + "request_networking": false, + "request_capabilities": [ + "hypermap-cacher:hypermap-cacher:sys" + ], + "grant_capabilities": [ + "hypermap-cacher:hypermap-cacher:sys" + ], + "wit_version": 1 + }, + "reset-cache.wasm": { + "root": false, + "public": false, + "request_networking": false, + "request_capabilities": [ + "hypermap-cacher:hypermap-cacher:sys" + ], + "grant_capabilities": [ + "hypermap-cacher:hypermap-cacher:sys" + ], + "wit_version": 1 + } +} diff --git a/hyperdrive/packages/hypermap-cacher/reset-cache/Cargo.toml b/hyperdrive/packages/hypermap-cacher/reset-cache/Cargo.toml new file mode 100644 index 000000000..2e8767af3 --- /dev/null +++ b/hyperdrive/packages/hypermap-cacher/reset-cache/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "reset-cache" +version = "0.1.0" +edition = "2021" +publish = false + +[dependencies] +hyperware_process_lib = "1.2.0" +process_macros = "0.1.0" +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +wit-bindgen = "0.36.0" + +[lib] +crate-type = ["cdylib"] + +[package.metadata.component] +package = "hyperware:process" diff --git a/hyperdrive/packages/hypermap-cacher/reset-cache/src/lib.rs b/hyperdrive/packages/hypermap-cacher/reset-cache/src/lib.rs new file mode 100644 index 000000000..64979a0d6 --- /dev/null +++ b/hyperdrive/packages/hypermap-cacher/reset-cache/src/lib.rs @@ -0,0 +1,67 @@ +//! reset:hypermap-cacher:sys +//! terminal script for resetting hypermap-cacher state and VFS. +//! +//! Usage: +//! reset:hypermap-cacher:sys [node1] [node2] [node3] ... +//! +//! Arguments: +//! [node1] [node2] ... Optional space-separated list of node names to use for bootstrapping +//! If no arguments provided, uses default nodes +//! +//! Example: +//! reset:hypermap-cacher:sys # Reset with default nodes +//! reset:hypermap-cacher:sys alice.os bob.os # Reset with custom nodes + +use crate::hyperware::process::hypermap_cacher::{CacherRequest, CacherResponse}; +use hyperware_process_lib::{await_next_message_body, call_init, println, Address, Request}; + +wit_bindgen::generate!({ + path: "target/wit", + world: "hypermap-cacher-sys-v0", + generate_unused_types: true, + additional_derives: [serde::Deserialize, serde::Serialize, process_macros::SerdeJsonInto], +}); + +call_init!(init); +fn init(_our: Address) { + let Ok(body) = await_next_message_body() else { + println!("reset: failed to get args!"); + return; + }; + + let args = String::from_utf8(body).unwrap_or_default(); + let parts: Vec<&str> = args.split_whitespace().collect(); + + let custom_nodes = if parts.is_empty() { + println!("Resetting hypermap-cacher with default nodes..."); + None + } else { + let nodes: Vec = parts.iter().map(|s| s.to_string()).collect(); + println!("Resetting hypermap-cacher with custom nodes: {:?}", nodes); + Some(nodes) + }; + + let response = Request::to(("our", "hypermap-cacher", "hypermap-cacher", "sys")) + .body(CacherRequest::Reset(custom_nodes)) + .send_and_await_response(10); // Give it more time for reset operations + + match response { + Ok(Ok(message)) => match message.body().try_into() { + Ok(CacherResponse::Reset(Ok(msg))) => { + println!("✓ {}", msg); + } + Ok(CacherResponse::Reset(Err(err))) => { + println!("✗ Failed to reset: {}", err); + } + _ => { + println!("✗ Unexpected response from hypermap-cacher"); + } + }, + Ok(Err(err)) => { + println!("✗ Request failed: {:?}", err); + } + Err(err) => { + println!("✗ Communication error: {:?}", err); + } + } +} diff --git a/hyperdrive/packages/hypermap-cacher/set-nodes/Cargo.toml b/hyperdrive/packages/hypermap-cacher/set-nodes/Cargo.toml new file mode 100644 index 000000000..ff8d23f8f --- /dev/null +++ b/hyperdrive/packages/hypermap-cacher/set-nodes/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "set-nodes" +version = "0.1.0" +edition = "2021" +publish = false + +[dependencies] +hyperware_process_lib = "1.2.0" +process_macros = "0.1.0" +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +wit-bindgen = "0.36.0" + +[lib] +crate-type = ["cdylib"] + +[package.metadata.component] +package = "hyperware:process" diff --git a/hyperdrive/packages/hypermap-cacher/set-nodes/src/lib.rs b/hyperdrive/packages/hypermap-cacher/set-nodes/src/lib.rs new file mode 100644 index 000000000..fa1de5cd6 --- /dev/null +++ b/hyperdrive/packages/hypermap-cacher/set-nodes/src/lib.rs @@ -0,0 +1,66 @@ +//! set-nodes:hypermap-cacher:sys +//! terminal script for setting the nodes list for hypermap-cacher bootstrap. +//! +//! Usage: +//! set-nodes:hypermap-cacher:sys [node1] [node2] [node3] ... +//! +//! Arguments: +//! [node1] [node2] ... Space-separated list of node names to use for bootstrapping +//! +//! Example: +//! set-nodes:hypermap-cacher:sys alice.os bob.os charlie.os + +use crate::hyperware::process::hypermap_cacher::{CacherRequest, CacherResponse}; +use hyperware_process_lib::{await_next_message_body, call_init, println, Address, Request}; + +wit_bindgen::generate!({ + path: "target/wit", + world: "hypermap-cacher-sys-v0", + generate_unused_types: true, + additional_derives: [serde::Deserialize, serde::Serialize, process_macros::SerdeJsonInto], +}); + +call_init!(init); +fn init(_our: Address) { + let Ok(body) = await_next_message_body() else { + println!("set-nodes: failed to get args!"); + return; + }; + + let args = String::from_utf8(body).unwrap_or_default(); + let parts: Vec<&str> = args.split_whitespace().collect(); + + if parts.is_empty() { + println!("set-nodes: no arguments provided. Please specify node names."); + println!("example: set-nodes alice.os bob.os charlie.os"); + return; + } + + let nodes: Vec = parts.iter().map(|s| s.to_string()).collect(); + + println!("Setting hypermap-cacher nodes to: {:?}", nodes); + + let response = Request::to(("our", "hypermap-cacher", "hypermap-cacher", "sys")) + .body(CacherRequest::SetNodes(nodes)) + .send_and_await_response(5); + + match response { + Ok(Ok(message)) => match message.body().try_into() { + Ok(CacherResponse::SetNodes(Ok(msg))) => { + println!("✓ {}", msg); + } + Ok(CacherResponse::SetNodes(Err(err))) => { + println!("✗ Failed to set nodes: {}", err); + } + _ => { + println!("✗ Unexpected response from hypermap-cacher"); + } + }, + Ok(Err(err)) => { + println!("✗ Request failed: {:?}", err); + } + Err(err) => { + println!("✗ Communication error: {:?}", err); + } + } +} diff --git a/hyperdrive/packages/hypermap-cacher/start-providing/Cargo.toml b/hyperdrive/packages/hypermap-cacher/start-providing/Cargo.toml new file mode 100644 index 000000000..3a9214964 --- /dev/null +++ b/hyperdrive/packages/hypermap-cacher/start-providing/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "start-providing" +version = "0.1.0" +edition = "2021" +publish = false + +[dependencies] +hyperware_process_lib = "1.2.0" +process_macros = "0.1.0" +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +wit-bindgen = "0.36.0" + +[lib] +crate-type = ["cdylib"] + +[package.metadata.component] +package = "hyperware:process" diff --git a/hyperdrive/packages/hypermap-cacher/start-providing/src/lib.rs b/hyperdrive/packages/hypermap-cacher/start-providing/src/lib.rs new file mode 100644 index 000000000..ced9ee8a3 --- /dev/null +++ b/hyperdrive/packages/hypermap-cacher/start-providing/src/lib.rs @@ -0,0 +1,38 @@ +use crate::hyperware::process::hypermap_cacher::{CacherRequest, CacherResponse}; +use hyperware_process_lib::{call_init, println, Address, Request}; + +wit_bindgen::generate!({ + path: "target/wit", + world: "hypermap-cacher-sys-v0", + generate_unused_types: true, + additional_derives: [serde::Deserialize, serde::Serialize, process_macros::SerdeJsonInto], +}); + +call_init!(init); +fn init(_our: Address) { + println!("Enabling hypermap-cacher provider mode..."); + + let response = Request::to(("our", "hypermap-cacher", "hypermap-cacher", "sys")) + .body(CacherRequest::StartProviding) + .send_and_await_response(5); + + match response { + Ok(Ok(message)) => match message.body().try_into() { + Ok(CacherResponse::StartProviding(Ok(msg))) => { + println!("✓ {}", msg); + } + Ok(CacherResponse::StartProviding(Err(err))) => { + println!("✗ Failed to enable provider mode: {}", err); + } + _ => { + println!("✗ Unexpected response from hypermap-cacher"); + } + }, + Ok(Err(err)) => { + println!("✗ Request failed: {:?}", err); + } + Err(err) => { + println!("✗ Communication error: {:?}", err); + } + } +} diff --git a/hyperdrive/packages/hypermap-cacher/stop-providing/Cargo.toml b/hyperdrive/packages/hypermap-cacher/stop-providing/Cargo.toml new file mode 100644 index 000000000..afb8ba956 --- /dev/null +++ b/hyperdrive/packages/hypermap-cacher/stop-providing/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "stop-providing" +version = "0.1.0" +edition = "2021" +publish = false + +[dependencies] +hyperware_process_lib = "1.2.0" +process_macros = "0.1.0" +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +wit-bindgen = "0.36.0" + +[lib] +crate-type = ["cdylib"] + +[package.metadata.component] +package = "hyperware:process" diff --git a/hyperdrive/packages/hypermap-cacher/stop-providing/src/lib.rs b/hyperdrive/packages/hypermap-cacher/stop-providing/src/lib.rs new file mode 100644 index 000000000..c3bbef6d5 --- /dev/null +++ b/hyperdrive/packages/hypermap-cacher/stop-providing/src/lib.rs @@ -0,0 +1,38 @@ +use crate::hyperware::process::hypermap_cacher::{CacherRequest, CacherResponse}; +use hyperware_process_lib::{call_init, println, Address, Request}; + +wit_bindgen::generate!({ + path: "target/wit", + world: "hypermap-cacher-sys-v0", + generate_unused_types: true, + additional_derives: [serde::Deserialize, serde::Serialize, process_macros::SerdeJsonInto], +}); + +call_init!(init); +fn init(_our: Address) { + println!("Disabling hypermap-cacher provider mode..."); + + let response = Request::to(("our", "hypermap-cacher", "hypermap-cacher", "sys")) + .body(CacherRequest::StopProviding) + .send_and_await_response(5); + + match response { + Ok(Ok(message)) => match message.body().try_into() { + Ok(CacherResponse::StopProviding(Ok(msg))) => { + println!("✓ {}", msg); + } + Ok(CacherResponse::StopProviding(Err(err))) => { + println!("✗ Failed to disable provider mode: {}", err); + } + _ => { + println!("✗ Unexpected response from hypermap-cacher"); + } + }, + Ok(Err(err)) => { + println!("✗ Request failed: {:?}", err); + } + Err(err) => { + println!("✗ Communication error: {:?}", err); + } + } +} diff --git a/hyperdrive/packages/settings/Cargo.lock b/hyperdrive/packages/settings/Cargo.lock index cdda8eb2d..cdf479e50 100644 --- a/hyperdrive/packages/settings/Cargo.lock +++ b/hyperdrive/packages/settings/Cargo.lock @@ -1512,15 +1512,16 @@ dependencies = [ [[package]] name = "hyperware_process_lib" -version = "1.0.5" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd85e48b5f017132d52df416578fe6816b51d166b70ffd8718dbe29ae979d98b" +checksum = "414dd471dfac43943b314200b4943f38c4b08337103840e2192cfb5dc9b1bea5" dependencies = [ "alloy", "alloy-primitives", "alloy-sol-macro", "alloy-sol-types", "anyhow", + "base64", "bincode", "http", "mime_guess", diff --git a/hyperdrive/packages/settings/settings/Cargo.toml b/hyperdrive/packages/settings/settings/Cargo.toml index ee2fd1f7a..f136481a3 100644 --- a/hyperdrive/packages/settings/settings/Cargo.toml +++ b/hyperdrive/packages/settings/settings/Cargo.toml @@ -9,7 +9,7 @@ simulation-mode = [] [dependencies] anyhow = "1.0" base64 = "0.22.0" -hyperware_process_lib = "1.0.5" +hyperware_process_lib = "1.2.0" rmp-serde = "1.2.0" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" diff --git a/hyperdrive/packages/sign/Cargo.lock b/hyperdrive/packages/sign/Cargo.lock index 81cfa1e02..fad4a2f94 100644 --- a/hyperdrive/packages/sign/Cargo.lock +++ b/hyperdrive/packages/sign/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "addr2line" @@ -1596,15 +1596,16 @@ dependencies = [ [[package]] name = "hyperware_process_lib" -version = "1.0.4" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "572247e1810eccc6197799ea4d9944751a62251d2fb6afa17ca88e16b30c22b9" +checksum = "414dd471dfac43943b314200b4943f38c4b08337103840e2192cfb5dc9b1bea5" dependencies = [ "alloy", "alloy-primitives", "alloy-sol-macro", "alloy-sol-types", "anyhow", + "base64", "bincode", "color-eyre", "http", diff --git a/hyperdrive/packages/sign/sign/Cargo.toml b/hyperdrive/packages/sign/sign/Cargo.toml index fb0b8b79d..0db3a3110 100644 --- a/hyperdrive/packages/sign/sign/Cargo.toml +++ b/hyperdrive/packages/sign/sign/Cargo.toml @@ -8,7 +8,7 @@ simulation-mode = [] [dependencies] anyhow = "1.0.97" -hyperware_process_lib = {version = "1.0.4", features = ["logging"]} +hyperware_process_lib = { version = "1.2.0", features = ["logging"] } process_macros = "0.1" rmp-serde = "1.3.0" serde = { version = "1.0", features = ["derive"] } diff --git a/hyperdrive/packages/sign/sign/src/lib.rs b/hyperdrive/packages/sign/sign/src/lib.rs index c4d94eb3e..15b82c144 100644 --- a/hyperdrive/packages/sign/sign/src/lib.rs +++ b/hyperdrive/packages/sign/sign/src/lib.rs @@ -41,7 +41,7 @@ fn handle_message(message: &Message) -> Result<()> { let source = message.source(); match body.try_into()? { sign::Request::NetKeySign => handle_sign(source), - sign::Request::NetKeyVerify(req) => handle_verify(source, req), + sign::Request::NetKeyVerify(req) => handle_verify(req), sign::Request::NetKeyMakeMessage => handle_make_message(source), } } @@ -73,13 +73,14 @@ fn handle_sign(source: &Address) -> Result<()> { Ok(()) } -fn handle_verify(source: &Address, req: sign::NetKeyVerifyRequest) -> Result<()> { - let Some(blob) = get_blob() else { - return Err(anyhow!("no blob")); - }; - let message = make_message(source, &blob); +fn handle_verify(req: sign::NetKeyVerifyRequest) -> Result<()> { + let blob = get_blob().unwrap_or(LazyLoadBlob::default()); + + let source = req.node.parse()?; + let message = make_message(&source, &blob); + let body = rmp_serde::to_vec(&NetAction::Verify { - from: our(), + from: Address::new(source.node(), ("sign", "sign", "sys")), signature: req.signature, })?; let res = Request::to(("our", "net", "distro", "sys")) @@ -110,7 +111,7 @@ fn handle_make_message(source: &Address) -> Result<()> { mime: None, bytes: message, }) - .body(sign::Response::NetKeySign) + .body(sign::Response::NetKeyMakeMessage) .send()?; Ok(()) } diff --git a/hyperdrive/packages/terminal/Cargo.lock b/hyperdrive/packages/terminal/Cargo.lock index 39b607178..ef7d1a2ed 100644 --- a/hyperdrive/packages/terminal/Cargo.lock +++ b/hyperdrive/packages/terminal/Cargo.lock @@ -1654,15 +1654,16 @@ dependencies = [ [[package]] name = "hyperware_process_lib" -version = "1.0.5" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd85e48b5f017132d52df416578fe6816b51d166b70ffd8718dbe29ae979d98b" +checksum = "414dd471dfac43943b314200b4943f38c4b08337103840e2192cfb5dc9b1bea5" dependencies = [ "alloy", "alloy-primitives", "alloy-sol-macro", "alloy-sol-types", "anyhow", + "base64", "bincode", "http", "mime_guess", diff --git a/hyperdrive/packages/terminal/alias/Cargo.toml b/hyperdrive/packages/terminal/alias/Cargo.toml index 2ab499c44..15c852151 100644 --- a/hyperdrive/packages/terminal/alias/Cargo.toml +++ b/hyperdrive/packages/terminal/alias/Cargo.toml @@ -8,7 +8,7 @@ simulation-mode = [] [dependencies] anyhow = "1.0" -hyperware_process_lib = "1.0.5" +hyperware_process_lib = "1.2.0" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" wit-bindgen = "0.36.0" diff --git a/hyperdrive/packages/terminal/cat/Cargo.toml b/hyperdrive/packages/terminal/cat/Cargo.toml index 3952dea50..f63537aa9 100644 --- a/hyperdrive/packages/terminal/cat/Cargo.toml +++ b/hyperdrive/packages/terminal/cat/Cargo.toml @@ -8,7 +8,7 @@ simulation-mode = [] [dependencies] anyhow = "1.0" -hyperware_process_lib = "1.0.5" +hyperware_process_lib = "1.2.0" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" wit-bindgen = "0.36.0" diff --git a/hyperdrive/packages/terminal/echo/Cargo.toml b/hyperdrive/packages/terminal/echo/Cargo.toml index 5b99dabb8..ecb7b533b 100644 --- a/hyperdrive/packages/terminal/echo/Cargo.toml +++ b/hyperdrive/packages/terminal/echo/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" simulation-mode = [] [dependencies] -hyperware_process_lib = "1.0.5" +hyperware_process_lib = "1.2.0" wit-bindgen = "0.36.0" [lib] diff --git a/hyperdrive/packages/terminal/help/Cargo.toml b/hyperdrive/packages/terminal/help/Cargo.toml index be5eb5701..e694b5dc7 100644 --- a/hyperdrive/packages/terminal/help/Cargo.toml +++ b/hyperdrive/packages/terminal/help/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" simulation-mode = [] [dependencies] -hyperware_process_lib = "1.0.5" +hyperware_process_lib = "1.2.0" wit-bindgen = "0.36.0" [lib] diff --git a/hyperdrive/packages/terminal/hfetch/Cargo.toml b/hyperdrive/packages/terminal/hfetch/Cargo.toml index ec30fae24..168545a97 100644 --- a/hyperdrive/packages/terminal/hfetch/Cargo.toml +++ b/hyperdrive/packages/terminal/hfetch/Cargo.toml @@ -8,7 +8,7 @@ simulation-mode = [] [dependencies] anyhow = "1.0" -hyperware_process_lib = "1.0.5" +hyperware_process_lib = "1.2.0" rmp-serde = "1.1.2" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" diff --git a/hyperdrive/packages/terminal/hi/Cargo.toml b/hyperdrive/packages/terminal/hi/Cargo.toml index 3eed73522..dc15aebbe 100644 --- a/hyperdrive/packages/terminal/hi/Cargo.toml +++ b/hyperdrive/packages/terminal/hi/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" simulation-mode = [] [dependencies] -hyperware_process_lib = "1.0.5" +hyperware_process_lib = "1.2.0" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" wit-bindgen = "0.36.0" diff --git a/hyperdrive/packages/terminal/kill/Cargo.toml b/hyperdrive/packages/terminal/kill/Cargo.toml index 78bdd5dbd..0d7f382f5 100644 --- a/hyperdrive/packages/terminal/kill/Cargo.toml +++ b/hyperdrive/packages/terminal/kill/Cargo.toml @@ -8,7 +8,7 @@ simulation-mode = [] [dependencies] anyhow = "1.0" -hyperware_process_lib = "1.0.5" +hyperware_process_lib = "1.2.0" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" wit-bindgen = "0.36.0" diff --git a/hyperdrive/packages/terminal/m/Cargo.toml b/hyperdrive/packages/terminal/m/Cargo.toml index 2c2e53f4e..bc62d159a 100644 --- a/hyperdrive/packages/terminal/m/Cargo.toml +++ b/hyperdrive/packages/terminal/m/Cargo.toml @@ -9,7 +9,7 @@ simulation-mode = [] [dependencies] anyhow = "1.0" clap = "4.4" -hyperware_process_lib = "1.0.5" +hyperware_process_lib = "1.2.0" regex = "1.10.3" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" diff --git a/hyperdrive/packages/terminal/net-diagnostics/Cargo.toml b/hyperdrive/packages/terminal/net-diagnostics/Cargo.toml index 25f0e1845..c8adb08a3 100644 --- a/hyperdrive/packages/terminal/net-diagnostics/Cargo.toml +++ b/hyperdrive/packages/terminal/net-diagnostics/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" simulation-mode = [] [dependencies] -hyperware_process_lib = "1.0.5" +hyperware_process_lib = "1.2.0" rmp-serde = "1.1.2" serde = { version = "1.0", features = ["derive"] } wit-bindgen = "0.36.0" diff --git a/hyperdrive/packages/terminal/peer/Cargo.toml b/hyperdrive/packages/terminal/peer/Cargo.toml index 6ae158991..74457b0b4 100644 --- a/hyperdrive/packages/terminal/peer/Cargo.toml +++ b/hyperdrive/packages/terminal/peer/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" simulation-mode = [] [dependencies] -hyperware_process_lib = "1.0.5" +hyperware_process_lib = "1.2.0" rmp-serde = "1.1.2" serde = { version = "1.0", features = ["derive"] } wit-bindgen = "0.36.0" diff --git a/hyperdrive/packages/terminal/peers/Cargo.toml b/hyperdrive/packages/terminal/peers/Cargo.toml index c46aa65b9..8fe5a22a0 100644 --- a/hyperdrive/packages/terminal/peers/Cargo.toml +++ b/hyperdrive/packages/terminal/peers/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" simulation-mode = [] [dependencies] -hyperware_process_lib = "1.0.5" +hyperware_process_lib = "1.2.0" rmp-serde = "1.1.2" serde = { version = "1.0", features = ["derive"] } wit-bindgen = "0.36.0" diff --git a/hyperdrive/packages/terminal/pkg/manifest.json b/hyperdrive/packages/terminal/pkg/manifest.json index fea110a2f..8238109e0 100644 --- a/hyperdrive/packages/terminal/pkg/manifest.json +++ b/hyperdrive/packages/terminal/pkg/manifest.json @@ -28,7 +28,9 @@ }, "kv:distro:sys", "net:distro:sys", + "sign:sign:sys", "sqlite:distro:sys", + "timer:distro:sys", "vfs:distro:sys", { "process": "vfs:distro:sys", diff --git a/hyperdrive/packages/terminal/terminal/Cargo.toml b/hyperdrive/packages/terminal/terminal/Cargo.toml index 0888a54e0..cb2639484 100644 --- a/hyperdrive/packages/terminal/terminal/Cargo.toml +++ b/hyperdrive/packages/terminal/terminal/Cargo.toml @@ -9,7 +9,7 @@ simulation-mode = [] [dependencies] anyhow = "1.0" bincode = "1.3.3" -hyperware_process_lib = "1.0.5" +hyperware_process_lib = "1.2.0" rand = "0.8" regex = "1.10.3" serde = { version = "1.0", features = ["derive"] } diff --git a/hyperdrive/packages/terminal/top/Cargo.toml b/hyperdrive/packages/terminal/top/Cargo.toml index 4a88d4dca..e3f30f405 100644 --- a/hyperdrive/packages/terminal/top/Cargo.toml +++ b/hyperdrive/packages/terminal/top/Cargo.toml @@ -9,7 +9,7 @@ simulation-mode = [] [dependencies] anyhow = "1.0" clap = "4.4" -hyperware_process_lib = "1.0.5" +hyperware_process_lib = "1.2.0" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" wit-bindgen = "0.36.0" diff --git a/hyperdrive/packages/tester/Cargo.lock b/hyperdrive/packages/tester/Cargo.lock index a91206ea1..ad65f9246 100644 --- a/hyperdrive/packages/tester/Cargo.lock +++ b/hyperdrive/packages/tester/Cargo.lock @@ -1512,15 +1512,16 @@ dependencies = [ [[package]] name = "hyperware_process_lib" -version = "1.0.5" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd85e48b5f017132d52df416578fe6816b51d166b70ffd8718dbe29ae979d98b" +checksum = "414dd471dfac43943b314200b4943f38c4b08337103840e2192cfb5dc9b1bea5" dependencies = [ "alloy", "alloy-primitives", "alloy-sol-macro", "alloy-sol-types", "anyhow", + "base64", "bincode", "http", "mime_guess", diff --git a/hyperdrive/packages/tester/tester/Cargo.toml b/hyperdrive/packages/tester/tester/Cargo.toml index 119d9b832..85a430763 100644 --- a/hyperdrive/packages/tester/tester/Cargo.toml +++ b/hyperdrive/packages/tester/tester/Cargo.toml @@ -9,7 +9,7 @@ simulation-mode = [] [dependencies] anyhow = "1.0" bincode = "1.3.3" -hyperware_process_lib = "1.0.5" +hyperware_process_lib = "1.2.0" process_macros = "0.1" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" diff --git a/hyperdrive/src/net/mod.rs b/hyperdrive/src/net/mod.rs index 96c711e97..94ab4c46e 100644 --- a/hyperdrive/src/net/mod.rs +++ b/hyperdrive/src/net/mod.rs @@ -9,7 +9,7 @@ use types::{ ActivePassthroughs, IdentityExt, NetData, OnchainPKI, Peers, PendingPassthroughs, TCP_PROTOCOL, WS_PROTOCOL, }; -use {dashmap::DashMap, ring::signature::Ed25519KeyPair, std::sync::Arc, tokio::task::JoinSet}; +use {dashmap::DashMap, ring::signature::{Ed25519KeyPair, KeyPair}, std::sync::Arc, tokio::task::JoinSet}; mod connect; mod indirect; @@ -302,7 +302,7 @@ async fn handle_local_request( .concat(); ( NetResponse::Verified(utils::validate_signature( - &from.node, &signature, &message, &data.pki, + &from.node, &signature, &message, &data.pki, ext.keypair.public_key().as_ref().to_vec(), )), None, ) diff --git a/hyperdrive/src/net/utils.rs b/hyperdrive/src/net/utils.rs index 36ea5b769..e80dac4e0 100644 --- a/hyperdrive/src/net/utils.rs +++ b/hyperdrive/src/net/utils.rs @@ -270,7 +270,7 @@ pub fn ingest_log(log: HnsUpdate, pki: &OnchainPKI) { ); } -pub fn validate_signature(from: &str, signature: &[u8], message: &[u8], pki: &OnchainPKI) -> bool { +pub fn validate_signature(from: &str, signature: &[u8], message: &[u8], pki: &OnchainPKI, our_key: Vec) -> bool { if let Some(peer_id) = pki.get(from) { let their_networking_key = signature::UnparsedPublicKey::new( &signature::ED25519, @@ -278,7 +278,11 @@ pub fn validate_signature(from: &str, signature: &[u8], message: &[u8], pki: &On ); their_networking_key.verify(message, signature).is_ok() } else { - false + let our_key = signature::UnparsedPublicKey::new( + &signature::ED25519, + our_key, + ); + our_key.verify(message, signature).is_ok() } } diff --git a/hyperdrive/src/register-ui/package-lock.json b/hyperdrive/src/register-ui/package-lock.json index f5fd6ff06..7ce6faa90 100644 --- a/hyperdrive/src/register-ui/package-lock.json +++ b/hyperdrive/src/register-ui/package-lock.json @@ -23,7 +23,7 @@ "react-modal": "^3.16.1", "react-router-dom": "^6.16.0", "unocss": "^0.59.4", - "viem": "^2.19.0", + "viem": "^2.23.2", "wagmi": "^2.12.5" }, "devDependencies": { diff --git a/hyperdrive/src/register-ui/package.json b/hyperdrive/src/register-ui/package.json index b1a0bb4e8..22e87e8a9 100644 --- a/hyperdrive/src/register-ui/package.json +++ b/hyperdrive/src/register-ui/package.json @@ -19,7 +19,7 @@ "react-modal": "^3.16.1", "react-router-dom": "^6.16.0", "unocss": "^0.59.4", - "viem": "^2.19.0", + "viem": "^2.23.2", "wagmi": "^2.12.5" }, "scripts": { diff --git a/hyperdrive/src/register-ui/src/pages/CommitDotOsName.tsx b/hyperdrive/src/register-ui/src/pages/CommitDotOsName.tsx index 75fc4f50e..a39af717f 100644 --- a/hyperdrive/src/register-ui/src/pages/CommitDotOsName.tsx +++ b/hyperdrive/src/register-ui/src/pages/CommitDotOsName.tsx @@ -11,7 +11,8 @@ import { Tooltip } from "../components/Tooltip"; import { useAccount, useWaitForTransactionReceipt, useWriteContract } from "wagmi"; import { useConnectModal, useAddRecentTransaction } from "@rainbow-me/rainbowkit" import { dotOsAbi, DOTOS } from "../abis"; -import { stringToHex, encodeAbiParameters, parseAbiParameters, keccak256 } from "viem"; +import { createPublicClient, http, stringToHex, encodeAbiParameters, parseAbiParameters, keccak256, BaseError, ContractFunctionRevertedError } from "viem"; +import { base } from 'viem/chains' import BackButton from "../components/BackButton"; interface RegisterOsNameProps extends PageProps { } @@ -76,13 +77,35 @@ function CommitDotOsName({ [stringToHex(name), address] ) ) - writeContract({ - abi: dotOsAbi, - address: DOTOS, - functionName: 'commit', - args: [commit], - gas: 1000000n, - }) + + const publicClient = createPublicClient({ + chain: base, + transport: http(), + }); + + try { + const { request } = await publicClient.simulateContract({ + abi: dotOsAbi, + address: DOTOS, + functionName: 'commit', + args: [commit], + account: address + }); + + writeContract(request); + } catch (err) { + if (err instanceof BaseError) { + const revertError = err.walk(err => err instanceof ContractFunctionRevertedError) + if (revertError instanceof ContractFunctionRevertedError) { + if (revertError?.data) { + const errorName = revertError.data.errorName; + const args = revertError.data.args; + console.log(`Reverted with ${errorName}`, args); + } + } + } + throw err; + } }, [name, direct, address, writeContract, setNetworkingKey, setIpAddress, setWsPort, setTcpPort, setRouters, openConnectModal]) diff --git a/hyperdrive/src/register-ui/src/pages/MintDotOsName.tsx b/hyperdrive/src/register-ui/src/pages/MintDotOsName.tsx index 25e3b6138..43b780f3d 100644 --- a/hyperdrive/src/register-ui/src/pages/MintDotOsName.tsx +++ b/hyperdrive/src/register-ui/src/pages/MintDotOsName.tsx @@ -3,10 +3,11 @@ import { useNavigate } from "react-router-dom"; import Loader from "../components/Loader"; import { PageProps } from "../lib/types"; -import { useAccount, useWaitForTransactionReceipt, useSendTransaction } from "wagmi"; +import { useAccount, useWaitForTransactionReceipt, useWriteContract } from "wagmi"; import { useConnectModal, useAddRecentTransaction } from "@rainbow-me/rainbowkit" import { generateNetworkingKeys, HYPER_ACCOUNT_IMPL, DOTOS, tbaMintAbi } from "../abis"; -import { encodePacked, encodeFunctionData, stringToHex } from "viem"; +import { createPublicClient, encodePacked, http, stringToHex, BaseError, ContractFunctionRevertedError } from "viem"; +import { base } from 'viem/chains' interface RegisterOsNameProps extends PageProps { } @@ -23,7 +24,7 @@ function MintDotOsName({ let navigate = useNavigate(); let { openConnectModal } = useConnectModal(); - const { data: hash, sendTransaction, isPending, isError, error } = useSendTransaction({ + const { data: hash, writeContract, isPending, isError, error } = useWriteContract({ mutation: { onSuccess: (data) => { addRecentTransaction({ hash: data, description: `Mint ${hnsName}` }); @@ -74,31 +75,40 @@ function MintDotOsName({ // strip .os suffix const name = hnsName.replace(/\.os$/, ''); - const data = encodeFunctionData({ - abi: tbaMintAbi, - functionName: 'mint', - args: [ - address, - encodePacked(["bytes"], [stringToHex(name)]), - initCall, - HYPER_ACCOUNT_IMPL, - ], - }) - - // use data to write to contract -- do NOT use writeContract - // writeContract will NOT generate the correct selector for some reason - // probably THEIR bug.. no abi works + const publicClient = createPublicClient({ + chain: base, + transport: http(), + }); + try { - sendTransaction({ - to: DOTOS, - data: data, - gas: 1000000n, - }) - } catch (error) { - console.error('Failed to send transaction:', error) - setHasMinted(false); + const { request } = await publicClient.simulateContract({ + abi: tbaMintAbi, + address: DOTOS, + functionName: 'mint', + args: [ + address, + encodePacked(["bytes"], [stringToHex(name)]), + initCall, + HYPER_ACCOUNT_IMPL, + ], + account: address + }); + + writeContract(request); + } catch (err) { + if (err instanceof BaseError) { + const revertError = err.walk(err => err instanceof ContractFunctionRevertedError) + if (revertError instanceof ContractFunctionRevertedError) { + if (revertError?.data) { + const errorName = revertError.data.errorName; + const args = revertError.data.args; + console.log(`Reverted with ${errorName}`, args); + } + } + } + throw err; } - }, [direct, address, sendTransaction, setNetworkingKey, setIpAddress, setWsPort, setTcpPort, setRouters, openConnectModal, hnsName, hasMinted]) + }, [direct, address, writeContract, setNetworkingKey, setIpAddress, setWsPort, setTcpPort, setRouters, openConnectModal, hnsName, hasMinted]) useEffect(() => { if (address && !isPending && !isConfirming) { @@ -132,4 +142,4 @@ function MintDotOsName({ ); } -export default MintDotOsName; \ No newline at end of file +export default MintDotOsName; diff --git a/lib/Cargo.toml b/lib/Cargo.toml index 3141736d4..da2977f99 100644 --- a/lib/Cargo.toml +++ b/lib/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "lib" authors = ["Sybil Technologies AG"] -version = "1.2.1" +version = "1.2.2" edition = "2021" description = "A general-purpose sovereign cloud computing platform" homepage = "https://hyperware.ai" diff --git a/scripts/build-packages/src/main.rs b/scripts/build-packages/src/main.rs index de4d60450..7040b3237 100644 --- a/scripts/build-packages/src/main.rs +++ b/scripts/build-packages/src/main.rs @@ -1,5 +1,5 @@ use std::{ - collections::HashSet, + collections::{HashMap, HashSet}, io::{Cursor, Read, Write}, path::{Path, PathBuf}, }; @@ -44,6 +44,7 @@ fn build_and_zip_package( parent_pkg_path: &str, skip_frontend: bool, features: &str, + local_dependencies: Vec, ) -> anyhow::Result<(PathBuf, String, Vec)> { let rt = tokio::runtime::Runtime::new().unwrap(); rt.block_on(async { @@ -58,7 +59,7 @@ fn build_and_zip_package( None, None, None, - vec![], + local_dependencies, vec![], false, false, @@ -121,6 +122,15 @@ fn main() -> anyhow::Result<()> { let skip_frontend = matches.get_flag("SKIP_FRONTEND"); + let local_dependencies = fs::read(hyperdrive_dir.join("packages-local-dependencies.json"))?; + let local_dependencies: HashMap> = + serde_json::from_slice(&local_dependencies)?; + let mut local_dependencies: HashMap> = local_dependencies + .into_iter() + .map(|(key, val)| (key, val.iter().map(|f| packages_dir.join(f)).collect())) + //.map(|(key, val)| (key, val.iter().map(|f| packages_dir.join(f)).collect::>())) + .collect(); + let results: Vec)>> = fs::read_dir(&packages_dir)? .filter_map(|entry| { let entry_path = match entry { @@ -132,11 +142,19 @@ fn main() -> anyhow::Result<()> { // don't run on, e.g., `.DS_Store` return None; } + let local_dependency_array = if let Some(filename) = entry_path.file_name() { + local_dependencies + .remove(&filename.to_string_lossy().to_string()) + .unwrap_or_default() + } else { + vec![] + }; Some(build_and_zip_package( entry_path.clone(), child_pkg_path.to_str().unwrap(), skip_frontend, &features, + local_dependency_array, )) }) .collect();