From f1283e2420ed25711386f5c93e45a6428761978c Mon Sep 17 00:00:00 2001 From: sebasti810 Date: Tue, 10 Dec 2024 12:19:45 +0100 Subject: [PATCH 01/13] feat: initial commit uniffi bindings to support android and ios --- Cargo.lock | 340 +++++++++++++++++++++- Cargo.toml | 5 +- node-native/Cargo.toml | 24 ++ node-native/build-android.sh | 19 ++ node-native/build-ios.sh | 31 ++ node-native/src/bin/uniffi-bindgen.rs | 3 + node-native/src/lib.rs | 392 ++++++++++++++++++++++++++ node-native/src/types.rs | 346 +++++++++++++++++++++++ 8 files changed, 1152 insertions(+), 8 deletions(-) create mode 100644 node-native/Cargo.toml create mode 100755 node-native/build-android.sh create mode 100755 node-native/build-ios.sh create mode 100644 node-native/src/bin/uniffi-bindgen.rs create mode 100644 node-native/src/lib.rs create mode 100644 node-native/src/types.rs diff --git a/Cargo.lock b/Cargo.lock index 47caaaa7..6549e83c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -280,6 +280,47 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" +[[package]] +name = "askama" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b79091df18a97caea757e28cd2d5fda49c6cd4bd01ddffd7ff01ace0c0ad2c28" +dependencies = [ + "askama_derive", + "askama_escape", +] + +[[package]] +name = "askama_derive" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19fe8d6cb13c4714962c072ea496f3392015f0989b1a2847bb4b2d9effd71d83" +dependencies = [ + "askama_parser", + "basic-toml", + "mime", + "mime_guess", + "proc-macro2", + "quote", + "serde", + "syn 2.0.87", +] + +[[package]] +name = "askama_escape" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "619743e34b5ba4e9703bba34deac3427c72507c7159f5fd030aea8cac0cfe341" + +[[package]] +name = "askama_parser" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acb1161c6b64d1c3d83108213c2a2533a342ac225aabd0bda218278c2ddb00c0" +dependencies = [ + "nom", +] + [[package]] name = "asn1-rs" version = "0.6.1" @@ -537,6 +578,15 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" +[[package]] +name = "basic-toml" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "823388e228f614e9558c6804262db37960ec8821856535f5c3f59913140558f8" +dependencies = [ + "serde", +] + [[package]] name = "bech32" version = "0.11.0" @@ -577,6 +627,15 @@ dependencies = [ "web-time", ] +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -740,6 +799,38 @@ dependencies = [ "serde", ] +[[package]] +name = "camino" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo-platform" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.15.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eee4243f1f26fc7a42710e7439c149e2b10b05472f88090acce52632f231a73a" +dependencies = [ + "camino", + "cargo-platform", + "semver 1.0.23", + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "cc" version = "1.0.99" @@ -1538,6 +1629,15 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "fs-err" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88a41f105fe1d5b6b34b2055e3dc59bb79b46b48b2040b9e6c7b4b5de097aa41" +dependencies = [ + "autocfg", +] + [[package]] name = "function_name" version = "0.3.0" @@ -1805,6 +1905,17 @@ dependencies = [ "web-sys", ] +[[package]] +name = "goblin" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b363a30c165f666402fe6a3024d3bec7ebc898f96a4a23bd1c99f8dbf3f4f47" +dependencies = [ + "log", + "plain", + "scroll", +] + [[package]] name = "group" version = "0.13.0" @@ -2677,9 +2788,9 @@ checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" [[package]] name = "libp2p" -version = "0.54.0" +version = "0.54.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b06a2ceb55591d19a194956ce541329007b4e4ee87c5fdd59d64dc439286a36" +checksum = "bbbe80f9c7e00526cd6b838075b9c171919404a4732cb2fa8ece0a093223bfc4" dependencies = [ "bytes", "either", @@ -2914,9 +3025,9 @@ dependencies = [ [[package]] name = "libp2p-kad" -version = "0.46.0" +version = "0.46.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3fd4d149f0539e608d178b7cd1cfb0c1c6a8dc367eda2bc1cc81a28a1552161" +checksum = "ced237d0bd84bbebb7c2cad4c073160dacb4fe40534963c32ed6d4c6bb7702a3" dependencies = [ "arrayvec", "asynchronous-codec", @@ -2965,9 +3076,9 @@ dependencies = [ [[package]] name = "libp2p-metrics" -version = "0.14.2" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a70afa7692c81ee03e89c40d1e8638d634f18baef6aeeea30fd245edfae4d3fd" +checksum = "77ebafa94a717c8442d8db8d3ae5d1c6a15e30f2d347e0cd31d057ca72e42566" dependencies = [ "futures", "libp2p-core 0.42.0", @@ -3664,6 +3775,21 @@ dependencies = [ "unsigned-varint 0.7.2", ] +[[package]] +name = "native" +version = "0.1.0" +dependencies = [ + "celestia-types", + "libp2p", + "lumina-node", + "redb", + "serde_json", + "tendermint", + "thiserror", + "tokio", + "uniffi", +] + [[package]] name = "netlink-packet-core" version = "0.4.2" @@ -4081,6 +4207,12 @@ dependencies = [ "spki", ] +[[package]] +name = "plain" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" + [[package]] name = "polling" version = "3.7.1" @@ -4955,6 +5087,26 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "scroll" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ab8598aa408498679922eff7fa985c25d58a90771bd6be794434c5277eab1a6" +dependencies = [ + "scroll_derive", +] + +[[package]] +name = "scroll_derive" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f81c2fde025af7e69b1d1420531c8a8811ca898919db177141a85313b1cb932" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + [[package]] name = "sec1" version = "0.7.3" @@ -5007,6 +5159,9 @@ name = "semver" version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" +dependencies = [ + "serde", +] [[package]] name = "semver-parser" @@ -5179,6 +5334,15 @@ dependencies = [ "dirs", ] +[[package]] +name = "signal-hook-registry" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +dependencies = [ + "libc", +] + [[package]] name = "signature" version = "2.2.0" @@ -5189,6 +5353,12 @@ dependencies = [ "rand_core", ] +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + [[package]] name = "slab" version = "0.4.9" @@ -5207,6 +5377,12 @@ dependencies = [ "serde", ] +[[package]] +name = "smawk" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" + [[package]] name = "snow" version = "0.9.6" @@ -5465,6 +5641,15 @@ dependencies = [ "time", ] +[[package]] +name = "textwrap" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" +dependencies = [ + "smawk", +] + [[package]] name = "thiserror" version = "1.0.61" @@ -5563,7 +5748,9 @@ dependencies = [ "libc", "mio", "num_cpus", + "parking_lot", "pin-project-lite", + "signal-hook-registry", "socket2", "tokio-macros", "windows-sys 0.48.0", @@ -5616,6 +5803,15 @@ dependencies = [ "tokio", ] +[[package]] +name = "toml" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "serde", +] + [[package]] name = "toml_datetime" version = "0.6.6" @@ -5886,6 +6082,124 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" +[[package]] +name = "uniffi" +version = "0.28.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cb08c58c7ed7033150132febe696bef553f891b1ede57424b40d87a89e3c170" +dependencies = [ + "anyhow", + "camino", + "cargo_metadata", + "clap", + "uniffi_bindgen", + "uniffi_core", + "uniffi_macros", +] + +[[package]] +name = "uniffi_bindgen" +version = "0.28.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cade167af943e189a55020eda2c314681e223f1e42aca7c4e52614c2b627698f" +dependencies = [ + "anyhow", + "askama", + "camino", + "cargo_metadata", + "fs-err", + "glob", + "goblin", + "heck 0.5.0", + "once_cell", + "paste", + "serde", + "textwrap", + "toml", + "uniffi_meta", + "uniffi_udl", +] + +[[package]] +name = "uniffi_checksum_derive" +version = "0.28.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "802d2051a700e3ec894c79f80d2705b69d85844dafbbe5d1a92776f8f48b563a" +dependencies = [ + "quote", + "syn 2.0.87", +] + +[[package]] +name = "uniffi_core" +version = "0.28.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc7687007d2546c454d8ae609b105daceb88175477dac280707ad6d95bcd6f1f" +dependencies = [ + "anyhow", + "bytes", + "log", + "once_cell", + "paste", + "static_assertions", +] + +[[package]] +name = "uniffi_macros" +version = "0.28.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12c65a5b12ec544ef136693af8759fb9d11aefce740fb76916721e876639033b" +dependencies = [ + "bincode", + "camino", + "fs-err", + "once_cell", + "proc-macro2", + "quote", + "serde", + "syn 2.0.87", + "toml", + "uniffi_meta", +] + +[[package]] +name = "uniffi_meta" +version = "0.28.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a74ed96c26882dac1ca9b93ca23c827e284bacbd7ec23c6f0b0372f747d59e4" +dependencies = [ + "anyhow", + "bytes", + "siphasher", + "uniffi_checksum_derive", +] + +[[package]] +name = "uniffi_testing" +version = "0.28.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6f984f0781f892cc864a62c3a5c60361b1ccbd68e538e6c9fbced5d82268ac" +dependencies = [ + "anyhow", + "camino", + "cargo_metadata", + "fs-err", + "once_cell", +] + +[[package]] +name = "uniffi_udl" +version = "0.28.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "037820a4cfc4422db1eaa82f291a3863c92c7d1789dc513489c36223f9b4cdfc" +dependencies = [ + "anyhow", + "textwrap", + "uniffi_meta", + "uniffi_testing", + "weedle2", +] + [[package]] name = "universal-hash" version = "0.5.1" @@ -6120,6 +6434,15 @@ dependencies = [ "rustls-pki-types", ] +[[package]] +name = "weedle2" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "998d2c24ec099a87daf9467808859f9d82b61f1d9c9701251aea037f514eae0e" +dependencies = [ + "nom", +] + [[package]] name = "widestring" version = "1.1.0" @@ -6545,3 +6868,8 @@ dependencies = [ "quote", "syn 2.0.87", ] + +[[patch.unused]] +name = "system-configuration" +version = "0.6.1" +source = "git+https://github.com/mullvad/system-configuration-rs?tag=v0.6.1#c7a1626d79410a2f35e0361de952b6076a33d95c" diff --git a/Cargo.toml b/Cargo.toml index 01256887..21ef9c30 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [workspace] resolver = "2" -members = ["cli", "grpc", "node", "node-wasm", "proto", "rpc", "types"] +members = ["cli", "grpc", "node", "node-wasm", "node-native", "proto", "rpc", "types"] [workspace.dependencies] blockstore = "0.7.1" @@ -13,7 +13,7 @@ celestia-types = { version = "0.9.0", path = "types", default-features = false } tendermint = { version = "0.40.0", default-features = false } tendermint-proto = "0.40.0" -libp2p = "0.54.0" +libp2p = "0.54.1" nmt-rs = "0.2.1" prost = "0.13.3" prost-build = "0.13.3" @@ -27,6 +27,7 @@ prost-types = "0.13.3" #libp2p = { path = "../../rust-libp2p/libp2p" } #libp2p-core = { path = "../../rust-libp2p/core" } #libp2p-swarm = { path = "../../rust-libp2p/swarm" } +system-configuration = { git = "https://github.com/mullvad/system-configuration-rs", tag = "v0.6.1" } # Uncomment this if you need debug symbols in release. # Also check node-wasm's `Cargo.toml`. diff --git a/node-native/Cargo.toml b/node-native/Cargo.toml new file mode 100644 index 00000000..7043947c --- /dev/null +++ b/node-native/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "native" +version = "0.1.0" +edition = "2021" +description = "Mobile bindings for Lumina node" + +[lib] +crate-type = ["lib", "staticlib", "cdylib"] + +[[bin]] +name = "uniffi-bindgen" +path = "./src/bin/uniffi-bindgen.rs" + +[dependencies] +lumina-node.workspace = true +celestia-types.workspace = true +tendermint.workspace = true +libp2p.workspace = true + +uniffi = { version = "0.28.3", features = ["bindgen", "cli"] } +tokio = { version = "1.0", features = ["full"] } +redb = "2.1.1" +thiserror = "1.0.61" +serde_json = "1.0.64" \ No newline at end of file diff --git a/node-native/build-android.sh b/node-native/build-android.sh new file mode 100755 index 00000000..335998e1 --- /dev/null +++ b/node-native/build-android.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +cargo build -p native + +rustup target add \ + aarch64-linux-android \ + armv7-linux-androideabi \ + x86_64-linux-android \ + i686-linux-android + +cargo ndk -o ./app/src/main/jniLibs \ + --manifest-path ./Cargo.toml \ + -t armeabi-v7a \ + -t arm64-v8a \ + -t x86 \ + -t x86_64 \ + build --release + +cargo run --bin uniffi-bindgen generate --library ../target/debug/libnative.dylib --language kotlin --out-dir ./app/src/main/java/tech/forgen/native/rust \ No newline at end of file diff --git a/node-native/build-ios.sh b/node-native/build-ios.sh new file mode 100755 index 00000000..613af599 --- /dev/null +++ b/node-native/build-ios.sh @@ -0,0 +1,31 @@ +#!/bin/bash + +cargo build -p native + +mkdir -p ./bindings + +cargo run --bin uniffi-bindgen generate --library ../target/debug/libnative.dylib --language swift --out-dir ./bindings + +for TARGET in \ + aarch64-apple-darwin \ + aarch64-apple-ios \ + aarch64-apple-ios-sim \ + x86_64-apple-darwin \ + x86_64-apple-ios +do + rustup target add $TARGET + cargo build --release --target=$TARGET +done + +mv ./bindings/nativeFFI.modulemap ./bindings/module.modulemap + +rm ./ios/Native.swift +mv ./bindings/native.swift ./ios/Native.swift + +rm -rf "ios/Native.xcframework" +xcodebuild -create-xcframework \ + -library ../target/aarch64-apple-ios-sim/release/libnative.a -headers ./bindings \ + -library ../target/aarch64-apple-ios/release/libnative.a -headers ./bindings \ + -output "ios/Native.xcframework" + +rm -rf bindings \ No newline at end of file diff --git a/node-native/src/bin/uniffi-bindgen.rs b/node-native/src/bin/uniffi-bindgen.rs new file mode 100644 index 00000000..f6cff6cf --- /dev/null +++ b/node-native/src/bin/uniffi-bindgen.rs @@ -0,0 +1,3 @@ +fn main() { + uniffi::uniffi_bindgen_main() +} diff --git a/node-native/src/lib.rs b/node-native/src/lib.rs new file mode 100644 index 00000000..4b813ab6 --- /dev/null +++ b/node-native/src/lib.rs @@ -0,0 +1,392 @@ +mod types; + +use celestia_types::ExtendedHeader; +use libp2p::identity::Keypair; +use lumina_node::{ + blockstore::RedbBlockstore, + events::{EventSubscriber, TryRecvError}, + network::{canonical_network_bootnodes, network_id}, + store::RedbStore, + Node, NodeConfig, NodeError, +}; +use std::{path::PathBuf, str::FromStr, sync::Arc, time::Duration}; +use tendermint::hash::Hash; +use thiserror::Error; +use tokio::{runtime::Runtime, sync::Mutex}; +use types::{Network, NetworkInfo, NodeEvent, PeerId, PeerTrackerInfo, SyncingInfo}; +use uniffi::Object; + +pub type Result = std::result::Result; + +#[cfg(target_os = "ios")] +fn get_base_path() -> Result { + std::env::var("HOME") + .map(PathBuf::from) + .map(|p| p.join("Library/Application Support/lumina")) + .map_err(|e| LuminaError::StorageError { + message: format!("Could not get HOME directory: {}", e), + }) +} + +#[cfg(target_os = "android")] +fn get_base_path() -> Result { + // On Android, we'll use the app's files directory passed from the platform + std::env::var("LUMINA_DATA_DIR") + .map(PathBuf::from) + .map_err(|e| LuminaError::StorageError { + message: format!("Could not get LUMINA_DATA_DIR: {}", e), + }) +} + +#[cfg(not(any(target_os = "ios", target_os = "android")))] +fn get_base_path() -> Result { + Err(LuminaError::StorageError { + message: "Unsupported platform".to_string(), + }) +} + +#[derive(Error, Debug, uniffi::Error)] +pub enum LuminaError { + #[error("Node is not running")] + NodeNotRunning, + #[error("Network error: {message}")] + NetworkError { message: String }, + #[error("Storage error: {message}")] + StorageError { message: String }, + #[error("Node is already running")] + AlreadyRunning, + #[error("Lock error")] + LockError, + #[error("Invalid hash format: {message}")] + InvalidHash { message: String }, + #[error("Invalid header format: {message}")] + InvalidHeader { message: String }, + #[error("Storage initialization failed: {message}")] + StorageInit { message: String }, +} + +impl From for LuminaError { + fn from(error: NodeError) -> Self { + LuminaError::NetworkError { + message: error.to_string(), + } + } +} + +#[derive(Object)] +pub struct LuminaNode { + node: Arc>>>, + runtime: Runtime, + network: Network, + events_subscriber: Arc>>, +} + +#[uniffi::export] +impl LuminaNode { + #[uniffi::constructor] + pub fn new(network: Network) -> Result> { + let runtime = Runtime::new().map_err(|e| LuminaError::NetworkError { + message: e.to_string(), + })?; + + Ok(Arc::new(Self { + node: Arc::new(Mutex::new(None)), + runtime, + network, + events_subscriber: Arc::new(Mutex::new(None)), + })) + } + + pub fn start(&self) -> Result { + self.runtime.block_on(async { + let mut node_guard = self.node.lock().await; + + if node_guard.is_some() { + return Err(LuminaError::AlreadyRunning); + } + + let network_id = network_id(self.network.into()); + + let base_path = get_base_path()?; + + std::fs::create_dir_all(&base_path).map_err(|e| LuminaError::StorageError { + message: format!("Failed to create data directory: {}", e), + })?; + + let store_path = base_path.join(format!("store-{}", network_id)); + let db = Arc::new(redb::Database::create(&store_path).map_err(|e| { + LuminaError::StorageInit { + message: format!("Failed to create database: {}", e), + } + })?); + + let store = RedbStore::new(db.clone()) + .await + .map_err(|e| LuminaError::StorageInit { + message: format!("Failed to initialize store: {}", e), + })?; + + let blockstore = RedbBlockstore::new(db); + + let p2p_bootnodes = + canonical_network_bootnodes(self.network.into()).collect::>(); + + let p2p_local_keypair = Keypair::generate_ed25519(); + + let config = NodeConfig { + network_id: network_id.to_string(), + p2p_bootnodes, + p2p_local_keypair, + p2p_listen_on: vec![], + sync_batch_size: 128, + custom_syncing_window: Some(Duration::from_secs(60 * 60 * 24)), + store, + blockstore, + }; + + let new_node = Node::new(config) + .await + .map_err(|e| LuminaError::NetworkError { + message: e.to_string(), + })?; + + let subscriber = new_node.event_subscriber(); + let mut events_guard = self.events_subscriber.lock().await; + *events_guard = Some(subscriber); + + *node_guard = Some(new_node); + Ok(true) + }) + } + + pub fn stop(&self) -> Result<()> { + self.runtime.block_on(async { + let mut node_guard = self.node.lock().await; + let node = node_guard.take().ok_or(LuminaError::NodeNotRunning)?; + node.stop().await; + Ok(()) + }) + } + + pub fn is_running(&self) -> bool { + self.runtime + .block_on(async { self.node.lock().await.is_some() }) + } + + pub fn local_peer_id(&self) -> Result { + self.runtime.block_on(async { + let node_guard = self.node.lock().await; + let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; + Ok(node.local_peer_id().to_string()) + }) + } + + pub fn peer_tracker_info(&self) -> Result { + self.runtime.block_on(async { + let node_guard = self.node.lock().await; + let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; + Ok(node.peer_tracker_info().into()) + }) + } + + pub fn wait_connected(&self) -> Result<()> { + self.runtime.block_on(async { + let node_guard = self.node.lock().await; + let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; + Ok(node.wait_connected().await?) + }) + } + + pub fn wait_connected_trusted(&self) -> Result<()> { + self.runtime.block_on(async { + let node_guard = self.node.lock().await; + let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; + Ok(node.wait_connected_trusted().await?) + }) + } + + pub fn network_info(&self) -> Result { + self.runtime.block_on(async { + let node_guard = self.node.lock().await; + let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; + let info = node.network_info().await?; + Ok(info.into()) + }) + } + + pub fn listeners(&self) -> Result> { + self.runtime.block_on(async { + let node_guard = self.node.lock().await; + let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; + let listeners = node.listeners().await?; + Ok(listeners.into_iter().map(|l| l.to_string()).collect()) + }) + } + + pub fn connected_peers(&self) -> Result> { + self.runtime.block_on(async { + let node_guard = self.node.lock().await; + let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; + let peers = node.connected_peers().await?; + Ok(peers.into_iter().map(PeerId::from).collect()) + }) + } + + pub fn set_peer_trust(&self, peer_id: PeerId, is_trusted: bool) -> Result<()> { + self.runtime.block_on(async { + let node_guard = self.node.lock().await; + let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; + let peer_id = peer_id + .to_libp2p() + .map_err(|e| LuminaError::NetworkError { message: e })?; + Ok(node.set_peer_trust(peer_id, is_trusted).await?) + }) + } + + pub fn request_head_header(&self) -> Result { + self.runtime.block_on(async { + let node_guard = self.node.lock().await; + let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; + let header = node.request_head_header().await?; + Ok(header.to_string()) //if extended header is needed, we need a wrapper + }) + } + + pub fn request_header_by_hash(&self, hash: String) -> Result { + self.runtime.block_on(async { + let node_guard = self.node.lock().await; + let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; + let hash = Hash::from_str(&hash).map_err(|e| LuminaError::InvalidHash { + message: e.to_string(), + })?; + let header = node.request_header_by_hash(&hash).await?; + Ok(header.to_string()) //if extended header is needed, we need a wrapper + }) + } + + pub fn request_header_by_height(&self, height: u64) -> Result { + self.runtime.block_on(async { + let node_guard = self.node.lock().await; + let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; + let header = node.request_header_by_height(height).await?; + Ok(header.to_string()) + }) + } + + pub fn request_verified_headers( + &self, + from: String, // serialized header like its done for WASM + amount: u64, + ) -> Result> { + self.runtime.block_on(async { + let node_guard = self.node.lock().await; + let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; + let from: ExtendedHeader = + serde_json::from_str(&from).map_err(|e| LuminaError::InvalidHeader { + message: format!("Invalid header JSON: {}", e), + })?; + let headers = node.request_verified_headers(&from, amount).await?; + Ok(headers.into_iter().map(|h| h.to_string()).collect()) + }) + } + + pub fn syncer_info(&self) -> Result { + self.runtime.block_on(async { + let node_guard = self.node.lock().await; + let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; + let info = node.syncer_info().await?; + Ok(info.into()) + }) + } + + pub fn get_network_head_header(&self) -> Result { + self.runtime.block_on(async { + let node_guard = self.node.lock().await; + let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; + let header = node.get_network_head_header().await?; + header.map_or( + // todo: better error handling, its undefined in wasm + Err(LuminaError::NetworkError { + message: "No network head header available".to_string(), + }), + |h| Ok(h.to_string()), + ) + }) + } + + pub fn get_local_head_header(&self) -> Result { + self.runtime.block_on(async { + let node_guard = self.node.lock().await; + let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; + let header = node.get_local_head_header().await?; + Ok(header.to_string()) + }) + } + + pub fn get_header_by_hash(&self, hash: String) -> Result { + self.runtime.block_on(async { + let node_guard = self.node.lock().await; + let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; + let hash = Hash::from_str(&hash).map_err(|e| LuminaError::InvalidHash { + message: e.to_string(), + })?; + let header = node.get_header_by_hash(&hash).await?; + Ok(header.to_string()) + }) + } + + pub fn get_header_by_height(&self, height: u64) -> Result { + self.runtime.block_on(async { + let node_guard = self.node.lock().await; + let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; + let header = node.get_header_by_height(height).await?; + Ok(header.to_string()) + }) + } + + pub fn get_headers( + &self, + start_height: Option, + end_height: Option, + ) -> Result> { + self.runtime.block_on(async { + let node_guard = self.node.lock().await; + let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; + + let headers = match (start_height, end_height) { + (None, None) => node.get_headers(..).await, + (Some(start), None) => node.get_headers(start..).await, + (None, Some(end)) => node.get_headers(..=end).await, + (Some(start), Some(end)) => node.get_headers(start..=end).await, + }?; + + Ok(headers.into_iter().map(|h| h.to_string()).collect()) + }) + } + + pub fn get_sampling_metadata(&self, height: u64) -> Result> { + self.runtime.block_on(async { + let node_guard = self.node.lock().await; + let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; + let metadata = node.get_sampling_metadata(height).await?; + Ok(metadata.map(|m| serde_json::to_string(&m).unwrap())) + }) + } + + pub fn events_channel(&self) -> Result> { + self.runtime.block_on(async { + let mut events_guard = self.events_subscriber.lock().await; + let subscriber = events_guard.as_mut().ok_or(LuminaError::NodeNotRunning)?; + + match subscriber.try_recv() { + Ok(event) => Ok(Some(event.event.into())), + Err(TryRecvError::Empty) => Ok(None), + Err(e) => Err(LuminaError::NetworkError { + message: e.to_string(), + }), + } + }) + } +} + +uniffi::setup_scaffolding!(); diff --git a/node-native/src/types.rs b/node-native/src/types.rs new file mode 100644 index 00000000..d4bd7297 --- /dev/null +++ b/node-native/src/types.rs @@ -0,0 +1,346 @@ +use libp2p::swarm::ConnectionCounters as Libp2pConnectionCounters; +use libp2p::swarm::NetworkInfo as Libp2pNetworkInfo; +use libp2p::PeerId as Libp2pPeerId; +use lumina_node::block_ranges::BlockRange as LuminaBlockRange; +use lumina_node::events::{NodeEvent as LuminaNodeEvent, NodeEventInfo as LuminaNodeEventInfo}; +use lumina_node::network; +use lumina_node::node::PeerTrackerInfo as LuminaPeerTrackerInfo; +use lumina_node::node::SyncingInfo as LuminaSyncingInfo; +use std::str::FromStr; +use std::time::SystemTime; +use uniffi::{Enum, Record}; + +/// Supported Celestia networks. +#[derive(Debug, Default, Clone, Copy, Enum)] +pub enum Network { + /// Celestia mainnet. + #[default] + Mainnet, + /// Arabica testnet. + Arabica, + /// Mocha testnet. + Mocha, + /// Private local network. + Private, +} + +// From implementation for converting between Lumina and Uniffi types +impl From for network::Network { + fn from(network: Network) -> Self { + match network { + Network::Mainnet => network::Network::Mainnet, + Network::Arabica => network::Network::Arabica, + Network::Mocha => network::Network::Mocha, + Network::Private => network::Network::Private, + } + } +} + +/// Statistics of the connected peers +#[derive(Debug, Clone, Default, Record)] +pub struct PeerTrackerInfo { + /// Number of the connected peers. + pub num_connected_peers: u64, + /// Number of the connected trusted peers. + pub num_connected_trusted_peers: u64, +} + +impl From for PeerTrackerInfo { + fn from(info: LuminaPeerTrackerInfo) -> Self { + Self { + num_connected_peers: info.num_connected_peers, + num_connected_trusted_peers: info.num_connected_trusted_peers, + } + } +} + +#[derive(Record)] +pub struct NetworkInfo { + pub num_peers: u32, + pub connection_counters: ConnectionCounters, +} + +#[derive(Record)] +pub struct ConnectionCounters { + pub num_connections: u32, + pub num_pending: u32, + pub num_pending_incoming: u32, + pub num_pending_outgoing: u32, + pub num_established: u32, + pub num_established_incoming: u32, + pub num_established_outgoing: u32, +} + +impl From for NetworkInfo { + fn from(info: Libp2pNetworkInfo) -> Self { + Self { + num_peers: info.num_peers() as u32, + connection_counters: info.connection_counters().into(), + } + } +} + +impl From<&Libp2pConnectionCounters> for ConnectionCounters { + fn from(counters: &Libp2pConnectionCounters) -> Self { + Self { + num_connections: counters.num_connections(), + num_pending: counters.num_pending(), + num_pending_incoming: counters.num_pending_incoming(), + num_pending_outgoing: counters.num_pending_outgoing(), + num_established: counters.num_established(), + num_established_incoming: counters.num_established_incoming(), + num_established_outgoing: counters.num_established_outgoing(), + } + } +} + +#[derive(Record)] +pub struct BlockRange { + pub start: u64, + pub end: u64, +} + +impl From for BlockRange { + fn from(range: LuminaBlockRange) -> Self { + Self { + start: *range.start(), + end: *range.end(), + } + } +} + +#[derive(Record)] +pub struct SyncingInfo { + pub stored_headers: Vec, + pub subjective_head: u64, +} + +impl From for SyncingInfo { + fn from(info: LuminaSyncingInfo) -> Self { + Self { + stored_headers: info + .stored_headers + .into_inner() + .into_iter() + .map(BlockRange::from) + .collect(), + subjective_head: info.subjective_head, + } + } +} + +#[derive(Record, Clone, Debug)] +pub struct PeerId { + // Store as base58 string for now + pub peer_id: String, +} + +impl PeerId { + pub fn to_libp2p(&self) -> Result { + Libp2pPeerId::from_str(&self.peer_id).map_err(|e| format!("Invalid peer ID format: {}", e)) + } + + pub fn from_libp2p(peer_id: &Libp2pPeerId) -> Self { + Self { + peer_id: peer_id.to_string(), + } + } +} + +impl From for PeerId { + fn from(peer_id: Libp2pPeerId) -> Self { + Self { + peer_id: peer_id.to_string(), + } + } +} + +#[derive(Record)] +pub struct ShareCoordinate { + pub row: u16, + pub column: u16, +} + +#[derive(uniffi::Enum)] +pub enum NodeEvent { + ConnectingToBootnodes, + PeerConnected { + id: PeerId, + trusted: bool, + }, + PeerDisconnected { + id: PeerId, + trusted: bool, + }, + SamplingStarted { + height: u64, + square_width: u16, + shares: Vec, + }, + ShareSamplingResult { + height: u64, + square_width: u16, + row: u16, + column: u16, + accepted: bool, + }, + SamplingFinished { + height: u64, + accepted: bool, + took_ms: u64, + }, + FatalDaserError { + error: String, + }, + AddedHeaderFromHeaderSub { + height: u64, + }, + FetchingHeadHeaderStarted, + FetchingHeadHeaderFinished { + height: u64, + took_ms: u64, + }, + FetchingHeadersStarted { + from_height: u64, + to_height: u64, + }, + FetchingHeadersFinished { + from_height: u64, + to_height: u64, + took_ms: u64, + }, + FetchingHeadersFailed { + from_height: u64, + to_height: u64, + error: String, + took_ms: u64, + }, + FatalSyncerError { + error: String, + }, + PrunedHeaders { + to_height: u64, + }, + FatalPrunerError { + error: String, + }, + NetworkCompromised, + NodeStopped, +} + +impl From for NodeEvent { + fn from(event: LuminaNodeEvent) -> Self { + match event { + LuminaNodeEvent::ConnectingToBootnodes => NodeEvent::ConnectingToBootnodes, + LuminaNodeEvent::PeerConnected { id, trusted } => NodeEvent::PeerConnected { + id: PeerId::from_libp2p(&id), + trusted, + }, + LuminaNodeEvent::PeerDisconnected { id, trusted } => NodeEvent::PeerDisconnected { + id: PeerId::from_libp2p(&id), + trusted, + }, + LuminaNodeEvent::SamplingStarted { + height, + square_width, + shares, + } => NodeEvent::SamplingStarted { + height, + square_width, + shares: shares + .into_iter() + .map(|(row, col)| ShareCoordinate { row, column: col }) + .collect(), + }, + LuminaNodeEvent::ShareSamplingResult { + height, + square_width, + row, + column, + accepted, + } => NodeEvent::ShareSamplingResult { + height, + square_width, + row, + column, + accepted, + }, + LuminaNodeEvent::SamplingFinished { + height, + accepted, + took, + } => NodeEvent::SamplingFinished { + height, + accepted, + took_ms: took.as_millis() as u64, + }, + LuminaNodeEvent::FatalDaserError { error } => NodeEvent::FatalDaserError { error }, + LuminaNodeEvent::AddedHeaderFromHeaderSub { height } => { + NodeEvent::AddedHeaderFromHeaderSub { height } + } + LuminaNodeEvent::FetchingHeadHeaderStarted => NodeEvent::FetchingHeadHeaderStarted, + LuminaNodeEvent::FetchingHeadHeaderFinished { height, took } => { + NodeEvent::FetchingHeadHeaderFinished { + height, + took_ms: took.as_millis() as u64, + } + } + LuminaNodeEvent::FetchingHeadersStarted { + from_height, + to_height, + } => NodeEvent::FetchingHeadersStarted { + from_height, + to_height, + }, + LuminaNodeEvent::FetchingHeadersFinished { + from_height, + to_height, + took, + } => NodeEvent::FetchingHeadersFinished { + from_height, + to_height, + took_ms: took.as_millis() as u64, + }, + LuminaNodeEvent::FetchingHeadersFailed { + from_height, + to_height, + error, + took, + } => NodeEvent::FetchingHeadersFailed { + from_height, + to_height, + error, + took_ms: took.as_millis() as u64, + }, + LuminaNodeEvent::FatalSyncerError { error } => NodeEvent::FatalSyncerError { error }, + LuminaNodeEvent::PrunedHeaders { to_height } => NodeEvent::PrunedHeaders { to_height }, + LuminaNodeEvent::FatalPrunerError { error } => NodeEvent::FatalPrunerError { error }, + LuminaNodeEvent::NetworkCompromised => NodeEvent::NetworkCompromised, + LuminaNodeEvent::NodeStopped => NodeEvent::NodeStopped, + _ => panic!("Unknown event: {:?}", event), + } + } +} + +#[derive(Record)] +pub struct NodeEventInfo { + pub event: NodeEvent, + pub timestamp: u64, // Unix timestamp in milliseconds for now + pub file_path: String, + pub file_line: u32, +} + +impl From for NodeEventInfo { + fn from(info: LuminaNodeEventInfo) -> Self { + Self { + event: info.event.into(), + timestamp: info + .time + .duration_since(SystemTime::UNIX_EPOCH) + .unwrap_or_default() + .as_millis() as u64, + file_path: info.file_path.to_string(), + file_line: info.file_line, + } + } +} From f84f3479b114fa8f65857bd1ba733bd919b31b45 Mon Sep 17 00:00:00 2001 From: sebasti810 Date: Tue, 10 Dec 2024 16:51:40 +0100 Subject: [PATCH 02/13] refac: using uniffi tokio feature to handle runtime --- Cargo.lock | 1495 +++++++++++++++++++------------------- node-native/Cargo.toml | 2 +- node-native/build-ios.sh | 1 + node-native/src/lib.rs | 424 +++++------ 4 files changed, 950 insertions(+), 972 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6549e83c..294562e5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,18 +4,18 @@ version = 4 [[package]] name = "addr2line" -version = "0.22.0" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" dependencies = [ "gimli", ] [[package]] -name = "adler" -version = "1.0.2" +name = "adler2" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" [[package]] name = "aead" @@ -52,18 +52,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "ahash" -version = "0.8.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" -dependencies = [ - "cfg-if", - "once_cell", - "version_check", - "zerocopy", -] - [[package]] name = "aho-corasick" version = "1.1.3" @@ -75,15 +63,15 @@ dependencies = [ [[package]] name = "allocator-api2" -version = "0.2.18" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] name = "alloy-rlp" -version = "0.3.5" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b155716bab55763c95ba212806cf43d05bcc70e5f35b02bad20cf5ec7fe11fed" +checksum = "f542548a609dca89fcd72b3b9f355928cf844d4363c5eed9c5273a3dd225e097" dependencies = [ "arrayvec", "bytes", @@ -91,9 +79,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.14" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" dependencies = [ "anstyle", "anstyle-parse", @@ -106,43 +94,43 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.7" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" [[package]] name = "anstyle-parse" -version = "0.2.4" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.0" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.3" +version = "3.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" +checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" dependencies = [ "anstyle", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "anyhow" -version = "1.0.86" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" +checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7" [[package]] name = "ark-ff" @@ -155,7 +143,7 @@ dependencies = [ "ark-serialize 0.3.0", "ark-std 0.3.0", "derivative", - "num-bigint 0.4.5", + "num-bigint 0.4.6", "num-traits", "paste", "rustc_version 0.3.3", @@ -175,10 +163,10 @@ dependencies = [ "derivative", "digest 0.10.7", "itertools 0.10.5", - "num-bigint 0.4.5", + "num-bigint 0.4.6", "num-traits", "paste", - "rustc_version 0.4.0", + "rustc_version 0.4.1", "zeroize", ] @@ -208,7 +196,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db2fd794a08ccb318058009eefdf15bcaaaaf6f8161eb3345f907222bac38b20" dependencies = [ - "num-bigint 0.4.5", + "num-bigint 0.4.6", "num-traits", "quote", "syn 1.0.109", @@ -220,7 +208,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" dependencies = [ - "num-bigint 0.4.5", + "num-bigint 0.4.6", "num-traits", "proc-macro2", "quote", @@ -245,7 +233,7 @@ checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" dependencies = [ "ark-std 0.4.0", "digest 0.10.7", - "num-bigint 0.4.5", + "num-bigint 0.4.6", ] [[package]] @@ -270,15 +258,15 @@ dependencies = [ [[package]] name = "arrayref" -version = "0.3.7" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" [[package]] name = "arrayvec" -version = "0.7.4" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" [[package]] name = "askama" @@ -303,7 +291,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -323,9 +311,9 @@ dependencies = [ [[package]] name = "asn1-rs" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ad1373757efa0f70ec53939aabc7152e1591cb485208052993070ac8d2429d" +checksum = "5493c3bedbacf7fd7382c6346bbd66687d12bbaad3a89a2d2c303ee6cf20b048" dependencies = [ "asn1-rs-derive", "asn1-rs-impl", @@ -333,19 +321,19 @@ dependencies = [ "nom", "num-traits", "rusticata-macros", - "thiserror", + "thiserror 1.0.69", "time", ] [[package]] name = "asn1-rs-derive" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7378575ff571966e99a744addeff0bff98b8ada0dedf1956d59e634db95eaac1" +checksum = "965c2d33e53cb6b267e148a4cb0760bc01f4904c1cd4bb4002a085bb016d1490" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", "synstructure", ] @@ -357,14 +345,27 @@ checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", +] + +[[package]] +name = "async-compat" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bab94bde396a3f7b4962e396fdad640e241ed797d4d8d77fc8c237d14c58fc0" +dependencies = [ + "futures-core", + "futures-io", + "once_cell", + "pin-project-lite", + "tokio", ] [[package]] name = "async-io" -version = "2.3.3" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d6baa8f0178795da0e71bc42c9e5d13261aac7ee549853162e66a241ba17964" +checksum = "43a2b323ccce0a1d90b449fd71f2a06ca7faa7c54c2751f06c9bd851fc061059" dependencies = [ "async-lock", "cfg-if", @@ -376,7 +377,7 @@ dependencies = [ "rustix", "slab", "tracing", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -409,18 +410,18 @@ checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] name = "async-trait" -version = "0.1.80" +version = "0.1.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" +checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -461,27 +462,27 @@ checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] name = "autocfg" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "axum" -version = "0.7.5" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a6c9af12842a67734c9a2e355436e5d03b22383ed60cf13cd0c18fbfe3dcbcf" +checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f" dependencies = [ "async-trait", "axum-core", "bytes", "futures-util", - "http 1.1.0", - "http-body 1.0.0", + "http 1.2.0", + "http-body 1.0.1", "http-body-util", "hyper 1.5.1", "hyper-util", @@ -496,9 +497,9 @@ dependencies = [ "serde_json", "serde_path_to_error", "serde_urlencoded", - "sync_wrapper 1.0.1", + "sync_wrapper 1.0.2", "tokio", - "tower", + "tower 0.5.1", "tower-layer", "tower-service", "tracing", @@ -506,20 +507,20 @@ dependencies = [ [[package]] name = "axum-core" -version = "0.4.3" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a15c63fd72d41492dc4f497196f5da1fb04fb7529e631d73630d1b491e47a2e3" +checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199" dependencies = [ "async-trait", "bytes", "futures-util", - "http 1.1.0", - "http-body 1.0.0", + "http 1.2.0", + "http-body 1.0.1", "http-body-util", "mime", "pin-project-lite", "rustversion", - "sync_wrapper 0.1.2", + "sync_wrapper 1.0.2", "tower-layer", "tower-service", "tracing", @@ -541,17 +542,17 @@ dependencies = [ [[package]] name = "backtrace" -version = "0.3.73" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" dependencies = [ "addr2line", - "cc", "cfg-if", "libc", "miniz_oxide", "object", "rustc-demangle", + "windows-targets 0.52.6", ] [[package]] @@ -619,7 +620,7 @@ dependencies = [ "multihash-codetable", "quick-protobuf", "smallvec", - "thiserror", + "thiserror 1.0.69", "time", "tracing", "unsigned-varint 0.8.0", @@ -644,9 +645,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" [[package]] name = "bitvec" @@ -693,9 +694,9 @@ dependencies = [ [[package]] name = "blake3" -version = "1.5.1" +version = "1.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30cca6d3674597c30ddf2c587bf8d9d65c9a84d2326d941cc79c9842dfe0ef52" +checksum = "b8ee0c1824c4dea5b5f81736aff91bae041d2c07ee1192bec91054e10e3e601e" dependencies = [ "arrayref", "arrayvec", @@ -729,21 +730,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0a8962daed8fb337472d9c4215006443acba1e40c6c91c9d4a3f440d1fb30436" dependencies = [ "cid", - "dashmap 6.0.1", + "dashmap 6.1.0", "js-sys", "multihash", "redb", "rexie", - "thiserror", + "thiserror 1.0.69", "tokio", "wasm-bindgen", ] [[package]] name = "borsh" -version = "1.5.1" +version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6362ed55def622cddc70a4746a68554d7b687713770de539e59a739b249f8ed" +checksum = "2506947f73ad44e344215ccd6403ac2ae18cd8e046e581a441bf8d199f257f03" dependencies = [ "borsh-derive", "cfg_aliases", @@ -751,16 +752,15 @@ dependencies = [ [[package]] name = "borsh-derive" -version = "1.5.1" +version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3ef8005764f53cd4dca619f5bf64cafd4664dada50ece25e4d81de54c80cc0b" +checksum = "c2593a3b8b938bd68373196c9832f516be11fa487ef4ae745eb282e6a56a7244" dependencies = [ "once_cell", - "proc-macro-crate 3.1.0", + "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.87", - "syn_derive", + "syn 2.0.90", ] [[package]] @@ -792,9 +792,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" +checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" dependencies = [ "serde", ] @@ -828,14 +828,17 @@ dependencies = [ "semver 1.0.23", "serde", "serde_json", - "thiserror", + "thiserror 1.0.69", ] [[package]] name = "cc" -version = "1.0.99" +version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96c51067fd44124faa7f870b4b1c969379ad32b2ba805aa959430ceaa384f695" +checksum = "27f657647bcff5394bf56c7317665bbf790a137a50eaaa5c6bfbb9e27a518f2d" +dependencies = [ + "shlex", +] [[package]] name = "celestia-grpc" @@ -852,7 +855,7 @@ dependencies = [ "serde", "tendermint", "tendermint-proto", - "thiserror", + "thiserror 1.0.69", "tokio", "tonic", ] @@ -863,7 +866,7 @@ version = "0.1.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -894,14 +897,14 @@ dependencies = [ "dotenvy", "futures", "getrandom", - "http 1.1.0", + "http 1.2.0", "jsonrpsee", "libp2p", "nmt-rs", "prost", "rand", "serde", - "thiserror", + "thiserror 1.0.69", "tokio", "tracing", "wasm-bindgen-test", @@ -937,7 +940,7 @@ dependencies = [ "sha2 0.10.8", "tendermint", "tendermint-proto", - "thiserror", + "thiserror 1.0.69", "time", "wasm-bindgen-test", ] @@ -1011,9 +1014,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.7" +version = "4.5.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5db83dced34638ad474f39f250d7fea9598bdd239eaced1bdf45d597da0f433f" +checksum = "3135e7ec2ef7b10c6ed8950f0f792ed96ee093fa088608f1c76e569722700c84" dependencies = [ "clap_builder", "clap_derive", @@ -1021,9 +1024,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.7" +version = "4.5.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7e204572485eb3fbf28f871612191521df159bc3e15a9f5064c66dba3a8c05f" +checksum = "30582fc632330df2bd26877bde0c1f4470d57c582bbc070376afcd04d8cb4838" dependencies = [ "anstream", "anstyle", @@ -1033,27 +1036,27 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.5" +version = "4.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c780290ccf4fb26629baa7a1081e68ced113f1d3ec302fa5948f1c381ebf06c6" +checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" dependencies = [ - "heck 0.5.0", + "heck", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] name = "clap_lex" -version = "0.7.1" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70" +checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" [[package]] name = "colorchoice" -version = "1.0.1" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" [[package]] name = "combine" @@ -1092,18 +1095,18 @@ checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] name = "const_format" -version = "0.2.32" +version = "0.2.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3a214c7af3d04997541b18d432afaff4c455e79e2029079647e72fc2bd27673" +checksum = "126f97965c8ad46d6d9163268ff28432e8f6a1196a55578867832e3049df63dd" dependencies = [ "const_format_proc_macros", ] [[package]] name = "const_format_proc_macros" -version = "0.2.32" +version = "0.2.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7f6ff08fd20f4f299298a28e2dfa8a8ba1036e6cd2460ac1de7b425d76f2500" +checksum = "1d57c2eccfb16dbac1f4e61e206105db5820c9d26c3c472bc17c774259ef7744" dependencies = [ "proc-macro2", "quote", @@ -1112,9 +1115,9 @@ dependencies = [ [[package]] name = "constant_time_eq" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" +checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" [[package]] name = "core-foundation" @@ -1128,9 +1131,9 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "core2" @@ -1143,9 +1146,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.12" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3" dependencies = [ "libc", ] @@ -1214,7 +1217,7 @@ dependencies = [ "curve25519-dalek-derive", "digest 0.10.7", "fiat-crypto", - "rustc_version 0.4.0", + "rustc_version 0.4.1", "subtle", "zeroize", ] @@ -1227,7 +1230,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -1258,9 +1261,9 @@ dependencies = [ [[package]] name = "dashmap" -version = "6.0.1" +version = "6.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "804c8821570c3f8b70230c2ba75ffa5c0f9a4189b9a432b6656c536712acae28" +checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" dependencies = [ "cfg-if", "crossbeam-utils", @@ -1315,7 +1318,7 @@ dependencies = [ "asn1-rs", "displaydoc", "nom", - "num-bigint 0.4.5", + "num-bigint 0.4.6", "num-traits", "rusticata-macros", ] @@ -1393,13 +1396,13 @@ dependencies = [ [[package]] name = "displaydoc" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -1449,7 +1452,7 @@ dependencies = [ "rand_core", "serde", "sha2 0.9.9", - "thiserror", + "thiserror 1.0.69", "zeroize", ] @@ -1495,14 +1498,14 @@ dependencies = [ [[package]] name = "enum-as-inner" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ffccbb6966c05b32ef8fbac435df276c4ae4d3dc55a8cd0eb9745e6c12f546a" +checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc" dependencies = [ - "heck 0.4.1", + "heck", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -1514,7 +1517,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -1525,12 +1528,12 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.9" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -1546,9 +1549,9 @@ dependencies = [ [[package]] name = "event-listener-strategy" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" +checksum = "3c3e4e0dd3673c1139bf041f3008816d9cf2946bbfac2945c09e523b8d7b05b2" dependencies = [ "event-listener", "pin-project-lite", @@ -1556,9 +1559,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "fastrlp" @@ -1620,6 +1623,12 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foldhash" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2" + [[package]] name = "form_urlencoded" version = "1.2.1" @@ -1720,9 +1729,9 @@ checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-lite" -version = "2.3.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" +checksum = "cef40d21ae2c515b51041df9ed313ed21e572df340ea58a922a0aefe7e8891a1" dependencies = [ "futures-core", "pin-project-lite", @@ -1736,7 +1745,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -1837,9 +1846,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.29.0" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] name = "glob" @@ -1857,12 +1866,12 @@ dependencies = [ "futures-core", "futures-sink", "gloo-utils", - "http 1.1.0", + "http 1.2.0", "js-sys", "pin-project", "serde", "serde_json", - "thiserror", + "thiserror 1.0.69", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", @@ -1939,7 +1948,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.12", - "indexmap 2.2.6", + "indexmap 2.7.0", "slab", "tokio", "tokio-util", @@ -1948,17 +1957,17 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.5" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa82e28a107a8cc405f0839610bdc9b15f1e25ec7d696aa5cf173edbcb1486ab" +checksum = "ccae279728d634d083c00f6099cb58f01cc99c145b84b8be2f6c74618d79922e" dependencies = [ "atomic-waker", "bytes", "fnv", "futures-core", "futures-sink", - "http 1.1.0", - "indexmap 2.2.6", + "http 1.2.0", + "indexmap 2.7.0", "slab", "tokio", "tokio-util", @@ -1976,16 +1985,17 @@ name = "hashbrown" version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" -dependencies = [ - "ahash", - "allocator-api2", -] [[package]] -name = "heck" -version = "0.4.1" +name = "hashbrown" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash", +] [[package]] name = "heck" @@ -1999,6 +2009,12 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +[[package]] +name = "hermit-abi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" + [[package]] name = "hex" version = "0.4.3" @@ -2029,7 +2045,7 @@ dependencies = [ "once_cell", "rand", "socket2", - "thiserror", + "thiserror 1.0.69", "tinyvec", "tokio", "tracing", @@ -2052,7 +2068,7 @@ dependencies = [ "rand", "resolv-conf", "smallvec", - "thiserror", + "thiserror 1.0.69", "tokio", "tracing", ] @@ -2099,9 +2115,9 @@ dependencies = [ [[package]] name = "http" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea" dependencies = [ "bytes", "fnv", @@ -2121,12 +2137,12 @@ dependencies = [ [[package]] name = "http-body" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", - "http 1.1.0", + "http 1.2.0", ] [[package]] @@ -2137,16 +2153,16 @@ checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" dependencies = [ "bytes", "futures-util", - "http 1.1.0", - "http-body 1.0.0", + "http 1.2.0", + "http-body 1.0.1", "pin-project-lite", ] [[package]] name = "httparse" -version = "1.9.3" +version = "1.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0e7a4dd27b9476dc40cb050d3632d3bba3a70ddbff012285f7f8559a1e7e545" +checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" [[package]] name = "httpdate" @@ -2156,9 +2172,9 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hyper" -version = "0.14.29" +version = "0.14.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f361cde2f109281a220d4307746cdfd5ee3f410da58a70377762396775634b33" +checksum = "8c08302e8fa335b151b788c775ff56e7a03ae64ff85c548ee820fecb70356e85" dependencies = [ "bytes", "futures-channel", @@ -2187,9 +2203,9 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "h2 0.4.5", - "http 1.1.0", - "http-body 1.0.0", + "h2 0.4.7", + "http 1.2.0", + "http-body 1.0.1", "httparse", "httpdate", "itoa", @@ -2201,12 +2217,12 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.27.2" +version = "0.27.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ee4be2c948921a1a5320b629c4193916ed787a7f7f293fd3f7f5a6c9de74155" +checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333" dependencies = [ "futures-util", - "http 1.1.0", + "http 1.2.0", "hyper 1.5.1", "hyper-util", "log", @@ -2239,8 +2255,8 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "http 1.1.0", - "http-body 1.0.0", + "http 1.2.0", + "http-body 1.0.1", "hyper 1.5.1", "pin-project-lite", "socket2", @@ -2320,9 +2336,9 @@ checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" [[package]] name = "icu_properties" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f8ac670d7422d7f76b32e17a5db556510825b29ec9154f235977c9caba61036" +checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" dependencies = [ "displaydoc", "icu_collections", @@ -2364,18 +2380,18 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] name = "idb" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2764bba4203538c2ef2d733d5bad8fdb4622b1ebc5560831279db7b3be1332e8" +checksum = "3afe8830d5802f769dc0be20a87f9f116798c896650cb6266eb5c19a3c109eed" dependencies = [ "js-sys", "num-traits", - "thiserror", + "thiserror 1.0.69", "tokio", "wasm-bindgen", "web-sys", @@ -2393,16 +2409,25 @@ dependencies = [ [[package]] name = "idna" -version = "1.0.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4716a3a0933a1d01c2f72450e89596eb51dd34ef3c211ccd875acdf1f8fe47ed" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" dependencies = [ - "icu_normalizer", - "icu_properties", + "idna_adapter", "smallvec", "utf8_iter", ] +[[package]] +name = "idna_adapter" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + [[package]] name = "if-addrs" version = "0.10.2" @@ -2415,9 +2440,9 @@ dependencies = [ [[package]] name = "if-watch" -version = "3.2.0" +version = "3.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6b0422c86d7ce0e97169cc42e04ae643caf278874a7a3c87b8150a220dc7e1e" +checksum = "cdf9d64cfcf380606e64f9a0bcf493616b65331199f984151a6fa11a7b3cde38" dependencies = [ "async-io", "core-foundation", @@ -2426,6 +2451,10 @@ dependencies = [ "if-addrs", "ipnet", "log", + "netlink-packet-core", + "netlink-packet-route", + "netlink-proto", + "netlink-sys", "rtnetlink", "system-configuration", "tokio", @@ -2443,7 +2472,7 @@ dependencies = [ "bytes", "futures", "http 0.2.12", - "hyper 0.14.29", + "hyper 0.14.31", "log", "rand", "tokio", @@ -2462,13 +2491,13 @@ dependencies = [ [[package]] name = "impl-trait-for-tuples" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" +checksum = "a0eb5a3343abf848c0984fe4604b2b105da9539376e24fc0a3b0007411ae4fd9" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.90", ] [[package]] @@ -2483,12 +2512,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.2.6" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" dependencies = [ "equivalent", - "hashbrown 0.14.5", + "hashbrown 0.15.2", ] [[package]] @@ -2532,15 +2561,15 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.9.0" +version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" +checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" [[package]] name = "is_terminal_polyfill" -version = "1.70.0" +version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" [[package]] name = "itertools" @@ -2562,9 +2591,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.11" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" [[package]] name = "jni" @@ -2576,7 +2605,7 @@ dependencies = [ "combine", "jni-sys", "log", - "thiserror", + "thiserror 1.0.69", "walkdir", ] @@ -2588,18 +2617,19 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" [[package]] name = "js-sys" -version = "0.3.70" +version = "0.3.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" +checksum = "6717b6b5b077764fb5966237269cb3c64edddde4b14ce42647430a78ced9e7b7" dependencies = [ + "once_cell", "wasm-bindgen", ] [[package]] name = "jsonrpsee" -version = "0.24.2" +version = "0.24.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a1d83ae9ed70d8e3440db663e343a82f93913104744cd543bbcdd1dbc0e35d3" +checksum = "c5c71d8c1a731cc4227c2f698d377e7848ca12c8a48866fc5e6951c43a4db843" dependencies = [ "jsonrpsee-core", "jsonrpsee-http-client", @@ -2612,22 +2642,22 @@ dependencies = [ [[package]] name = "jsonrpsee-client-transport" -version = "0.24.2" +version = "0.24.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5be764c8b96cdcd2974655560a1c6542a366440d47c88114894cc20c24317815" +checksum = "548125b159ba1314104f5bb5f38519e03a41862786aa3925cf349aae9cdd546e" dependencies = [ "base64", "futures-channel", "futures-util", "gloo-net", - "http 1.1.0", + "http 1.2.0", "jsonrpsee-core", "pin-project", "rustls", "rustls-pki-types", "rustls-platform-verifier", "soketto", - "thiserror", + "thiserror 1.0.69", "tokio", "tokio-rustls", "tokio-util", @@ -2637,23 +2667,23 @@ dependencies = [ [[package]] name = "jsonrpsee-core" -version = "0.24.2" +version = "0.24.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83b772fb8aa2b511eeed75f7e19d8e5fa57be7e8202249470bf26210727399c7" +checksum = "f2882f6f8acb9fdaec7cefc4fd607119a9bd709831df7d7672a1d3b644628280" dependencies = [ "async-trait", "bytes", "futures-timer", "futures-util", - "http 1.1.0", - "http-body 1.0.0", + "http 1.2.0", + "http-body 1.0.1", "http-body-util", "jsonrpsee-types", "pin-project", - "rustc-hash 2.0.0", + "rustc-hash", "serde", "serde_json", - "thiserror", + "thiserror 1.0.69", "tokio", "tokio-stream", "tracing", @@ -2662,13 +2692,13 @@ dependencies = [ [[package]] name = "jsonrpsee-http-client" -version = "0.24.2" +version = "0.24.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d5f8f6ddb09312a9592ec9e21a3ccd6f61e51730d9d56321351eff971b0fe55" +checksum = "b3638bc4617f96675973253b3a45006933bde93c2fd8a6170b33c777cc389e5b" dependencies = [ "async-trait", "base64", - "http-body 1.0.0", + "http-body 1.0.1", "hyper 1.5.1", "hyper-rustls", "hyper-util", @@ -2678,43 +2708,43 @@ dependencies = [ "rustls-platform-verifier", "serde", "serde_json", - "thiserror", + "thiserror 1.0.69", "tokio", - "tower", + "tower 0.4.13", "tracing", "url", ] [[package]] name = "jsonrpsee-proc-macros" -version = "0.24.2" +version = "0.24.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "295d9b81496d1bef5bd34066d83c984388b6acb97620f468817bf46f67a1e9ab" +checksum = "c06c01ae0007548e73412c08e2285ffe5d723195bf268bce67b1b77c3bb2a14d" dependencies = [ - "heck 0.5.0", - "proc-macro-crate 3.1.0", + "heck", + "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] name = "jsonrpsee-types" -version = "0.24.2" +version = "0.24.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98deeee954567f75632fa40666ac93a66d4f9f4ed4ca15bd6b7ed0720b53e761" +checksum = "a178c60086f24cc35bb82f57c651d0d25d99c4742b4d335de04e97fa1f08a8a1" dependencies = [ - "http 1.1.0", + "http 1.2.0", "serde", "serde_json", - "thiserror", + "thiserror 1.0.69", ] [[package]] name = "jsonrpsee-wasm-client" -version = "0.24.2" +version = "0.24.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8a01468705cf6d326b8ba9c035e71abf5cc5e10948ba46e8af151386878398" +checksum = "1a01cd500915d24ab28ca17527e23901ef1be6d659a2322451e1045532516c25" dependencies = [ "jsonrpsee-client-transport", "jsonrpsee-core", @@ -2723,11 +2753,11 @@ dependencies = [ [[package]] name = "jsonrpsee-ws-client" -version = "0.24.2" +version = "0.24.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "385cf0a6103a9f64987cdf0f7c9d0b08e1d7183dd952820beffb3676e7df7787" +checksum = "0fe322e0896d0955a3ebdd5bf813571c53fea29edd713bc315b76620b327e86d" dependencies = [ - "http 1.1.0", + "http 1.2.0", "jsonrpsee-client-transport", "jsonrpsee-core", "jsonrpsee-types", @@ -2759,9 +2789,9 @@ dependencies = [ [[package]] name = "lazy_static" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "leopard-codec" @@ -2771,20 +2801,20 @@ checksum = "ee58dbc414bd23885d7da915e0457618b36d1fc950a6169ef2cb29829d1b1a1d" dependencies = [ "bytes", "lazy_static", - "thiserror", + "thiserror 1.0.69", ] [[package]] name = "libc" -version = "0.2.164" +version = "0.2.168" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "433bfe06b8c75da9b2e3fbea6e5329ff87748f0b144ef75306e674c3f6f7c13f" +checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d" [[package]] name = "libm" -version = "0.2.8" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" +checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" [[package]] name = "libp2p" @@ -2822,7 +2852,7 @@ dependencies = [ "multiaddr", "pin-project", "rw-stream-sink", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -2858,7 +2888,7 @@ dependencies = [ "quick-protobuf-codec", "rand", "rand_core", - "thiserror", + "thiserror 1.0.69", "tracing", "void", "web-time", @@ -2897,7 +2927,7 @@ dependencies = [ "rand", "rw-stream-sink", "smallvec", - "thiserror", + "thiserror 1.0.69", "tracing", "unsigned-varint 0.8.0", "void", @@ -2926,7 +2956,7 @@ dependencies = [ "rw-stream-sink", "serde", "smallvec", - "thiserror", + "thiserror 1.0.69", "tracing", "unsigned-varint 0.8.0", "void", @@ -2999,16 +3029,16 @@ dependencies = [ "quick-protobuf", "quick-protobuf-codec", "smallvec", - "thiserror", + "thiserror 1.0.69", "tracing", "void", ] [[package]] name = "libp2p-identity" -version = "0.2.9" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55cca1eb2bc1fd29f099f3daaab7effd01e1a54b7c577d0ed082521034d912e8" +checksum = "257b5621d159b32282eac446bed6670c39c7dc68a200a992d8f056afa0066f6d" dependencies = [ "bs58", "ed25519-dalek", @@ -3018,7 +3048,7 @@ dependencies = [ "rand", "serde", "sha2 0.10.8", - "thiserror", + "thiserror 1.0.69", "tracing", "zeroize", ] @@ -3046,7 +3076,7 @@ dependencies = [ "serde", "sha2 0.10.8", "smallvec", - "thiserror", + "thiserror 1.0.69", "tracing", "uint", "void", @@ -3113,7 +3143,7 @@ dependencies = [ "sha2 0.10.8", "snow", "static_assertions", - "thiserror", + "thiserror 1.0.69", "tracing", "x25519-dalek", "zeroize", @@ -3156,7 +3186,7 @@ dependencies = [ "ring 0.17.8", "rustls", "socket2", - "thiserror", + "thiserror 1.0.69", "tokio", "tracing", ] @@ -3213,10 +3243,10 @@ version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "206e0aa0ebe004d778d79fb0966aa0de996c19894e2c0605ba2f8524dd4443d8" dependencies = [ - "heck 0.5.0", + "heck", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -3250,7 +3280,7 @@ dependencies = [ "ring 0.17.8", "rustls", "rustls-webpki 0.101.7", - "thiserror", + "thiserror 1.0.69", "x509-parser", "yasna", ] @@ -3286,7 +3316,7 @@ dependencies = [ "pin-project-lite", "rw-stream-sink", "soketto", - "thiserror", + "thiserror 1.0.69", "tracing", "url", "webpki-roots 0.25.4", @@ -3304,7 +3334,7 @@ dependencies = [ "libp2p-core 0.41.3", "parking_lot", "send_wrapper 0.6.0", - "thiserror", + "thiserror 1.0.69", "tracing", "wasm-bindgen", "web-sys", @@ -3322,7 +3352,7 @@ dependencies = [ "libp2p-core 0.42.0", "parking_lot", "send_wrapper 0.6.0", - "thiserror", + "thiserror 1.0.69", "tracing", "wasm-bindgen", "web-sys", @@ -3342,7 +3372,7 @@ dependencies = [ "multiaddr", "multihash", "send_wrapper 0.6.0", - "thiserror", + "thiserror 1.0.69", "tracing", "wasm-bindgen", "wasm-bindgen-futures", @@ -3358,10 +3388,10 @@ dependencies = [ "either", "futures", "libp2p-core 0.42.0", - "thiserror", + "thiserror 1.0.69", "tracing", "yamux 0.12.1", - "yamux 0.13.3", + "yamux 0.13.4", ] [[package]] @@ -3370,7 +3400,7 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "libc", ] @@ -3388,9 +3418,9 @@ checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] name = "litemap" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "643cb0b8d4fcc284004d5fd0d67ccf61dfffadb7f75e1e71bc420f4688a3a704" +checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" [[package]] name = "lock_api" @@ -3404,50 +3434,50 @@ dependencies = [ [[package]] name = "log" -version = "0.4.21" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "logos" -version = "0.14.2" +version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c6b6e02facda28ca5fb8dbe4b152496ba3b1bd5a4b40bb2b1b2d8ad74e0f39b" +checksum = "7251356ef8cb7aec833ddf598c6cb24d17b689d20b993f9d11a3d764e34e6458" dependencies = [ "logos-derive", ] [[package]] name = "logos-codegen" -version = "0.14.2" +version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b32eb6b5f26efacd015b000bfc562186472cd9b34bdba3f6b264e2a052676d10" +checksum = "59f80069600c0d66734f5ff52cc42f2dabd6b29d205f333d61fd7832e9e9963f" dependencies = [ "beef", "fnv", "lazy_static", "proc-macro2", "quote", - "regex-syntax 0.8.4", - "syn 2.0.87", + "regex-syntax 0.8.5", + "syn 2.0.90", ] [[package]] name = "logos-derive" -version = "0.14.2" +version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e5d0c5463c911ef55624739fc353238b4e310f0144be1f875dc42fec6bfd5ec" +checksum = "24fb722b06a9dc12adb0963ed585f19fc61dc5413e6a9be9422ef92c091e731d" dependencies = [ "logos-codegen", ] [[package]] name = "lru" -version = "0.12.3" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3262e75e648fce39813cb56ac41f3c3e3f65217ebf3844d818d1f9398cfb0dc" +checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" dependencies = [ - "hashbrown 0.14.5", + "hashbrown 0.15.2", ] [[package]] @@ -3523,7 +3553,7 @@ dependencies = [ "tempfile", "tendermint", "tendermint-proto", - "thiserror", + "thiserror 1.0.69", "tokio", "tokio-util", "tracing", @@ -3556,7 +3586,7 @@ dependencies = [ "serde_json", "serde_repr", "tendermint", - "thiserror", + "thiserror 1.0.69", "time", "tokio", "tracing", @@ -3597,25 +3627,25 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "miette" -version = "7.2.0" +version = "7.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4edc8853320c2a0dab800fbda86253c8938f6ea88510dc92c5f1ed20e794afc1" +checksum = "317f146e2eb7021892722af37cf1b971f0a70c8406f487e24952667616192c64" dependencies = [ "cfg-if", "miette-derive", - "thiserror", + "thiserror 1.0.69", "unicode-width", ] [[package]] name = "miette-derive" -version = "7.2.0" +version = "7.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf09caffaac8068c346b6df2a7fc27a177fd20b39421a39ce0a211bde679a6c" +checksum = "23c9b935fbe1d6cbd1dac857b54a688145e2d93f48db36010514d0f612d0ad67" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -3626,9 +3656,9 @@ checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] name = "mime_guess" -version = "2.0.4" +version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" dependencies = [ "mime", "unicase", @@ -3636,9 +3666,9 @@ dependencies = [ [[package]] name = "minicov" -version = "0.3.5" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c71e683cd655513b99affab7d317deb690528255a0d5f717f1024093c12b169" +checksum = "f27fe9f1cc3c22e1687f9446c2083c4c5fc7f0bcf1c7a86bdbded14985895b4b" dependencies = [ "cc", "walkdir", @@ -3652,29 +3682,29 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.7.3" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87dfd01fe195c66b572b37921ad8803d010623c0aca821bea2302239d155cdae" +checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" dependencies = [ - "adler", + "adler2", ] [[package]] name = "mio" -version = "0.8.11" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" dependencies = [ "libc", "wasi", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "multiaddr" -version = "0.18.1" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b852bc02a2da5feed68cd14fa50d0774b92790a5bdbfa932a813926c8472070" +checksum = "fe6351f60b488e04c1d21bc69e56b89cb3f5e8f5d22557d6e8031bdfd79b6961" dependencies = [ "arrayref", "byteorder", @@ -3685,7 +3715,7 @@ dependencies = [ "percent-encoding", "serde", "static_assertions", - "unsigned-varint 0.7.2", + "unsigned-varint 0.8.0", "url", ] @@ -3702,20 +3732,20 @@ dependencies = [ [[package]] name = "multihash" -version = "0.19.1" +version = "0.19.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "076d548d76a0e2a0d4ab471d0b1c36c577786dfc4471242035d97a12a735c492" +checksum = "6b430e7953c29dd6a09afc29ff0bb69c6e306329ee6794700aee27b76a1aea8d" dependencies = [ "core2", "serde", - "unsigned-varint 0.7.2", + "unsigned-varint 0.8.0", ] [[package]] name = "multihash-codetable" -version = "0.1.2" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c11bbdf904c8be009e82ff968c4dab84388cbafc45dfaff61936eca4bf40f1b5" +checksum = "67996849749d25f1da9f238e8ace2ece8f9d6bdf3f9750aaf2ae7de3a5cad8ea" dependencies = [ "blake2b_simd", "blake2s_simd", @@ -3732,9 +3762,9 @@ dependencies = [ [[package]] name = "multihash-derive" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "890e72cb7396cb99ed98c1246a97b243cc16394470d94e0bc8b0c2c11d84290e" +checksum = "1f1b7edab35d920890b88643a765fc9bd295cf0201f4154dda231bef9b8404eb" dependencies = [ "core2", "multihash", @@ -3743,15 +3773,14 @@ dependencies = [ [[package]] name = "multihash-derive-impl" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3958713ce794e12f7c6326fac9aa274c68d74c4881dd37b3e2662b8a2046bb19" +checksum = "e3dc7141bd06405929948754f0628d247f5ca1865be745099205e5086da957cb" dependencies = [ - "proc-macro-crate 2.0.0", - "proc-macro-error", + "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", "synstructure", ] @@ -3785,28 +3814,27 @@ dependencies = [ "redb", "serde_json", "tendermint", - "thiserror", + "thiserror 1.0.69", "tokio", "uniffi", ] [[package]] name = "netlink-packet-core" -version = "0.4.2" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "345b8ab5bd4e71a2986663e88c56856699d060e78e152e6e9d7966fcd5491297" +checksum = "72724faf704479d67b388da142b186f916188505e7e0b26719019c525882eda4" dependencies = [ "anyhow", "byteorder", - "libc", "netlink-packet-utils", ] [[package]] name = "netlink-packet-route" -version = "0.12.0" +version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9ea4302b9759a7a88242299225ea3688e63c85ea136371bb6cf94fd674efaab" +checksum = "053998cea5a306971f88580d0829e90f270f940befd7cf928da179d4187a5a66" dependencies = [ "anyhow", "bitflags 1.3.2", @@ -3825,29 +3853,29 @@ dependencies = [ "anyhow", "byteorder", "paste", - "thiserror", + "thiserror 1.0.69", ] [[package]] name = "netlink-proto" -version = "0.10.0" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65b4b14489ab424703c092062176d52ba55485a89c076b4f9db05092b7223aa6" +checksum = "86b33524dc0968bfad349684447bfce6db937a9ac3332a1fe60c0c5a5ce63f21" dependencies = [ "bytes", "futures", "log", "netlink-packet-core", "netlink-sys", - "thiserror", + "thiserror 1.0.69", "tokio", ] [[package]] name = "netlink-sys" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "416060d346fbaf1f23f9512963e3e878f1a78e707cb699ba9215761754244307" +checksum = "16c903aa70590cb93691bf97a767c8d1d6122d2cc9070433deb3bbf36ce8bd23" dependencies = [ "bytes", "futures", @@ -3858,9 +3886,9 @@ dependencies = [ [[package]] name = "nix" -version = "0.24.3" +version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa52e972a9a719cecb6864fb88568781eb706bac2cd1d4f04a648542dbf78069" +checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" dependencies = [ "bitflags 1.3.2", "cfg-if", @@ -3869,9 +3897,9 @@ dependencies = [ [[package]] name = "nmt-rs" -version = "0.2.1" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479d559d6a0da9cd6972630efff47d85bbe483e4298723e7f3b43df149f5e484" +checksum = "e408e823bdc9b4bb525a61b44e846239833a8f9bd86c03a43e4ca314a5497582" dependencies = [ "borsh", "bytes", @@ -3932,9 +3960,9 @@ dependencies = [ [[package]] name = "num-bigint" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c165a9ab64cf766f73521c0dd2cfdff64f488b8f0b3e621face3462d3db536d7" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" dependencies = [ "num-integer", "num-traits", @@ -4004,33 +4032,33 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi", + "hermit-abi 0.3.9", "libc", ] [[package]] name = "object" -version = "0.36.0" +version = "0.36.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "576dfe1fc8f9df304abb159d767a29d0476f7750fbf8aa7ad07816004a207434" +checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" dependencies = [ "memchr", ] [[package]] name = "oid-registry" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c958dd45046245b9c3c2547369bb634eb461670b2e7e0de552905801a648d1d" +checksum = "a8d8034d9489cdaf79228eb9f6a3b8d7bb32ba00d6645ebd48eef4077ceb5bd9" dependencies = [ "asn1-rs", ] [[package]] name = "once_cell" -version = "1.19.0" +version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "opaque-debug" @@ -4076,7 +4104,7 @@ version = "3.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d830939c76d294956402033aee57a6da7b438f2294eb94864c37b0569053a42c" dependencies = [ - "proc-macro-crate 3.1.0", + "proc-macro-crate", "proc-macro2", "quote", "syn 1.0.109", @@ -4084,9 +4112,9 @@ dependencies = [ [[package]] name = "parking" -version = "2.2.0" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" [[package]] name = "parking_lot" @@ -4108,7 +4136,7 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-targets 0.52.5", + "windows-targets 0.52.6", ] [[package]] @@ -4146,12 +4174,12 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pest" -version = "2.7.10" +version = "2.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "560131c633294438da9f7c4b08189194b20946c8274c6b9e38881a7874dc8ee8" +checksum = "8b7cafe60d6cf8e62e1b9b2ea516a089c008945bb5a275416789e7db0bc199dc" dependencies = [ "memchr", - "thiserror", + "thiserror 2.0.6", "ucd-trie", ] @@ -4162,34 +4190,34 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" dependencies = [ "fixedbitset", - "indexmap 2.2.6", + "indexmap 2.7.0", ] [[package]] name = "pin-project" -version = "1.1.5" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" +checksum = "be57f64e946e500c8ee36ef6331845d40a93055567ec57e8fae13efd33759b95" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.5" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" +checksum = "3c0f5fad0874fc7abcd4d750e76917eaebbecaa2c20bde22e1dbeeba8beb758c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] name = "pin-project-lite" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" +checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" [[package]] name = "pin-utils" @@ -4215,17 +4243,17 @@ checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" [[package]] name = "polling" -version = "3.7.1" +version = "3.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e6a007746f34ed64099e88783b0ae369eaa3da6392868ba262e2af9b8fbaea1" +checksum = "a604568c3202727d1507653cb121dbd627a58684eb09a820fd746bee38b4442f" dependencies = [ "cfg-if", "concurrent-queue", - "hermit-abi", + "hermit-abi 0.4.0", "pin-project-lite", "rustix", "tracing", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -4259,18 +4287,21 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" -version = "0.2.17" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] [[package]] name = "prettyplease" -version = "0.2.20" +version = "0.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f12335488a2f3b0a83b14edad48dca9879ce89b2edd10e80237e4e852dd645e" +checksum = "64d1ec885c64d0457d564db4ec299b2dae3f9c02808b8ad9c3a089c591b18033" dependencies = [ "proc-macro2", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -4286,60 +4317,27 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e8366a6159044a37876a2b9817124296703c586a5c92e2c53751fa06d8d43e8" -dependencies = [ - "toml_edit 0.20.7", -] - -[[package]] -name = "proc-macro-crate" -version = "3.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" -dependencies = [ - "toml_edit 0.21.1", -] - -[[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn 1.0.109", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" dependencies = [ - "proc-macro2", - "quote", - "version_check", + "toml_edit", ] [[package]] name = "proc-macro2" -version = "1.0.89" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" dependencies = [ "unicode-ident", ] [[package]] name = "prometheus-client" -version = "0.22.2" +version = "0.22.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1ca959da22a332509f2a73ae9e5f23f9dcfc31fd3a54d71f159495bd5909baa" +checksum = "504ee9ff529add891127c4827eb481bd69dc0ebc72e9a682e187db4caa60c3ca" dependencies = [ "dtoa", "itoa", @@ -4355,30 +4353,30 @@ checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] name = "proptest" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31b476131c3c86cb68032fdc5cb6d5a1045e3e42d96b69fa599fd77701e1f5bf" +checksum = "b4c2511913b88df1637da85cc8d96ec8e43a3f8bb8ccb71ee1ac240d6f3df58d" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "lazy_static", "num-traits", "rand", "rand_chacha", "rand_xorshift", - "regex-syntax 0.8.4", + "regex-syntax 0.8.5", "unarray", ] [[package]] name = "prost" -version = "0.13.3" +version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b0487d90e047de87f984913713b85c601c05609aad5b0df4b4573fbf69aa13f" +checksum = "2c0fef6c4230e4ccf618a35c59d7ede15dea37de8427500f50aff708806e42ec" dependencies = [ "bytes", "prost-derive", @@ -4386,12 +4384,11 @@ dependencies = [ [[package]] name = "prost-build" -version = "0.13.3" +version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c1318b19085f08681016926435853bbf7858f9c082d0999b80550ff5d9abe15" +checksum = "d0f3e5beed80eb580c68e2c600937ac2c4eedabdfd5ef1e5b7ea4f3fba84497b" dependencies = [ - "bytes", - "heck 0.5.0", + "heck", "itertools 0.13.0", "log", "multimap", @@ -4401,28 +4398,28 @@ dependencies = [ "prost", "prost-types", "regex", - "syn 2.0.87", + "syn 2.0.90", "tempfile", ] [[package]] name = "prost-derive" -version = "0.13.3" +version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9552f850d5f0964a4e4d0bf306459ac29323ddfbae05e35a7c0d35cb0803cc5" +checksum = "157c5a9d7ea5c2ed2d9fb8f495b64759f7816c7eaea54ba3978f0d63000162e3" dependencies = [ "anyhow", "itertools 0.13.0", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] name = "prost-reflect" -version = "0.14.2" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b7535b02f0e5efe3e1dbfcb428be152226ed0c66cad9541f2274c8ba8d4cd40" +checksum = "20ae544fca2892fd4b7e9ff26cba1090cedf1d4d95c2aded1af15d2f93f270b8" dependencies = [ "logos", "miette", @@ -4433,9 +4430,9 @@ dependencies = [ [[package]] name = "prost-types" -version = "0.13.3" +version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4759aa0d3a6232fb8dbdb97b61de2c20047c68aca932c7ed76da9d788508d670" +checksum = "cc2f1e56baa61e93533aebc21af4d2134b70f66275e0fcdf3cbe43d77ff7e8fc" dependencies = [ "prost", ] @@ -4452,7 +4449,7 @@ dependencies = [ "prost-reflect", "prost-types", "protox-parse", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -4464,7 +4461,7 @@ dependencies = [ "logos", "miette", "prost-types", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -4491,56 +4488,61 @@ dependencies = [ "asynchronous-codec", "bytes", "quick-protobuf", - "thiserror", + "thiserror 1.0.69", "unsigned-varint 0.8.0", ] [[package]] name = "quinn" -version = "0.11.2" +version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4ceeeeabace7857413798eb1ffa1e9c905a9946a57d81fb69b4b71c4d8eb3ad" +checksum = "62e96808277ec6f97351a2380e6c25114bc9e67037775464979f3037c92d05ef" dependencies = [ "bytes", "futures-io", "pin-project-lite", "quinn-proto", "quinn-udp", - "rustc-hash 1.1.0", + "rustc-hash", "rustls", - "thiserror", + "socket2", + "thiserror 2.0.6", "tokio", "tracing", ] [[package]] name = "quinn-proto" -version = "0.11.8" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fadfaed2cd7f389d0161bb73eeb07b7b78f8691047a6f3e73caaeae55310a4a6" +checksum = "a2fe5ef3495d7d2e377ff17b1a8ce2ee2ec2a18cde8b6ad6619d65d0701c135d" dependencies = [ "bytes", + "getrandom", "rand", "ring 0.17.8", - "rustc-hash 2.0.0", + "rustc-hash", "rustls", + "rustls-pki-types", "slab", - "thiserror", + "thiserror 2.0.6", "tinyvec", "tracing", + "web-time", ] [[package]] name = "quinn-udp" -version = "0.5.2" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9096629c45860fc7fb143e125eb826b5e721e10be3263160c7d60ca832cf8c46" +checksum = "52cd4b1eff68bf27940dd39811292c49e007f4d0b4c357358dc9b0197be6b527" dependencies = [ + "cfg_aliases", "libc", "once_cell", "socket2", "tracing", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -4611,43 +4613,43 @@ dependencies = [ [[package]] name = "redb" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6dd20d3cdeb9c7d2366a0b16b93b35b75aec15309fbeb7ce477138c9f68c8c0" +checksum = "84b1de48a7cf7ba193e81e078d17ee2b786236eed1d3f7c60f8a09545efc4925" dependencies = [ "libc", ] [[package]] name = "redox_syscall" -version = "0.5.1" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" +checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", ] [[package]] name = "redox_users" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ "getrandom", "libredox", - "thiserror", + "thiserror 1.0.69", ] [[package]] name = "regex" -version = "1.10.5" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.7", - "regex-syntax 0.8.4", + "regex-automata 0.4.9", + "regex-syntax 0.8.5", ] [[package]] @@ -4661,13 +4663,13 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.7" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.4", + "regex-syntax 0.8.5", ] [[package]] @@ -4678,9 +4680,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "relative-path" @@ -4705,7 +4707,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "887466cfa8a12c08ee4b174998135cea8ff0fd84858627cd793e56535a045bc9" dependencies = [ "idb", - "thiserror", + "thiserror 1.0.69", "wasm-bindgen", ] @@ -4777,7 +4779,7 @@ dependencies = [ "futures", "futures-timer", "rstest_macros", - "rustc_version 0.4.0", + "rustc_version 0.4.1", ] [[package]] @@ -4788,28 +4790,31 @@ checksum = "4165dfae59a39dd41d8dec720d3cbfbc71f69744efb480a3920f5d4e0cc6798d" dependencies = [ "cfg-if", "glob", - "proc-macro-crate 3.1.0", + "proc-macro-crate", "proc-macro2", "quote", "regex", "relative-path", - "rustc_version 0.4.0", - "syn 2.0.87", + "rustc_version 0.4.1", + "syn 2.0.90", "unicode-ident", ] [[package]] name = "rtnetlink" -version = "0.10.1" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "322c53fd76a18698f1c27381d58091de3a043d356aa5bd0d510608b565f469a0" +checksum = "7a552eb82d19f38c3beed3f786bd23aa434ceb9ac43ab44419ca6d67a7e186c0" dependencies = [ "futures", "log", + "netlink-packet-core", "netlink-packet-route", + "netlink-packet-utils", "netlink-proto", + "netlink-sys", "nix", - "thiserror", + "thiserror 1.0.69", "tokio", ] @@ -4824,7 +4829,7 @@ dependencies = [ "ark-ff 0.4.2", "bytes", "fastrlp", - "num-bigint 0.4.5", + "num-bigint 0.4.6", "num-traits", "parity-scale-codec", "primitive-types", @@ -4845,9 +4850,9 @@ checksum = "48fd7bd8a6377e15ad9d42a8ec25371b94ddc67abe7c8b9127bec79bebaaae18" [[package]] name = "rust-embed" -version = "8.4.0" +version = "8.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19549741604902eb99a7ed0ee177a0663ee1eda51a29f71401f166e47e77806a" +checksum = "fa66af4a4fdd5e7ebc276f115e895611a34739a9c1c01028383d612d550953c0" dependencies = [ "rust-embed-impl", "rust-embed-utils", @@ -4856,23 +4861,23 @@ dependencies = [ [[package]] name = "rust-embed-impl" -version = "8.4.0" +version = "8.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb9f96e283ec64401f30d3df8ee2aaeb2561f34c824381efa24a35f79bf40ee4" +checksum = "6125dbc8867951125eec87294137f4e9c2c96566e61bf72c45095a7c77761478" dependencies = [ "proc-macro2", "quote", "rust-embed-utils", "shellexpand", - "syn 2.0.87", + "syn 2.0.90", "walkdir", ] [[package]] name = "rust-embed-utils" -version = "8.4.0" +version = "8.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38c74a686185620830701348de757fd36bef4aa9680fd23c49fc539ddcc1af32" +checksum = "2e5347777e9aacb56039b0e1f28785929a8a3b709e87482e7442c72e7c12529d" dependencies = [ "sha2 0.10.8", "walkdir", @@ -4886,15 +4891,9 @@ checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - -[[package]] -name = "rustc-hash" -version = "2.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" +checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497" [[package]] name = "rustc-hex" @@ -4913,9 +4912,9 @@ dependencies = [ [[package]] name = "rustc_version" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ "semver 1.0.23", ] @@ -4931,37 +4930,37 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.41" +version = "0.38.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7f649912bc1495e167a6edee79151c84b1bad49748cb4f1f1167f459f6224f6" +checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "errno", "libc", "linux-raw-sys", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "rustls" -version = "0.23.10" +version = "0.23.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05cff451f60db80f490f3c182b77c35260baace73209e9cdbbe526bfe3a4d402" +checksum = "934b404430bb06b3fae2cba809eb45a1ab1aecd64491213d7c3301b88393f8d1" dependencies = [ "log", "once_cell", "ring 0.17.8", "rustls-pki-types", - "rustls-webpki 0.102.4", + "rustls-webpki 0.102.8", "subtle", "zeroize", ] [[package]] name = "rustls-native-certs" -version = "0.7.0" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f1fb85efa936c42c6d5fc28d2629bb51e4b2f4b8a5211e297d599cc5a093792" +checksum = "e5bfb394eeed242e909609f56089eecfe5fda225042e8b171791b9c95f5931e5" dependencies = [ "openssl-probe", "rustls-pemfile", @@ -4972,25 +4971,27 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "2.1.2" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29993a25686778eb88d4189742cd713c9bce943bc54251a33509dc63cbacf73d" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" dependencies = [ - "base64", "rustls-pki-types", ] [[package]] name = "rustls-pki-types" -version = "1.7.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" +checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b" +dependencies = [ + "web-time", +] [[package]] name = "rustls-platform-verifier" -version = "0.3.1" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5f0d26fa1ce3c790f9590868f0109289a044acb954525f933e2aa3b871c157d" +checksum = "afbb878bdfdf63a336a5e63561b1835e7a8c91524f51621db870169eac84b490" dependencies = [ "core-foundation", "core-foundation-sys", @@ -5000,18 +5001,18 @@ dependencies = [ "rustls", "rustls-native-certs", "rustls-platform-verifier-android", - "rustls-webpki 0.102.4", + "rustls-webpki 0.102.8", "security-framework", "security-framework-sys", - "webpki-roots 0.26.2", + "webpki-roots 0.26.7", "winapi", ] [[package]] name = "rustls-platform-verifier-android" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84e217e7fdc8466b5b35d30f8c0a30febd29173df4a3a0c2115d306b9c4117ad" +checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" [[package]] name = "rustls-webpki" @@ -5025,9 +5026,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.102.4" +version = "0.102.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff448f7e92e913c4b7d4c6d8e4540a1724b319b4152b8aef6d4cf8339712b33e" +checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" dependencies = [ "ring 0.17.8", "rustls-pki-types", @@ -5036,9 +5037,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" +checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" [[package]] name = "rw-stream-sink" @@ -5068,11 +5069,11 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.23" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" +checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -5104,7 +5105,7 @@ checksum = "7f81c2fde025af7e69b1d1420531c8a8811ca898919db177141a85313b1cb932" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -5123,23 +5124,23 @@ dependencies = [ [[package]] name = "security-framework" -version = "2.11.0" +version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c627723fd09706bacdb5cf41499e95098555af3c3c29d014dc3c458ef6be11c0" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "core-foundation", "core-foundation-sys", "libc", - "num-bigint 0.4.5", + "num-bigint 0.4.6", "security-framework-sys", ] [[package]] name = "security-framework-sys" -version = "2.11.0" +version = "2.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "317936bbbd05227752583946b9e66d7ce3b489f84e11a94a510b4437fef407d7" +checksum = "fa39c7303dc58b5543c94d22c1766b0d31f2ee58306363ea622b10bbc075eaa2" dependencies = [ "core-foundation-sys", "libc", @@ -5165,9 +5166,9 @@ dependencies = [ [[package]] name = "semver-parser" -version = "0.10.2" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" +checksum = "9900206b54a3527fdc7b8a938bffd94a568bac4f4aa8113b209df75a09c0dec2" dependencies = [ "pest", ] @@ -5209,9 +5210,9 @@ dependencies = [ [[package]] name = "serde_bytes" -version = "0.11.14" +version = "0.11.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b8497c313fd43ab992087548117643f6fcd935cbf36f176ffda0aacf9591734" +checksum = "387cc504cb06bb40a96c8e04e951fe01854cf6bc921053c954e4a606d9675c6a" dependencies = [ "serde", ] @@ -5224,16 +5225,17 @@ checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] name = "serde_json" -version = "1.0.120" +version = "1.0.133" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5" +checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" dependencies = [ "itoa", + "memchr", "ryu", "serde", ] @@ -5256,7 +5258,7 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -5334,6 +5336,12 @@ dependencies = [ "dirs", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "signal-hook-registry" version = "1.4.2" @@ -5395,16 +5403,16 @@ dependencies = [ "curve25519-dalek", "rand_core", "ring 0.17.8", - "rustc_version 0.4.0", + "rustc_version 0.4.1", "sha2 0.10.8", "subtle", ] [[package]] name = "socket2" -version = "0.5.7" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" dependencies = [ "libc", "windows-sys 0.52.0", @@ -5412,9 +5420,9 @@ dependencies = [ [[package]] name = "soketto" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37468c595637c10857701c990f93a40ce0e357cedb0953d1c26c8d8027f9bb53" +checksum = "2e859df029d160cb88608f5d7df7fb4753fd20fdfb4de5644f3d8b8440841721" dependencies = [ "base64", "bytes", @@ -5461,9 +5469,9 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "strobe-rs" -version = "0.8.1" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fabb238a1cccccfa4c4fb703670c0d157e1256c1ba695abf1b93bd2bb14bab2d" +checksum = "98fe17535ea31344936cc58d29fec9b500b0452ddc4cc24c429c8a921a0e84e5" dependencies = [ "bitflags 1.3.2", "byteorder", @@ -5480,9 +5488,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "subtle" -version = "2.5.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "subtle-encoding" @@ -5512,27 +5520,15 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.87" +version = "2.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" +checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] -[[package]] -name = "syn_derive" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1329189c02ff984e9736652b1631330da25eaa6bc639089ed4915d25446cbe7b" -dependencies = [ - "proc-macro-error", - "proc-macro2", - "quote", - "syn 2.0.87", -] - [[package]] name = "sync_wrapper" version = "0.1.2" @@ -5541,9 +5537,9 @@ checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" [[package]] name = "sync_wrapper" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" [[package]] name = "synstructure" @@ -5553,25 +5549,23 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] name = "system-configuration" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +version = "0.6.1" +source = "git+https://github.com/mullvad/system-configuration-rs?tag=v0.6.1#c7a1626d79410a2f35e0361de952b6076a33d95c" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.6.0", "core-foundation", "system-configuration-sys", ] [[package]] name = "system-configuration-sys" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +version = "0.6.0" +source = "git+https://github.com/mullvad/system-configuration-rs?tag=v0.6.1#c7a1626d79410a2f35e0361de952b6076a33d95c" dependencies = [ "core-foundation-sys", "libc", @@ -5593,7 +5587,7 @@ dependencies = [ "fastrand", "once_cell", "rustix", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -5652,22 +5646,42 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.61" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ - "thiserror-impl", + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fec2a1820ebd077e2b90c4df007bebf344cd394098a13c563957d0afc83ea47" +dependencies = [ + "thiserror-impl 2.0.6", ] [[package]] name = "thiserror-impl" -version = "1.0.61" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d65750cab40f4ff1929fb1ba509e9914eb756131cef4210da8d5d700d26f6312" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", ] [[package]] @@ -5682,9 +5696,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.36" +version = "0.3.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" dependencies = [ "deranged", "itoa", @@ -5704,9 +5718,9 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.18" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" +checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de" dependencies = [ "num-conv", "time-core", @@ -5724,9 +5738,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.6.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" dependencies = [ "tinyvec_macros", ] @@ -5739,50 +5753,48 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.38.0" +version = "1.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a" +checksum = "5cec9b21b0450273377fc97bd4c33a8acffc8c996c987a7c5b319a0083707551" dependencies = [ "backtrace", "bytes", "libc", "mio", - "num_cpus", "parking_lot", "pin-project-lite", "signal-hook-registry", "socket2", "tokio-macros", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "tokio-macros" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a" +checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] name = "tokio-rustls" -version = "0.26.0" +version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" +checksum = "5f6d0975eaace0cf0fcadee4e4aaa5da15b5c079146f2cffb67c113be122bf37" dependencies = [ "rustls", - "rustls-pki-types", "tokio", ] [[package]] name = "tokio-stream" -version = "0.1.16" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f4e6ce100d0eb49a2734f8c0812bcd324cf357d21810932c5df6b96ef2b86f1" +checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" dependencies = [ "futures-core", "pin-project-lite", @@ -5791,9 +5803,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.11" +version = "0.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" +checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078" dependencies = [ "bytes", "futures-core", @@ -5814,28 +5826,17 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.6" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" [[package]] name = "toml_edit" -version = "0.20.7" +version = "0.22.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81" +checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" dependencies = [ - "indexmap 2.2.6", - "toml_datetime", - "winnow", -] - -[[package]] -name = "toml_edit" -version = "0.21.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" -dependencies = [ - "indexmap 2.2.6", + "indexmap 2.7.0", "toml_datetime", "winnow", ] @@ -5851,9 +5852,9 @@ dependencies = [ "axum", "base64", "bytes", - "h2 0.4.5", - "http 1.1.0", - "http-body 1.0.0", + "h2 0.4.7", + "http 1.2.0", + "http-body 1.0.1", "http-body-util", "hyper 1.5.1", "hyper-timeout", @@ -5864,7 +5865,7 @@ dependencies = [ "socket2", "tokio", "tokio-stream", - "tower", + "tower 0.4.13", "tower-layer", "tower-service", "tracing", @@ -5881,7 +5882,7 @@ dependencies = [ "prost-build", "prost-types", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -5904,23 +5905,39 @@ dependencies = [ "tracing", ] +[[package]] +name = "tower" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2873938d487c3cfb9aed7546dc9f2711d867c9f90c46b889989a2cb84eba6b4f" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper 0.1.2", + "tokio", + "tower-layer", + "tower-service", + "tracing", +] + [[package]] name = "tower-layer" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" [[package]] name = "tower-service" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" -version = "0.1.40" +version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ "log", "pin-project-lite", @@ -5935,27 +5952,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3566e8ce28cc0a3fe42519fc80e6b4c943cc4c8cef275620eb8dac2d3d4e06cf" dependencies = [ "crossbeam-channel", - "thiserror", + "thiserror 1.0.69", "time", "tracing-subscriber", ] [[package]] name = "tracing-attributes" -version = "0.1.27" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] name = "tracing-core" -version = "0.1.32" +version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" dependencies = [ "once_cell", "valuable", @@ -5974,9 +5991,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.18" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" dependencies = [ "matchers", "nu-ansi-term", @@ -6018,9 +6035,9 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "ucd-trie" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" [[package]] name = "uint" @@ -6042,30 +6059,27 @@ checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" [[package]] name = "unicase" -version = "2.7.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" -dependencies = [ - "version_check", -] +checksum = "7e51b68083f157f853b6379db119d1c1be0e6e4dec98101079dec41f6f5cf6df" [[package]] name = "unicode-bidi" -version = "0.3.15" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" +checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893" [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" [[package]] name = "unicode-normalization" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" dependencies = [ "tinyvec", ] @@ -6078,9 +6092,9 @@ checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" [[package]] name = "unicode-xid" -version = "0.2.4" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] name = "uniffi" @@ -6110,7 +6124,7 @@ dependencies = [ "fs-err", "glob", "goblin", - "heck 0.5.0", + "heck", "once_cell", "paste", "serde", @@ -6127,7 +6141,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "802d2051a700e3ec894c79f80d2705b69d85844dafbbe5d1a92776f8f48b563a" dependencies = [ "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -6137,6 +6151,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc7687007d2546c454d8ae609b105daceb88175477dac280707ad6d95bcd6f1f" dependencies = [ "anyhow", + "async-compat", "bytes", "log", "once_cell", @@ -6157,7 +6172,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.87", + "syn 2.0.90", "toml", "uniffi_meta", ] @@ -6236,12 +6251,12 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.5.1" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7c25da092f0a868cdf09e8674cd3b7ef3a7d92a24253e663a2fb85e2496de56" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" dependencies = [ "form_urlencoded", - "idna 1.0.0", + "idna 1.0.3", "percent-encoding", ] @@ -6271,9 +6286,9 @@ checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" [[package]] name = "version_check" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "void" @@ -6308,9 +6323,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.93" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" +checksum = "a474f6281d1d70c17ae7aa6a613c87fce69a127e2624002df63dcb39d6cf6396" dependencies = [ "cfg-if", "once_cell", @@ -6319,36 +6334,36 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.93" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" +checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79" dependencies = [ "bumpalo", "log", - "once_cell", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.43" +version = "0.4.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed" +checksum = "38176d9b44ea84e9184eff0bc34cc167ed044f816accfe5922e54d84cf48eca2" dependencies = [ "cfg-if", "js-sys", + "once_cell", "wasm-bindgen", "web-sys", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.93" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" +checksum = "2cc6181fd9a7492eef6fef1f33961e3695e4579b9872a6f7c83aee556666d4fe" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -6356,30 +6371,29 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.93" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" +checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.93" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" +checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6" [[package]] name = "wasm-bindgen-test" -version = "0.3.43" +version = "0.3.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68497a05fb21143a08a7d24fc81763384a3072ee43c44e86aad1744d6adef9d9" +checksum = "c61d44563646eb934577f2772656c7ad5e9c90fac78aa8013d776fcdaf24625d" dependencies = [ - "console_error_panic_hook", "js-sys", "minicov", "scoped-tls", @@ -6390,20 +6404,20 @@ dependencies = [ [[package]] name = "wasm-bindgen-test-macro" -version = "0.3.43" +version = "0.3.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b8220be1fa9e4c889b30fd207d4906657e7e90b12e0e6b0c8b8d8709f5de021" +checksum = "54171416ce73aa0b9c377b51cc3cb542becee1cd678204812e8392e5b0e4a031" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] name = "web-sys" -version = "0.3.70" +version = "0.3.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0" +checksum = "04dd7223427d52553d3702c004d3b2fe07c148165faa56313cb00211e31c12bc" dependencies = [ "js-sys", "wasm-bindgen", @@ -6427,9 +6441,9 @@ checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" [[package]] name = "webpki-roots" -version = "0.26.2" +version = "0.26.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c452ad30530b54a4d8e71952716a212b08efd0f3562baa66c29a618b07da7c3" +checksum = "5d642ff16b7e79272ae451b7322067cdc17cadf68c23264be9d94a32319efe7e" dependencies = [ "rustls-pki-types", ] @@ -6467,11 +6481,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -6482,21 +6496,31 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows" -version = "0.51.1" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca229916c5ee38c2f2bc1e9d8f04df975b4bd93f9955dc69fabb5d91270045c9" +checksum = "efc5cf48f83140dcaab716eeaea345f9e93d0018fb81162753a3f76c3397b538" dependencies = [ "windows-core", - "windows-targets 0.48.5", + "windows-targets 0.52.6", ] [[package]] name = "windows-core" -version = "0.51.1" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" +checksum = "9dcc5b895a6377f1ab9fa55acedab1fd5ac0db66ad1e6c7f47e28a22e446a5dd" dependencies = [ - "windows-targets 0.48.5", + "windows-result", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-result" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8" +dependencies = [ + "windows-targets 0.52.6", ] [[package]] @@ -6514,7 +6538,16 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.5", + "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]] @@ -6534,18 +6567,18 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.5", - "windows_aarch64_msvc 0.52.5", - "windows_i686_gnu 0.52.5", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", "windows_i686_gnullvm", - "windows_i686_msvc 0.52.5", - "windows_x86_64_gnu 0.52.5", - "windows_x86_64_gnullvm 0.52.5", - "windows_x86_64_msvc 0.52.5", + "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]] @@ -6556,9 +6589,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" @@ -6568,9 +6601,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" @@ -6580,15 +6613,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" @@ -6598,9 +6631,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" @@ -6610,9 +6643,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" @@ -6622,9 +6655,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" @@ -6634,15 +6667,15 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.5.40" +version = "0.6.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" dependencies = [ "memchr", ] @@ -6703,15 +6736,15 @@ dependencies = [ "nom", "oid-registry", "rusticata-macros", - "thiserror", + "thiserror 1.0.69", "time", ] [[package]] name = "xml-rs" -version = "0.8.20" +version = "0.8.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "791978798f0597cfc70478424c2b4fdc2b7a8024aaff78497ef00f24ef674193" +checksum = "ea8b391c9a790b496184c29f7f93b9ed5b16abb306c05415b68bcc16e4d06432" [[package]] name = "xmltree" @@ -6739,9 +6772,9 @@ dependencies = [ [[package]] name = "yamux" -version = "0.13.3" +version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31b5e376a8b012bee9c423acdbb835fc34d45001cfa3106236a624e4b738028" +checksum = "17610762a1207ee816c6fadc29220904753648aba0a9ed61c7b8336e80a559c4" dependencies = [ "futures", "log", @@ -6764,9 +6797,9 @@ dependencies = [ [[package]] name = "yoke" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c5b1314b079b0930c31e3af543d8ee1757b1951ae1e1565ec704403a7240ca5" +checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" dependencies = [ "serde", "stable_deref_trait", @@ -6776,54 +6809,55 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95" +checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", "synstructure", ] [[package]] name = "zerocopy" -version = "0.7.34" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae87e3fcd617500e5d106f0380cf7b77f3c6092aae37191433159dda23cfb087" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ + "byteorder", "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.34" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] name = "zerofrom" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ec111ce797d0e0784a1116d0ddcdbea84322cd79e5d5ad173daeba4f93ab55" +checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" dependencies = [ "zerofrom-derive", ] [[package]] name = "zerofrom-derive" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5" +checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", "synstructure", ] @@ -6844,7 +6878,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -6866,10 +6900,5 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] - -[[patch.unused]] -name = "system-configuration" -version = "0.6.1" -source = "git+https://github.com/mullvad/system-configuration-rs?tag=v0.6.1#c7a1626d79410a2f35e0361de952b6076a33d95c" diff --git a/node-native/Cargo.toml b/node-native/Cargo.toml index 7043947c..e097fa66 100644 --- a/node-native/Cargo.toml +++ b/node-native/Cargo.toml @@ -17,7 +17,7 @@ celestia-types.workspace = true tendermint.workspace = true libp2p.workspace = true -uniffi = { version = "0.28.3", features = ["bindgen", "cli"] } +uniffi = { version = "0.28.3", features = ["bindgen", "tokio", "cli"] } tokio = { version = "1.0", features = ["full"] } redb = "2.1.1" thiserror = "1.0.61" diff --git a/node-native/build-ios.sh b/node-native/build-ios.sh index 613af599..9cf73bce 100755 --- a/node-native/build-ios.sh +++ b/node-native/build-ios.sh @@ -3,6 +3,7 @@ cargo build -p native mkdir -p ./bindings +mkdir -p ./ios cargo run --bin uniffi-bindgen generate --library ../target/debug/libnative.dylib --language swift --out-dir ./bindings diff --git a/node-native/src/lib.rs b/node-native/src/lib.rs index 4b813ab6..db53567d 100644 --- a/node-native/src/lib.rs +++ b/node-native/src/lib.rs @@ -12,7 +12,7 @@ use lumina_node::{ use std::{path::PathBuf, str::FromStr, sync::Arc, time::Duration}; use tendermint::hash::Hash; use thiserror::Error; -use tokio::{runtime::Runtime, sync::Mutex}; +use tokio::sync::Mutex; use types::{Network, NetworkInfo, NodeEvent, PeerId, PeerTrackerInfo, SyncingInfo}; use uniffi::Object; @@ -76,316 +76,264 @@ impl From for LuminaError { #[derive(Object)] pub struct LuminaNode { node: Arc>>>, - runtime: Runtime, network: Network, events_subscriber: Arc>>, } -#[uniffi::export] +#[uniffi::export(async_runtime = "tokio")] impl LuminaNode { #[uniffi::constructor] pub fn new(network: Network) -> Result> { - let runtime = Runtime::new().map_err(|e| LuminaError::NetworkError { - message: e.to_string(), - })?; - Ok(Arc::new(Self { node: Arc::new(Mutex::new(None)), - runtime, network, events_subscriber: Arc::new(Mutex::new(None)), })) } - pub fn start(&self) -> Result { - self.runtime.block_on(async { - let mut node_guard = self.node.lock().await; + pub async fn start(&self) -> Result { + let mut node_guard = self.node.lock().await; + + if node_guard.is_some() { + return Err(LuminaError::AlreadyRunning); + } + + let network_id = network_id(self.network.into()); + + let base_path = get_base_path()?; - if node_guard.is_some() { - return Err(LuminaError::AlreadyRunning); + std::fs::create_dir_all(&base_path).map_err(|e| LuminaError::StorageError { + message: format!("Failed to create data directory: {}", e), + })?; + + let store_path = base_path.join(format!("store-{}", network_id)); + let db = Arc::new(redb::Database::create(&store_path).map_err(|e| { + LuminaError::StorageInit { + message: format!("Failed to create database: {}", e), } + })?); + + let store = RedbStore::new(db.clone()) + .await + .map_err(|e| LuminaError::StorageInit { + message: format!("Failed to initialize store: {}", e), + })?; + + let blockstore = RedbBlockstore::new(db); + + let p2p_bootnodes = canonical_network_bootnodes(self.network.into()).collect::>(); - let network_id = network_id(self.network.into()); + let p2p_local_keypair = Keypair::generate_ed25519(); - let base_path = get_base_path()?; + let config = NodeConfig { + network_id: network_id.to_string(), + p2p_bootnodes, + p2p_local_keypair, + p2p_listen_on: vec![], + sync_batch_size: 128, + custom_syncing_window: Some(Duration::from_secs(60 * 60 * 24)), + store, + blockstore, + }; - std::fs::create_dir_all(&base_path).map_err(|e| LuminaError::StorageError { - message: format!("Failed to create data directory: {}", e), + let new_node = Node::new(config) + .await + .map_err(|e| LuminaError::NetworkError { + message: e.to_string(), })?; - let store_path = base_path.join(format!("store-{}", network_id)); - let db = Arc::new(redb::Database::create(&store_path).map_err(|e| { - LuminaError::StorageInit { - message: format!("Failed to create database: {}", e), - } - })?); - - let store = RedbStore::new(db.clone()) - .await - .map_err(|e| LuminaError::StorageInit { - message: format!("Failed to initialize store: {}", e), - })?; - - let blockstore = RedbBlockstore::new(db); - - let p2p_bootnodes = - canonical_network_bootnodes(self.network.into()).collect::>(); - - let p2p_local_keypair = Keypair::generate_ed25519(); - - let config = NodeConfig { - network_id: network_id.to_string(), - p2p_bootnodes, - p2p_local_keypair, - p2p_listen_on: vec![], - sync_batch_size: 128, - custom_syncing_window: Some(Duration::from_secs(60 * 60 * 24)), - store, - blockstore, - }; - - let new_node = Node::new(config) - .await - .map_err(|e| LuminaError::NetworkError { - message: e.to_string(), - })?; - - let subscriber = new_node.event_subscriber(); - let mut events_guard = self.events_subscriber.lock().await; - *events_guard = Some(subscriber); - - *node_guard = Some(new_node); - Ok(true) - }) + let subscriber = new_node.event_subscriber(); + let mut events_guard = self.events_subscriber.lock().await; + *events_guard = Some(subscriber); + + *node_guard = Some(new_node); + Ok(true) } - pub fn stop(&self) -> Result<()> { - self.runtime.block_on(async { - let mut node_guard = self.node.lock().await; - let node = node_guard.take().ok_or(LuminaError::NodeNotRunning)?; - node.stop().await; - Ok(()) - }) + pub async fn stop(&self) -> Result<()> { + let mut node_guard = self.node.lock().await; + let node = node_guard.take().ok_or(LuminaError::NodeNotRunning)?; + node.stop().await; + Ok(()) } - pub fn is_running(&self) -> bool { - self.runtime - .block_on(async { self.node.lock().await.is_some() }) + pub async fn is_running(&self) -> bool { + self.node.lock().await.is_some() } - pub fn local_peer_id(&self) -> Result { - self.runtime.block_on(async { - let node_guard = self.node.lock().await; - let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; - Ok(node.local_peer_id().to_string()) - }) + pub async fn local_peer_id(&self) -> Result { + let node_guard = self.node.lock().await; + let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; + Ok(node.local_peer_id().to_string()) } - pub fn peer_tracker_info(&self) -> Result { - self.runtime.block_on(async { - let node_guard = self.node.lock().await; - let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; - Ok(node.peer_tracker_info().into()) - }) + pub async fn peer_tracker_info(&self) -> Result { + let node_guard = self.node.lock().await; + let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; + Ok(node.peer_tracker_info().into()) } - pub fn wait_connected(&self) -> Result<()> { - self.runtime.block_on(async { - let node_guard = self.node.lock().await; - let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; - Ok(node.wait_connected().await?) - }) + pub async fn wait_connected(&self) -> Result<()> { + let node_guard = self.node.lock().await; + let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; + Ok(node.wait_connected().await?) } - pub fn wait_connected_trusted(&self) -> Result<()> { - self.runtime.block_on(async { - let node_guard = self.node.lock().await; - let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; - Ok(node.wait_connected_trusted().await?) - }) + pub async fn wait_connected_trusted(&self) -> Result<()> { + let node_guard = self.node.lock().await; + let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; + Ok(node.wait_connected_trusted().await?) } - pub fn network_info(&self) -> Result { - self.runtime.block_on(async { - let node_guard = self.node.lock().await; - let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; - let info = node.network_info().await?; - Ok(info.into()) - }) + pub async fn network_info(&self) -> Result { + let node_guard = self.node.lock().await; + let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; + let info = node.network_info().await?; + Ok(info.into()) } - pub fn listeners(&self) -> Result> { - self.runtime.block_on(async { - let node_guard = self.node.lock().await; - let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; - let listeners = node.listeners().await?; - Ok(listeners.into_iter().map(|l| l.to_string()).collect()) - }) + pub async fn listeners(&self) -> Result> { + let node_guard = self.node.lock().await; + let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; + let listeners = node.listeners().await?; + Ok(listeners.into_iter().map(|l| l.to_string()).collect()) } - pub fn connected_peers(&self) -> Result> { - self.runtime.block_on(async { - let node_guard = self.node.lock().await; - let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; - let peers = node.connected_peers().await?; - Ok(peers.into_iter().map(PeerId::from).collect()) - }) + pub async fn connected_peers(&self) -> Result> { + let node_guard = self.node.lock().await; + let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; + let peers = node.connected_peers().await?; + Ok(peers.into_iter().map(PeerId::from).collect()) } - pub fn set_peer_trust(&self, peer_id: PeerId, is_trusted: bool) -> Result<()> { - self.runtime.block_on(async { - let node_guard = self.node.lock().await; - let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; - let peer_id = peer_id - .to_libp2p() - .map_err(|e| LuminaError::NetworkError { message: e })?; - Ok(node.set_peer_trust(peer_id, is_trusted).await?) - }) + pub async fn set_peer_trust(&self, peer_id: PeerId, is_trusted: bool) -> Result<()> { + let node_guard = self.node.lock().await; + let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; + let peer_id = peer_id + .to_libp2p() + .map_err(|e| LuminaError::NetworkError { message: e })?; + Ok(node.set_peer_trust(peer_id, is_trusted).await?) } - pub fn request_head_header(&self) -> Result { - self.runtime.block_on(async { - let node_guard = self.node.lock().await; - let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; - let header = node.request_head_header().await?; - Ok(header.to_string()) //if extended header is needed, we need a wrapper - }) + pub async fn request_head_header(&self) -> Result { + let node_guard = self.node.lock().await; + let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; + let header = node.request_head_header().await?; + Ok(header.to_string()) //if extended header is needed, we need a wrapper } - pub fn request_header_by_hash(&self, hash: String) -> Result { - self.runtime.block_on(async { - let node_guard = self.node.lock().await; - let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; - let hash = Hash::from_str(&hash).map_err(|e| LuminaError::InvalidHash { - message: e.to_string(), - })?; - let header = node.request_header_by_hash(&hash).await?; - Ok(header.to_string()) //if extended header is needed, we need a wrapper - }) + pub async fn request_header_by_hash(&self, hash: String) -> Result { + let node_guard = self.node.lock().await; + let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; + let hash = Hash::from_str(&hash).map_err(|e| LuminaError::InvalidHash { + message: e.to_string(), + })?; + let header = node.request_header_by_hash(&hash).await?; + Ok(header.to_string()) //if extended header is needed, we need a wrapper } - pub fn request_header_by_height(&self, height: u64) -> Result { - self.runtime.block_on(async { - let node_guard = self.node.lock().await; - let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; - let header = node.request_header_by_height(height).await?; - Ok(header.to_string()) - }) + pub async fn request_header_by_height(&self, height: u64) -> Result { + let node_guard = self.node.lock().await; + let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; + let header = node.request_header_by_height(height).await?; + Ok(header.to_string()) } - pub fn request_verified_headers( + pub async fn request_verified_headers( &self, from: String, // serialized header like its done for WASM amount: u64, ) -> Result> { - self.runtime.block_on(async { - let node_guard = self.node.lock().await; - let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; - let from: ExtendedHeader = - serde_json::from_str(&from).map_err(|e| LuminaError::InvalidHeader { - message: format!("Invalid header JSON: {}", e), - })?; - let headers = node.request_verified_headers(&from, amount).await?; - Ok(headers.into_iter().map(|h| h.to_string()).collect()) - }) + let node_guard = self.node.lock().await; + let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; + let from: ExtendedHeader = + serde_json::from_str(&from).map_err(|e| LuminaError::InvalidHeader { + message: format!("Invalid header JSON: {}", e), + })?; + let headers = node.request_verified_headers(&from, amount).await?; + Ok(headers.into_iter().map(|h| h.to_string()).collect()) } - pub fn syncer_info(&self) -> Result { - self.runtime.block_on(async { - let node_guard = self.node.lock().await; - let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; - let info = node.syncer_info().await?; - Ok(info.into()) - }) + pub async fn syncer_info(&self) -> Result { + let node_guard = self.node.lock().await; + let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; + let info = node.syncer_info().await?; + Ok(info.into()) } - pub fn get_network_head_header(&self) -> Result { - self.runtime.block_on(async { - let node_guard = self.node.lock().await; - let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; - let header = node.get_network_head_header().await?; - header.map_or( - // todo: better error handling, its undefined in wasm - Err(LuminaError::NetworkError { - message: "No network head header available".to_string(), - }), - |h| Ok(h.to_string()), - ) - }) + pub async fn get_network_head_header(&self) -> Result { + let node_guard = self.node.lock().await; + let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; + let header = node.get_network_head_header().await?; + header.map_or( + // todo: better error handling, its undefined in wasm + Err(LuminaError::NetworkError { + message: "No network head header available".to_string(), + }), + |h| Ok(h.to_string()), + ) } - pub fn get_local_head_header(&self) -> Result { - self.runtime.block_on(async { - let node_guard = self.node.lock().await; - let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; - let header = node.get_local_head_header().await?; - Ok(header.to_string()) - }) + pub async fn get_local_head_header(&self) -> Result { + let node_guard = self.node.lock().await; + let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; + let header = node.get_local_head_header().await?; + Ok(header.to_string()) } - pub fn get_header_by_hash(&self, hash: String) -> Result { - self.runtime.block_on(async { - let node_guard = self.node.lock().await; - let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; - let hash = Hash::from_str(&hash).map_err(|e| LuminaError::InvalidHash { - message: e.to_string(), - })?; - let header = node.get_header_by_hash(&hash).await?; - Ok(header.to_string()) - }) + pub async fn get_header_by_hash(&self, hash: String) -> Result { + let node_guard = self.node.lock().await; + let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; + let hash = Hash::from_str(&hash).map_err(|e| LuminaError::InvalidHash { + message: e.to_string(), + })?; + let header = node.get_header_by_hash(&hash).await?; + Ok(header.to_string()) } - pub fn get_header_by_height(&self, height: u64) -> Result { - self.runtime.block_on(async { - let node_guard = self.node.lock().await; - let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; - let header = node.get_header_by_height(height).await?; - Ok(header.to_string()) - }) + pub async fn get_header_by_height(&self, height: u64) -> Result { + let node_guard = self.node.lock().await; + let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; + let header = node.get_header_by_height(height).await?; + Ok(header.to_string()) } - pub fn get_headers( + pub async fn get_headers( &self, start_height: Option, end_height: Option, ) -> Result> { - self.runtime.block_on(async { - let node_guard = self.node.lock().await; - let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; - - let headers = match (start_height, end_height) { - (None, None) => node.get_headers(..).await, - (Some(start), None) => node.get_headers(start..).await, - (None, Some(end)) => node.get_headers(..=end).await, - (Some(start), Some(end)) => node.get_headers(start..=end).await, - }?; - - Ok(headers.into_iter().map(|h| h.to_string()).collect()) - }) + let node_guard = self.node.lock().await; + let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; + + let headers = match (start_height, end_height) { + (None, None) => node.get_headers(..).await, + (Some(start), None) => node.get_headers(start..).await, + (None, Some(end)) => node.get_headers(..=end).await, + (Some(start), Some(end)) => node.get_headers(start..=end).await, + }?; + + Ok(headers.into_iter().map(|h| h.to_string()).collect()) } - pub fn get_sampling_metadata(&self, height: u64) -> Result> { - self.runtime.block_on(async { - let node_guard = self.node.lock().await; - let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; - let metadata = node.get_sampling_metadata(height).await?; - Ok(metadata.map(|m| serde_json::to_string(&m).unwrap())) - }) + pub async fn get_sampling_metadata(&self, height: u64) -> Result> { + let node_guard = self.node.lock().await; + let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; + let metadata = node.get_sampling_metadata(height).await?; + Ok(metadata.map(|m| serde_json::to_string(&m).unwrap())) } - pub fn events_channel(&self) -> Result> { - self.runtime.block_on(async { - let mut events_guard = self.events_subscriber.lock().await; - let subscriber = events_guard.as_mut().ok_or(LuminaError::NodeNotRunning)?; - - match subscriber.try_recv() { - Ok(event) => Ok(Some(event.event.into())), - Err(TryRecvError::Empty) => Ok(None), - Err(e) => Err(LuminaError::NetworkError { - message: e.to_string(), - }), - } - }) + pub async fn events_channel(&self) -> Result> { + let mut events_guard = self.events_subscriber.lock().await; + let subscriber = events_guard.as_mut().ok_or(LuminaError::NodeNotRunning)?; + + match subscriber.try_recv() { + Ok(event) => Ok(Some(event.event.into())), + Err(TryRecvError::Empty) => Ok(None), + Err(e) => Err(LuminaError::NetworkError { + message: e.to_string(), + }), + } } } From 81e194aec41fcbc261835745f77b2b99609aad72 Mon Sep 17 00:00:00 2001 From: sebasti810 Date: Wed, 11 Dec 2024 12:13:34 +0100 Subject: [PATCH 03/13] fix: rename message to msg to avoid conflicts with the base kotlin exception class --- node-native/src/lib.rs | 58 +++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 32 deletions(-) diff --git a/node-native/src/lib.rs b/node-native/src/lib.rs index db53567d..0a04d2bc 100644 --- a/node-native/src/lib.rs +++ b/node-native/src/lib.rs @@ -24,7 +24,7 @@ fn get_base_path() -> Result { .map(PathBuf::from) .map(|p| p.join("Library/Application Support/lumina")) .map_err(|e| LuminaError::StorageError { - message: format!("Could not get HOME directory: {}", e), + msg: format!("Could not get HOME directory: {}", e), }) } @@ -34,14 +34,14 @@ fn get_base_path() -> Result { std::env::var("LUMINA_DATA_DIR") .map(PathBuf::from) .map_err(|e| LuminaError::StorageError { - message: format!("Could not get LUMINA_DATA_DIR: {}", e), + msg: format!("Could not get LUMINA_DATA_DIR: {}", e), }) } #[cfg(not(any(target_os = "ios", target_os = "android")))] fn get_base_path() -> Result { Err(LuminaError::StorageError { - message: "Unsupported platform".to_string(), + msg: "Unsupported platform".to_string(), }) } @@ -49,26 +49,26 @@ fn get_base_path() -> Result { pub enum LuminaError { #[error("Node is not running")] NodeNotRunning, - #[error("Network error: {message}")] - NetworkError { message: String }, - #[error("Storage error: {message}")] - StorageError { message: String }, + #[error("Network error: {msg}")] + NetworkError { msg: String }, + #[error("Storage error: {msg}")] + StorageError { msg: String }, #[error("Node is already running")] AlreadyRunning, #[error("Lock error")] LockError, - #[error("Invalid hash format: {message}")] - InvalidHash { message: String }, - #[error("Invalid header format: {message}")] - InvalidHeader { message: String }, - #[error("Storage initialization failed: {message}")] - StorageInit { message: String }, + #[error("Invalid hash format: {msg}")] + InvalidHash { msg: String }, + #[error("Invalid header format: {msg}")] + InvalidHeader { msg: String }, + #[error("Storage initialization failed: {msg}")] + StorageInit { msg: String }, } impl From for LuminaError { fn from(error: NodeError) -> Self { LuminaError::NetworkError { - message: error.to_string(), + msg: error.to_string(), } } } @@ -103,20 +103,20 @@ impl LuminaNode { let base_path = get_base_path()?; std::fs::create_dir_all(&base_path).map_err(|e| LuminaError::StorageError { - message: format!("Failed to create data directory: {}", e), + msg: format!("Failed to create data directory: {}", e), })?; let store_path = base_path.join(format!("store-{}", network_id)); let db = Arc::new(redb::Database::create(&store_path).map_err(|e| { LuminaError::StorageInit { - message: format!("Failed to create database: {}", e), + msg: format!("Failed to create database: {}", e), } })?); let store = RedbStore::new(db.clone()) .await .map_err(|e| LuminaError::StorageInit { - message: format!("Failed to initialize store: {}", e), + msg: format!("Failed to initialize store: {}", e), })?; let blockstore = RedbBlockstore::new(db); @@ -138,9 +138,7 @@ impl LuminaNode { let new_node = Node::new(config) .await - .map_err(|e| LuminaError::NetworkError { - message: e.to_string(), - })?; + .map_err(|e| LuminaError::NetworkError { msg: e.to_string() })?; let subscriber = new_node.event_subscriber(); let mut events_guard = self.events_subscriber.lock().await; @@ -211,7 +209,7 @@ impl LuminaNode { let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; let peer_id = peer_id .to_libp2p() - .map_err(|e| LuminaError::NetworkError { message: e })?; + .map_err(|e| LuminaError::NetworkError { msg: e })?; Ok(node.set_peer_trust(peer_id, is_trusted).await?) } @@ -225,9 +223,8 @@ impl LuminaNode { pub async fn request_header_by_hash(&self, hash: String) -> Result { let node_guard = self.node.lock().await; let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; - let hash = Hash::from_str(&hash).map_err(|e| LuminaError::InvalidHash { - message: e.to_string(), - })?; + let hash = + Hash::from_str(&hash).map_err(|e| LuminaError::InvalidHash { msg: e.to_string() })?; let header = node.request_header_by_hash(&hash).await?; Ok(header.to_string()) //if extended header is needed, we need a wrapper } @@ -248,7 +245,7 @@ impl LuminaNode { let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; let from: ExtendedHeader = serde_json::from_str(&from).map_err(|e| LuminaError::InvalidHeader { - message: format!("Invalid header JSON: {}", e), + msg: format!("Invalid header JSON: {}", e), })?; let headers = node.request_verified_headers(&from, amount).await?; Ok(headers.into_iter().map(|h| h.to_string()).collect()) @@ -268,7 +265,7 @@ impl LuminaNode { header.map_or( // todo: better error handling, its undefined in wasm Err(LuminaError::NetworkError { - message: "No network head header available".to_string(), + msg: "No network head header available".to_string(), }), |h| Ok(h.to_string()), ) @@ -284,9 +281,8 @@ impl LuminaNode { pub async fn get_header_by_hash(&self, hash: String) -> Result { let node_guard = self.node.lock().await; let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; - let hash = Hash::from_str(&hash).map_err(|e| LuminaError::InvalidHash { - message: e.to_string(), - })?; + let hash = + Hash::from_str(&hash).map_err(|e| LuminaError::InvalidHash { msg: e.to_string() })?; let header = node.get_header_by_hash(&hash).await?; Ok(header.to_string()) } @@ -330,9 +326,7 @@ impl LuminaNode { match subscriber.try_recv() { Ok(event) => Ok(Some(event.event.into())), Err(TryRecvError::Empty) => Ok(None), - Err(e) => Err(LuminaError::NetworkError { - message: e.to_string(), - }), + Err(e) => Err(LuminaError::NetworkError { msg: e.to_string() }), } } } From 5f59a21c458371aac8c96a308ef4627de7f0f018 Mon Sep 17 00:00:00 2001 From: sebasti810 Date: Wed, 11 Dec 2024 13:24:59 +0100 Subject: [PATCH 04/13] fix: add docs --- node-native/src/lib.rs | 91 +++++++++++++++++++++++++++++++----------- 1 file changed, 68 insertions(+), 23 deletions(-) diff --git a/node-native/src/lib.rs b/node-native/src/lib.rs index 0a04d2bc..36fc6cf8 100644 --- a/node-native/src/lib.rs +++ b/node-native/src/lib.rs @@ -18,31 +18,38 @@ use uniffi::Object; pub type Result = std::result::Result; -#[cfg(target_os = "ios")] +/// Returns the platform-specific base path for storing Lumina data. +/// +/// The function determines the base path based on the target operating system: +/// - **iOS**: `~/Library/Application Support/lumina` +/// - **Android**: Value of the `LUMINA_DATA_DIR` environment variable +/// - **Other platforms**: Returns an error indicating unsupported platform. fn get_base_path() -> Result { - std::env::var("HOME") - .map(PathBuf::from) - .map(|p| p.join("Library/Application Support/lumina")) - .map_err(|e| LuminaError::StorageError { - msg: format!("Could not get HOME directory: {}", e), - }) -} + #[cfg(target_os = "ios")] + { + std::env::var("HOME") + .map(PathBuf::from) + .map(|p| p.join("Library/Application Support/lumina")) + .map_err(|e| LuminaError::StorageError { + msg: format!("Could not get HOME directory: {}", e), + }) + } -#[cfg(target_os = "android")] -fn get_base_path() -> Result { - // On Android, we'll use the app's files directory passed from the platform - std::env::var("LUMINA_DATA_DIR") - .map(PathBuf::from) - .map_err(|e| LuminaError::StorageError { - msg: format!("Could not get LUMINA_DATA_DIR: {}", e), - }) -} + #[cfg(target_os = "android")] + { + std::env::var("LUMINA_DATA_DIR") + .map(PathBuf::from) + .map_err(|e| LuminaError::StorageError { + msg: format!("Could not get LUMINA_DATA_DIR: {}", e), + }) + } -#[cfg(not(any(target_os = "ios", target_os = "android")))] -fn get_base_path() -> Result { - Err(LuminaError::StorageError { - msg: "Unsupported platform".to_string(), - }) + #[cfg(not(any(target_os = "ios", target_os = "android")))] + { + Err(LuminaError::StorageError { + msg: "Unsupported platform".to_string(), + }) + } } #[derive(Error, Debug, uniffi::Error)] @@ -73,6 +80,7 @@ impl From for LuminaError { } } +/// The main Lumina node that manages the connection to the Celestia network. #[derive(Object)] pub struct LuminaNode { node: Arc>>>, @@ -82,6 +90,7 @@ pub struct LuminaNode { #[uniffi::export(async_runtime = "tokio")] impl LuminaNode { + /// Sets a new connection to the Lumina node for the specified network. #[uniffi::constructor] pub fn new(network: Network) -> Result> { Ok(Arc::new(Self { @@ -91,6 +100,7 @@ impl LuminaNode { })) } + /// Starts the Lumina node. Returns true if successfully started. pub async fn start(&self) -> Result { let mut node_guard = self.node.lock().await; @@ -148,6 +158,7 @@ impl LuminaNode { Ok(true) } + /// Stops the running node and closes all network connections. pub async fn stop(&self) -> Result<()> { let mut node_guard = self.node.lock().await; let node = node_guard.take().ok_or(LuminaError::NodeNotRunning)?; @@ -155,34 +166,40 @@ impl LuminaNode { Ok(()) } + /// Checks if the node is currently running. pub async fn is_running(&self) -> bool { self.node.lock().await.is_some() } + /// Gets the local peer ID as a string. pub async fn local_peer_id(&self) -> Result { let node_guard = self.node.lock().await; let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; - Ok(node.local_peer_id().to_string()) + Ok(node.local_peer_id().to_base58()) } + /// Gets information about connected peers. pub async fn peer_tracker_info(&self) -> Result { let node_guard = self.node.lock().await; let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; Ok(node.peer_tracker_info().into()) } + /// Waits until the node is connected to at least one peer. pub async fn wait_connected(&self) -> Result<()> { let node_guard = self.node.lock().await; let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; Ok(node.wait_connected().await?) } + /// Waits until the node is connected to at least one trusted peer. pub async fn wait_connected_trusted(&self) -> Result<()> { let node_guard = self.node.lock().await; let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; Ok(node.wait_connected_trusted().await?) } + /// Gets current network information. pub async fn network_info(&self) -> Result { let node_guard = self.node.lock().await; let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; @@ -190,6 +207,7 @@ impl LuminaNode { Ok(info.into()) } + /// Gets list of addresses the node is listening to. pub async fn listeners(&self) -> Result> { let node_guard = self.node.lock().await; let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; @@ -197,6 +215,7 @@ impl LuminaNode { Ok(listeners.into_iter().map(|l| l.to_string()).collect()) } + /// Gets list of currently connected peer IDs. pub async fn connected_peers(&self) -> Result> { let node_guard = self.node.lock().await; let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; @@ -204,6 +223,7 @@ impl LuminaNode { Ok(peers.into_iter().map(PeerId::from).collect()) } + /// Sets whether a peer with give ID is trusted. pub async fn set_peer_trust(&self, peer_id: PeerId, is_trusted: bool) -> Result<()> { let node_guard = self.node.lock().await; let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; @@ -213,6 +233,9 @@ impl LuminaNode { Ok(node.set_peer_trust(peer_id, is_trusted).await?) } + /// Request the head header from the network. + /// + /// Returns a serialized ExtendedHeader string. pub async fn request_head_header(&self) -> Result { let node_guard = self.node.lock().await; let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; @@ -220,6 +243,7 @@ impl LuminaNode { Ok(header.to_string()) //if extended header is needed, we need a wrapper } + /// Request a header for the block with a given hash from the network. pub async fn request_header_by_hash(&self, hash: String) -> Result { let node_guard = self.node.lock().await; let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; @@ -229,6 +253,7 @@ impl LuminaNode { Ok(header.to_string()) //if extended header is needed, we need a wrapper } + /// Requests a header by its height. pub async fn request_header_by_height(&self, height: u64) -> Result { let node_guard = self.node.lock().await; let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; @@ -236,6 +261,10 @@ impl LuminaNode { Ok(header.to_string()) } + /// Request headers in range (from, from + amount] from the network. + /// + /// The headers will be verified with the `from` header. + /// Returns array of serialized ExtendedHeader strings. pub async fn request_verified_headers( &self, from: String, // serialized header like its done for WASM @@ -251,6 +280,7 @@ impl LuminaNode { Ok(headers.into_iter().map(|h| h.to_string()).collect()) } + /// Gets current syncing information. pub async fn syncer_info(&self) -> Result { let node_guard = self.node.lock().await; let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; @@ -258,6 +288,7 @@ impl LuminaNode { Ok(info.into()) } + /// Gets the latest header announced in the network. pub async fn get_network_head_header(&self) -> Result { let node_guard = self.node.lock().await; let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; @@ -271,6 +302,7 @@ impl LuminaNode { ) } + /// Gets the latest locally synced header. pub async fn get_local_head_header(&self) -> Result { let node_guard = self.node.lock().await; let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; @@ -278,6 +310,7 @@ impl LuminaNode { Ok(header.to_string()) } + /// Get a synced header for the block with a given hash. pub async fn get_header_by_hash(&self, hash: String) -> Result { let node_guard = self.node.lock().await; let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; @@ -287,6 +320,7 @@ impl LuminaNode { Ok(header.to_string()) } + /// Get a synced header for the block with a given height. pub async fn get_header_by_height(&self, height: u64) -> Result { let node_guard = self.node.lock().await; let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; @@ -294,6 +328,13 @@ impl LuminaNode { Ok(header.to_string()) } + /// Gets headers from the given heights range. + /// + /// If start of the range is undefined (None), the first returned header will be of height 1. + /// If end of the range is undefined (None), the last returned header will be the last header in the + /// store. + /// + /// Returns array of serialized ExtendedHeader strings. pub async fn get_headers( &self, start_height: Option, @@ -312,6 +353,9 @@ impl LuminaNode { Ok(headers.into_iter().map(|h| h.to_string()).collect()) } + /// Gets data sampling metadata for a height. + /// + /// Returns serialized SamplingMetadata string if metadata exists for the height. pub async fn get_sampling_metadata(&self, height: u64) -> Result> { let node_guard = self.node.lock().await; let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; @@ -319,6 +363,7 @@ impl LuminaNode { Ok(metadata.map(|m| serde_json::to_string(&m).unwrap())) } + /// Returns the next event from the node's event channel. pub async fn events_channel(&self) -> Result> { let mut events_guard = self.events_subscriber.lock().await; let subscriber = events_guard.as_mut().ok_or(LuminaError::NodeNotRunning)?; From 4d850e2bed1d7cdbd788acdcf1c425148239f4fc Mon Sep 17 00:00:00 2001 From: sebasti810 Date: Wed, 11 Dec 2024 14:59:45 +0100 Subject: [PATCH 05/13] fix: add docs to types --- node-native/src/types.rs | 77 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 75 insertions(+), 2 deletions(-) diff --git a/node-native/src/types.rs b/node-native/src/types.rs index d4bd7297..d84bd77e 100644 --- a/node-native/src/types.rs +++ b/node-native/src/types.rs @@ -56,18 +56,28 @@ impl From for PeerTrackerInfo { #[derive(Record)] pub struct NetworkInfo { + /// The total number of connected peers. pub num_peers: u32, + /// Counters of ongoing network connections. pub connection_counters: ConnectionCounters, } +/// Counters of ongoing network connections. #[derive(Record)] pub struct ConnectionCounters { + /// The current number of connections. pub num_connections: u32, + /// The current number of pending connections. pub num_pending: u32, + /// The current number of incoming connections. pub num_pending_incoming: u32, + /// The current number of outgoing connections. pub num_pending_outgoing: u32, + /// The current number of established connections. pub num_established: u32, + /// The current number of established inbound connections. pub num_established_incoming: u32, + /// The current number of established outbound connections. pub num_established_outgoing: u32, } @@ -94,6 +104,7 @@ impl From<&Libp2pConnectionCounters> for ConnectionCounters { } } +/// A range of blocks. #[derive(Record)] pub struct BlockRange { pub start: u64, @@ -109,9 +120,12 @@ impl From for BlockRange { } } +/// Status of the node syncing. #[derive(Record)] pub struct SyncingInfo { + /// Ranges of headers that are already synchronised pub stored_headers: Vec, + /// Syncing target. The latest height seen in the network that was successfully verified. pub subjective_head: u64, } @@ -131,7 +145,7 @@ impl From for SyncingInfo { #[derive(Record, Clone, Debug)] pub struct PeerId { - // Store as base58 string for now + /// The peer ID stored as base58 string. pub peer_id: String, } @@ -161,70 +175,124 @@ pub struct ShareCoordinate { pub column: u16, } +/// Events emitted by the node. #[derive(uniffi::Enum)] pub enum NodeEvent { + /// Node is connecting to bootnodes ConnectingToBootnodes, + /// Peer just connected PeerConnected { + /// The ID of the peer. id: PeerId, + /// Whether peer was in the trusted list or not. trusted: bool, }, PeerDisconnected { + /// The ID of the peer. id: PeerId, + /// Whether peer was in the trusted list or not. trusted: bool, }, + /// Sampling just started. SamplingStarted { + /// The block height that will be sampled. height: u64, + /// The square width of the block. square_width: u16, + /// The coordinates of the shares that will be sampled. shares: Vec, }, + /// A share was sampled. ShareSamplingResult { + /// The block height of the share. height: u64, + /// The square width of the block. square_width: u16, + /// The row of the share. row: u16, + /// The column of the share. column: u16, + /// The result of the sampling of the share. accepted: bool, }, + /// Sampling just finished. SamplingFinished { + /// The block height that was sampled. height: u64, + /// The overall result of the sampling. accepted: bool, + /// How much time sampling took in milliseconds. took_ms: u64, }, + /// Data sampling fatal error. FatalDaserError { + /// A human readable error. error: String, }, + /// A new header was added from HeaderSub. AddedHeaderFromHeaderSub { + /// The height of the header. height: u64, }, + /// Fetching header of network head just started. FetchingHeadHeaderStarted, + /// Fetching header of network head just finished. FetchingHeadHeaderFinished { + /// The height of the network head. height: u64, + /// How much time fetching took in milliseconds. took_ms: u64, }, + /// Fetching headers of a specific block range just started. FetchingHeadersStarted { + /// Start of the range. from_height: u64, + /// End of the range (included). to_height: u64, }, + /// Fetching headers of a specific block range just finished. FetchingHeadersFinished { + /// Start of the range. from_height: u64, + /// End of the range (included). to_height: u64, + /// How much time fetching took in milliseconds. took_ms: u64, }, + /// Fetching headers of a specific block range just failed. FetchingHeadersFailed { + /// Start of the range. from_height: u64, + /// End of the range (included). to_height: u64, + /// A human readable error. error: String, + /// How much time fetching took in milliseconds. took_ms: u64, }, + /// Header syncing fatal error. FatalSyncerError { + /// A human readable error. error: String, }, + /// Pruned headers up to and including specified height. PrunedHeaders { + /// Last header height that was pruned to_height: u64, }, + /// Pruning fatal error. FatalPrunerError { + /// A human readable error. error: String, }, + /// Network was compromised. + /// + /// This happens when a valid bad encoding fraud proof is received. + /// Ideally it would never happen, but protection needs to exist. + /// In case of compromised network, syncing and data sampling will + /// stop immediately. NetworkCompromised, + /// Node stopped. NodeStopped, } @@ -322,11 +390,16 @@ impl From for NodeEvent { } } +/// Information about a node event. #[derive(Record)] pub struct NodeEventInfo { + /// The event that occurred. pub event: NodeEvent, - pub timestamp: u64, // Unix timestamp in milliseconds for now + /// Unix timestamp in milliseconds when the event occurred. + pub timestamp: u64, + /// Source file path where the event was emitted. pub file_path: String, + /// Line number in source file where event was emitted. pub file_line: u32, } From 0ec839469cac05a8f1f129d729803a6d9962e4fb Mon Sep 17 00:00:00 2001 From: sebasti810 Date: Thu, 12 Dec 2024 14:23:58 +0100 Subject: [PATCH 06/13] refac: update docs and use nodebuilder and new types --- Cargo.lock | 11 ---- node-native/Cargo.toml | 7 +-- node-native/src/bin/uniffi-bindgen.rs | 5 ++ node-native/src/lib.rs | 82 +++++++++++++++++++-------- node-native/src/types.rs | 14 +++-- 5 files changed, 74 insertions(+), 45 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 294562e5..16e1f976 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5342,15 +5342,6 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" -[[package]] -name = "signal-hook-registry" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" -dependencies = [ - "libc", -] - [[package]] name = "signature" version = "2.2.0" @@ -5761,9 +5752,7 @@ dependencies = [ "bytes", "libc", "mio", - "parking_lot", "pin-project-lite", - "signal-hook-registry", "socket2", "tokio-macros", "windows-sys 0.52.0", diff --git a/node-native/Cargo.toml b/node-native/Cargo.toml index e097fa66..693b6e7e 100644 --- a/node-native/Cargo.toml +++ b/node-native/Cargo.toml @@ -16,9 +16,8 @@ lumina-node.workspace = true celestia-types.workspace = true tendermint.workspace = true libp2p.workspace = true - -uniffi = { version = "0.28.3", features = ["bindgen", "tokio", "cli"] } -tokio = { version = "1.0", features = ["full"] } redb = "2.1.1" thiserror = "1.0.61" -serde_json = "1.0.64" \ No newline at end of file +serde_json = "1.0.64" +uniffi = { version = "0.28.3", features = ["bindgen", "tokio", "cli"] } +tokio = { version = "1.38.0", features = ["macros", "sync"] } \ No newline at end of file diff --git a/node-native/src/bin/uniffi-bindgen.rs b/node-native/src/bin/uniffi-bindgen.rs index f6cff6cf..c89b7813 100644 --- a/node-native/src/bin/uniffi-bindgen.rs +++ b/node-native/src/bin/uniffi-bindgen.rs @@ -1,3 +1,8 @@ +//! Binary executable for generating UniFFI bindings. +//! +//! This binary is used by the build system to generate language bindings. + +/// This is the entry point for the uniffi-bindgen binary. fn main() { uniffi::uniffi_bindgen_main() } diff --git a/node-native/src/lib.rs b/node-native/src/lib.rs index 36fc6cf8..54c3e145 100644 --- a/node-native/src/lib.rs +++ b/node-native/src/lib.rs @@ -1,3 +1,8 @@ +//! Native library providing Rust to mobile language bindings for the Lumina node. +//! +//! This crate uses Mozillas UniFFI to generate Swift and Kotlin bindings for the Lumina node, +//! allowing it to be used from iOS and Android applications. + mod types; use celestia_types::ExtendedHeader; @@ -5,17 +10,18 @@ use libp2p::identity::Keypair; use lumina_node::{ blockstore::RedbBlockstore, events::{EventSubscriber, TryRecvError}, - network::{canonical_network_bootnodes, network_id}, + network, store::RedbStore, - Node, NodeConfig, NodeError, + Node, NodeError, }; -use std::{path::PathBuf, str::FromStr, sync::Arc, time::Duration}; +use std::{path::PathBuf, str::FromStr, sync::Arc}; use tendermint::hash::Hash; use thiserror::Error; use tokio::sync::Mutex; use types::{Network, NetworkInfo, NodeEvent, PeerId, PeerTrackerInfo, SyncingInfo}; use uniffi::Object; +/// Result type alias for LuminaNode operations that can fail with a LuminaError pub type Result = std::result::Result; /// Returns the platform-specific base path for storing Lumina data. @@ -52,24 +58,55 @@ fn get_base_path() -> Result { } } +/// Represents all possible errors that can occur in the LuminaNode. #[derive(Error, Debug, uniffi::Error)] pub enum LuminaError { + /// Error returned when trying to perform operations on a node that isn't running #[error("Node is not running")] NodeNotRunning, + + /// Error returned when network operations fail #[error("Network error: {msg}")] - NetworkError { msg: String }, + NetworkError { + /// Description of the network error + msg: String, + }, + + /// Error returned when storage operations fail #[error("Storage error: {msg}")] - StorageError { msg: String }, + StorageError { + /// Description of the storage error + msg: String, + }, + + /// Error returned when trying to start a node that's already running #[error("Node is already running")] AlreadyRunning, + + /// Error returned when a mutex lock operation fails #[error("Lock error")] LockError, + + /// Error returned when a hash string is invalid or malformed #[error("Invalid hash format: {msg}")] - InvalidHash { msg: String }, + InvalidHash { + /// Description of why the hash is invalid + msg: String, + }, + + /// Error returned when a header is invalid or malformed #[error("Invalid header format: {msg}")] - InvalidHeader { msg: String }, + InvalidHeader { + /// Description of why the header is invalid + msg: String, + }, + + /// Error returned when storage initialization fails #[error("Storage initialization failed: {msg}")] - StorageInit { msg: String }, + StorageInit { + /// Description of why storage initialization failed + msg: String, + }, } impl From for LuminaError { @@ -108,7 +145,8 @@ impl LuminaNode { return Err(LuminaError::AlreadyRunning); } - let network_id = network_id(self.network.into()); + let network = network::Network::from(&self.network); + let network_id = network.id(); let base_path = get_base_path()?; @@ -131,26 +169,22 @@ impl LuminaNode { let blockstore = RedbBlockstore::new(db); - let p2p_bootnodes = canonical_network_bootnodes(self.network.into()).collect::>(); - + let p2p_bootnodes = network.canonical_bootnodes().collect::>(); let p2p_local_keypair = Keypair::generate_ed25519(); - let config = NodeConfig { - network_id: network_id.to_string(), - p2p_bootnodes, - p2p_local_keypair, - p2p_listen_on: vec![], - sync_batch_size: 128, - custom_syncing_window: Some(Duration::from_secs(60 * 60 * 24)), - store, - blockstore, - }; - - let new_node = Node::new(config) + let builder = Node::builder() + .store(store) + .blockstore(blockstore) + .network(network) + .bootnodes(p2p_bootnodes) + .keypair(p2p_local_keypair) + .sync_batch_size(128); + + let (new_node, subscriber) = builder + .start_subscribed() .await .map_err(|e| LuminaError::NetworkError { msg: e.to_string() })?; - let subscriber = new_node.event_subscriber(); let mut events_guard = self.events_subscriber.lock().await; *events_guard = Some(subscriber); diff --git a/node-native/src/types.rs b/node-native/src/types.rs index d84bd77e..d795619f 100644 --- a/node-native/src/types.rs +++ b/node-native/src/types.rs @@ -11,7 +11,7 @@ use std::time::SystemTime; use uniffi::{Enum, Record}; /// Supported Celestia networks. -#[derive(Debug, Default, Clone, Copy, Enum)] +#[derive(Debug, Default, Clone, Enum)] pub enum Network { /// Celestia mainnet. #[default] @@ -20,18 +20,20 @@ pub enum Network { Arabica, /// Mocha testnet. Mocha, - /// Private local network. - Private, + /// Custom network. + Custom { id: String }, } // From implementation for converting between Lumina and Uniffi types -impl From for network::Network { - fn from(network: Network) -> Self { +impl From<&Network> for network::Network { + fn from(network: &Network) -> Self { match network { Network::Mainnet => network::Network::Mainnet, Network::Arabica => network::Network::Arabica, Network::Mocha => network::Network::Mocha, - Network::Private => network::Network::Private, + Network::Custom { id } => { + network::Network::Custom(network::NetworkId::new(id).expect("invalid network id")) + } } } } From 049adb134544266e35da9979d548c95dcc4b9ba5 Mon Sep 17 00:00:00 2001 From: sebasti810 Date: Fri, 13 Dec 2024 10:31:56 +0100 Subject: [PATCH 07/13] fix: remove system-configuration patch --- Cargo.lock | 91 +++++++++++++++++++----------------------------------- Cargo.toml | 1 - 2 files changed, 31 insertions(+), 61 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 16e1f976..4742b280 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 4 +version = 3 [[package]] name = "addr2line" @@ -497,9 +497,9 @@ dependencies = [ "serde_json", "serde_path_to_error", "serde_urlencoded", - "sync_wrapper 1.0.2", + "sync_wrapper", "tokio", - "tower 0.5.1", + "tower 0.5.2", "tower-layer", "tower-service", "tracing", @@ -520,7 +520,7 @@ dependencies = [ "mime", "pin-project-lite", "rustversion", - "sync_wrapper 1.0.2", + "sync_wrapper", "tower-layer", "tower-service", "tracing", @@ -825,7 +825,7 @@ checksum = "eee4243f1f26fc7a42710e7439c149e2b10b05472f88090acce52632f231a73a" dependencies = [ "camino", "cargo-platform", - "semver 1.0.23", + "semver 1.0.24", "serde", "serde_json", "thiserror 1.0.69", @@ -2029,9 +2029,9 @@ checksum = "b07f60793ff0a4d9cef0f18e63b5357e06209987153a64648c972c1e5aff336f" [[package]] name = "hickory-proto" -version = "0.24.1" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07698b8420e2f0d6447a436ba999ec85d8fbf2a398bbd737b82cac4a2e96e512" +checksum = "447afdcdb8afb9d0a852af6dc65d9b285ce720ed7a59e42a8bf2e931c67bc1b5" dependencies = [ "async-trait", "cfg-if", @@ -2040,7 +2040,7 @@ dependencies = [ "futures-channel", "futures-io", "futures-util", - "idna 0.4.0", + "idna", "ipnet", "once_cell", "rand", @@ -2054,9 +2054,9 @@ dependencies = [ [[package]] name = "hickory-resolver" -version = "0.24.1" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28757f23aa75c98f254cf0405e6d8c25b831b32921b050a66692427679b1f243" +checksum = "0a2e2aba9c389ce5267d31cf1e4dace82390ae276b0b364ea55630b1fa1b44b4" dependencies = [ "cfg-if", "futures-util", @@ -2397,16 +2397,6 @@ dependencies = [ "web-sys", ] -[[package]] -name = "idna" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" -dependencies = [ - "unicode-bidi", - "unicode-normalization", -] - [[package]] name = "idna" version = "1.0.3" @@ -4613,18 +4603,18 @@ dependencies = [ [[package]] name = "redb" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84b1de48a7cf7ba193e81e078d17ee2b786236eed1d3f7c60f8a09545efc4925" +checksum = "a7c2a94325f9c5826b17c42af11067230f503747f870117a28180e85696e21ba" dependencies = [ "libc", ] [[package]] name = "redox_syscall" -version = "0.5.7" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" +checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" dependencies = [ "bitflags 2.6.0", ] @@ -4916,7 +4906,7 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ - "semver 1.0.23", + "semver 1.0.24", ] [[package]] @@ -4943,9 +4933,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.19" +version = "0.23.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "934b404430bb06b3fae2cba809eb45a1ab1aecd64491213d7c3301b88393f8d1" +checksum = "5065c3f250cbd332cd894be57c40fa52387247659b14a2d6041d121547903b1b" dependencies = [ "log", "once_cell", @@ -5157,9 +5147,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.23" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" +checksum = "3cb6eb87a131f756572d7fb904f6e7b68633f09cca868c5df1c4b8d1a694bbba" dependencies = [ "serde", ] @@ -5190,9 +5180,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.215" +version = "1.0.216" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" +checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e" dependencies = [ "serde_derive", ] @@ -5219,9 +5209,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.215" +version = "1.0.216" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" +checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e" dependencies = [ "proc-macro2", "quote", @@ -5520,12 +5510,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "sync_wrapper" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" - [[package]] name = "sync_wrapper" version = "1.0.2" @@ -5546,7 +5530,8 @@ dependencies = [ [[package]] name = "system-configuration" version = "0.6.1" -source = "git+https://github.com/mullvad/system-configuration-rs?tag=v0.6.1#c7a1626d79410a2f35e0361de952b6076a33d95c" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" dependencies = [ "bitflags 2.6.0", "core-foundation", @@ -5556,7 +5541,8 @@ dependencies = [ [[package]] name = "system-configuration-sys" version = "0.6.0" -source = "git+https://github.com/mullvad/system-configuration-rs?tag=v0.6.1#c7a1626d79410a2f35e0361de952b6076a33d95c" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" dependencies = [ "core-foundation-sys", "libc", @@ -5896,14 +5882,14 @@ dependencies = [ [[package]] name = "tower" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2873938d487c3cfb9aed7546dc9f2711d867c9f90c46b889989a2cb84eba6b4f" +checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" dependencies = [ "futures-core", "futures-util", "pin-project-lite", - "sync_wrapper 0.1.2", + "sync_wrapper", "tokio", "tower-layer", "tower-service", @@ -6052,27 +6038,12 @@ version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7e51b68083f157f853b6379db119d1c1be0e6e4dec98101079dec41f6f5cf6df" -[[package]] -name = "unicode-bidi" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893" - [[package]] name = "unicode-ident" version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" -[[package]] -name = "unicode-normalization" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" -dependencies = [ - "tinyvec", -] - [[package]] name = "unicode-width" version = "0.1.14" @@ -6245,7 +6216,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" dependencies = [ "form_urlencoded", - "idna 1.0.3", + "idna", "percent-encoding", ] diff --git a/Cargo.toml b/Cargo.toml index 21ef9c30..42e7aece 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,7 +27,6 @@ prost-types = "0.13.3" #libp2p = { path = "../../rust-libp2p/libp2p" } #libp2p-core = { path = "../../rust-libp2p/core" } #libp2p-swarm = { path = "../../rust-libp2p/swarm" } -system-configuration = { git = "https://github.com/mullvad/system-configuration-rs", tag = "v0.6.1" } # Uncomment this if you need debug symbols in release. # Also check node-wasm's `Cargo.toml`. From 9d2bb14d28761206b20ca15926a196a0ce7fd09b Mon Sep 17 00:00:00 2001 From: sebasti810 Date: Sat, 14 Dec 2024 18:31:17 +0100 Subject: [PATCH 08/13] refac: rename to node-uniffi, introduce uniffi feature, start reusing types --- Cargo.lock | 32 +++++----- Cargo.toml | 2 +- {node-native => node-uniffi}/Cargo.toml | 6 +- {node-native => node-uniffi}/build-android.sh | 0 {node-native => node-uniffi}/build-ios.sh | 0 .../src/bin/uniffi-bindgen.rs | 0 {node-native => node-uniffi}/src/lib.rs | 21 ++++--- {node-native => node-uniffi}/src/types.rs | 60 +++++++------------ node/Cargo.toml | 3 + node/src/lib.rs | 3 + node/src/network.rs | 16 +++-- node/src/peer_tracker.rs | 1 + types/Cargo.toml | 2 + 13 files changed, 72 insertions(+), 74 deletions(-) rename {node-native => node-uniffi}/Cargo.toml (76%) rename {node-native => node-uniffi}/build-android.sh (100%) rename {node-native => node-uniffi}/build-ios.sh (100%) rename {node-native => node-uniffi}/src/bin/uniffi-bindgen.rs (100%) rename {node-native => node-uniffi}/src/lib.rs (97%) rename {node-native => node-uniffi}/src/types.rs (89%) diff --git a/Cargo.lock b/Cargo.lock index 4742b280..778fafff 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -942,6 +942,7 @@ dependencies = [ "tendermint-proto", "thiserror 1.0.69", "time", + "uniffi", "wasm-bindgen-test", ] @@ -3547,6 +3548,7 @@ dependencies = [ "tokio", "tokio-util", "tracing", + "uniffi", "void", "wasm-bindgen", "wasm-bindgen-futures", @@ -3554,6 +3556,21 @@ dependencies = [ "web-time", ] +[[package]] +name = "lumina-node-uniffi" +version = "0.1.0" +dependencies = [ + "celestia-types", + "libp2p", + "lumina-node", + "redb", + "serde_json", + "tendermint", + "thiserror 1.0.69", + "tokio", + "uniffi", +] + [[package]] name = "lumina-node-wasm" version = "0.7.0" @@ -3794,21 +3811,6 @@ dependencies = [ "unsigned-varint 0.7.2", ] -[[package]] -name = "native" -version = "0.1.0" -dependencies = [ - "celestia-types", - "libp2p", - "lumina-node", - "redb", - "serde_json", - "tendermint", - "thiserror 1.0.69", - "tokio", - "uniffi", -] - [[package]] name = "netlink-packet-core" version = "0.7.0" diff --git a/Cargo.toml b/Cargo.toml index 42e7aece..b378aff1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [workspace] resolver = "2" -members = ["cli", "grpc", "node", "node-wasm", "node-native", "proto", "rpc", "types"] +members = ["cli", "grpc", "node", "node-wasm", "node-uniffi", "proto", "rpc", "types"] [workspace.dependencies] blockstore = "0.7.1" diff --git a/node-native/Cargo.toml b/node-uniffi/Cargo.toml similarity index 76% rename from node-native/Cargo.toml rename to node-uniffi/Cargo.toml index 693b6e7e..ea737524 100644 --- a/node-native/Cargo.toml +++ b/node-uniffi/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "native" +name = "lumina-node-uniffi" version = "0.1.0" edition = "2021" description = "Mobile bindings for Lumina node" @@ -12,8 +12,8 @@ name = "uniffi-bindgen" path = "./src/bin/uniffi-bindgen.rs" [dependencies] -lumina-node.workspace = true -celestia-types.workspace = true +lumina-node = { workspace = true, features = ["uniffi"] } +celestia-types = { workspace = true, features = ["uniffi"] } tendermint.workspace = true libp2p.workspace = true redb = "2.1.1" diff --git a/node-native/build-android.sh b/node-uniffi/build-android.sh similarity index 100% rename from node-native/build-android.sh rename to node-uniffi/build-android.sh diff --git a/node-native/build-ios.sh b/node-uniffi/build-ios.sh similarity index 100% rename from node-native/build-ios.sh rename to node-uniffi/build-ios.sh diff --git a/node-native/src/bin/uniffi-bindgen.rs b/node-uniffi/src/bin/uniffi-bindgen.rs similarity index 100% rename from node-native/src/bin/uniffi-bindgen.rs rename to node-uniffi/src/bin/uniffi-bindgen.rs diff --git a/node-native/src/lib.rs b/node-uniffi/src/lib.rs similarity index 97% rename from node-native/src/lib.rs rename to node-uniffi/src/lib.rs index 54c3e145..442bc152 100644 --- a/node-native/src/lib.rs +++ b/node-uniffi/src/lib.rs @@ -2,6 +2,7 @@ //! //! This crate uses Mozillas UniFFI to generate Swift and Kotlin bindings for the Lumina node, //! allowing it to be used from iOS and Android applications. +#![cfg(not(target_arch = "wasm32"))] mod types; @@ -10,7 +11,8 @@ use libp2p::identity::Keypair; use lumina_node::{ blockstore::RedbBlockstore, events::{EventSubscriber, TryRecvError}, - network, + network::Network, + node::PeerTrackerInfo, store::RedbStore, Node, NodeError, }; @@ -18,9 +20,13 @@ use std::{path::PathBuf, str::FromStr, sync::Arc}; use tendermint::hash::Hash; use thiserror::Error; use tokio::sync::Mutex; -use types::{Network, NetworkInfo, NodeEvent, PeerId, PeerTrackerInfo, SyncingInfo}; +use types::{NetworkInfo, NodeEvent, PeerId, SyncingInfo}; use uniffi::Object; +uniffi::setup_scaffolding!(); + +lumina_node::uniffi_reexport_scaffolding!(); + /// Result type alias for LuminaNode operations that can fail with a LuminaError pub type Result = std::result::Result; @@ -145,8 +151,7 @@ impl LuminaNode { return Err(LuminaError::AlreadyRunning); } - let network = network::Network::from(&self.network); - let network_id = network.id(); + let network_id = self.network.id(); let base_path = get_base_path()?; @@ -169,13 +174,13 @@ impl LuminaNode { let blockstore = RedbBlockstore::new(db); - let p2p_bootnodes = network.canonical_bootnodes().collect::>(); + let p2p_bootnodes = self.network.canonical_bootnodes().collect::>(); let p2p_local_keypair = Keypair::generate_ed25519(); let builder = Node::builder() .store(store) .blockstore(blockstore) - .network(network) + .network(self.network.clone()) .bootnodes(p2p_bootnodes) .keypair(p2p_local_keypair) .sync_batch_size(128); @@ -216,7 +221,7 @@ impl LuminaNode { pub async fn peer_tracker_info(&self) -> Result { let node_guard = self.node.lock().await; let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; - Ok(node.peer_tracker_info().into()) + Ok(node.peer_tracker_info()) } /// Waits until the node is connected to at least one peer. @@ -409,5 +414,3 @@ impl LuminaNode { } } } - -uniffi::setup_scaffolding!(); diff --git a/node-native/src/types.rs b/node-uniffi/src/types.rs similarity index 89% rename from node-native/src/types.rs rename to node-uniffi/src/types.rs index d795619f..35db5040 100644 --- a/node-native/src/types.rs +++ b/node-uniffi/src/types.rs @@ -3,55 +3,35 @@ use libp2p::swarm::NetworkInfo as Libp2pNetworkInfo; use libp2p::PeerId as Libp2pPeerId; use lumina_node::block_ranges::BlockRange as LuminaBlockRange; use lumina_node::events::{NodeEvent as LuminaNodeEvent, NodeEventInfo as LuminaNodeEventInfo}; -use lumina_node::network; -use lumina_node::node::PeerTrackerInfo as LuminaPeerTrackerInfo; use lumina_node::node::SyncingInfo as LuminaSyncingInfo; use std::str::FromStr; use std::time::SystemTime; -use uniffi::{Enum, Record}; +use uniffi::Record; -/// Supported Celestia networks. -#[derive(Debug, Default, Clone, Enum)] -pub enum Network { - /// Celestia mainnet. - #[default] - Mainnet, - /// Arabica testnet. - Arabica, - /// Mocha testnet. - Mocha, - /// Custom network. - Custom { id: String }, -} +/// Configuration options for the Lumina node +#[derive(Debug, Clone, Record)] +pub struct NodeStartConfig { + /// Custom syncing window in seconds, defines maximum age of headers + /// considered for syncing and sampling + pub syncing_window_secs: Option, -// From implementation for converting between Lumina and Uniffi types -impl From<&Network> for network::Network { - fn from(network: &Network) -> Self { - match network { - Network::Mainnet => network::Network::Mainnet, - Network::Arabica => network::Network::Arabica, - Network::Mocha => network::Network::Mocha, - Network::Custom { id } => { - network::Network::Custom(network::NetworkId::new(id).expect("invalid network id")) - } - } - } -} + /// Custom pruning delay after the syncing window in seconds + pub pruning_delay_secs: Option, + + /// Maximum number of headers in batch while syncing + pub sync_batch_size: Option, -/// Statistics of the connected peers -#[derive(Debug, Clone, Default, Record)] -pub struct PeerTrackerInfo { - /// Number of the connected peers. - pub num_connected_peers: u64, - /// Number of the connected trusted peers. - pub num_connected_trusted_peers: u64, + /// Whether to listen for incoming connections + pub enable_listener: bool, } -impl From for PeerTrackerInfo { - fn from(info: LuminaPeerTrackerInfo) -> Self { +impl Default for NodeStartConfig { + fn default() -> Self { Self { - num_connected_peers: info.num_connected_peers, - num_connected_trusted_peers: info.num_connected_trusted_peers, + syncing_window_secs: None, + pruning_delay_secs: None, + sync_batch_size: None, + enable_listener: false, } } } diff --git a/node/Cargo.toml b/node/Cargo.toml index d6b24da7..ce04d344 100644 --- a/node/Cargo.toml +++ b/node/Cargo.toml @@ -69,6 +69,7 @@ libp2p = { workspace = true, features = [ redb = "2.1.1" rustls-pemfile = "2.1.2" rustls-pki-types = "1.7.0" +uniffi = { version = "0.28.0", optional = true } [target.'cfg(target_arch = "wasm32")'.dependencies] backoff = { version = "0.4.0", features = ["wasm-bindgen"] } @@ -110,7 +111,9 @@ serde_json = "1.0.117" tempfile = "3.10.1" [features] +default-features = [] test-utils = ["celestia-types/test-utils"] +uniffi = ["dep:uniffi", "celestia-types/uniffi"] [package.metadata.docs.rs] features = ["test-utils"] diff --git a/node/src/lib.rs b/node/src/lib.rs index 70c76ec3..f377f1be 100644 --- a/node/src/lib.rs +++ b/node/src/lib.rs @@ -21,5 +21,8 @@ mod utils; #[cfg(all(target_arch = "wasm32", test))] wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); +#[cfg(feature = "uniffi")] +uniffi::setup_scaffolding!(); + #[doc(inline)] pub use crate::node::{Node, NodeBuilder, NodeError, Result}; diff --git a/node/src/network.rs b/node/src/network.rs index 6056651e..c57b2aca 100644 --- a/node/src/network.rs +++ b/node/src/network.rs @@ -9,6 +9,7 @@ use serde::{Deserialize, Serialize}; use thiserror::Error; /// Supported Celestia networks. +#[cfg_attr(feature = "uniffi", derive(uniffi::Enum))] #[derive(Debug, Default, Clone, PartialEq, Eq)] pub enum Network { /// Celestia mainnet. @@ -28,8 +29,11 @@ pub enum Network { pub struct InvalidNetworkId(String); /// Valid network id +#[cfg_attr(feature = "uniffi", derive(uniffi::Record))] #[derive(Debug, Clone, PartialEq, Eq)] -pub struct NetworkId(String); +pub struct NetworkId { + pub id: String, // / Rename from 0 to id since uniffi doesn't support tuple structs +} impl NetworkId { /// Creates validated network id. @@ -37,14 +41,14 @@ impl NetworkId { if id.contains('/') { Err(InvalidNetworkId(id.to_owned())) } else { - Ok(NetworkId(id.to_owned())) + Ok(NetworkId { id: id.to_owned() }) } } } impl AsRef for NetworkId { fn as_ref(&self) -> &str { - &self.0 + &self.id } } @@ -52,7 +56,7 @@ impl Deref for NetworkId { type Target = str; fn deref(&self) -> &str { - &self.0 + &self.id } } @@ -66,7 +70,7 @@ impl FromStr for NetworkId { impl fmt::Display for NetworkId { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&self.0) + f.write_str(&self.id) } } @@ -87,7 +91,7 @@ impl Network { Network::Mainnet => "celestia", Network::Arabica => "arabica-11", Network::Mocha => "mocha-4", - Network::Custom(ref s) => &s.0, + Network::Custom(ref s) => &s.id, } } diff --git a/node/src/peer_tracker.rs b/node/src/peer_tracker.rs index 8002174e..3641cc11 100644 --- a/node/src/peer_tracker.rs +++ b/node/src/peer_tracker.rs @@ -22,6 +22,7 @@ pub struct PeerTracker { } /// Statistics of the connected peers +#[cfg_attr(feature = "uniffi", derive(uniffi::Record))] #[derive(Debug, Clone, Default, Serialize, Deserialize)] pub struct PeerTrackerInfo { /// Number of the connected peers. diff --git a/types/Cargo.toml b/types/Cargo.toml index 3084e80e..dc18003d 100644 --- a/types/Cargo.toml +++ b/types/Cargo.toml @@ -40,6 +40,7 @@ serde_repr = { version = "0.1.19", optional = true } sha2 = "0.10.6" thiserror = "1.0.61" time = { version = "0.3.36", default-features = false } +uniffi = { version = "0.28.0", optional = true } [dev-dependencies] ed25519-consensus = "2.1.0" @@ -62,6 +63,7 @@ wasm-bindgen = ["time/wasm-bindgen"] [package.metadata.docs.rs] features = ["p2p", "test-utils"] rustdoc-args = ["--cfg", "docsrs"] +uniffi = ["dep:uniffi"] [package.metadata.cargo-udeps.ignore] development = ["indoc"] From 995f26574bc1a29fdb980173ec1549ed3b5ea938 Mon Sep 17 00:00:00 2001 From: sebasti810 Date: Tue, 17 Dec 2024 10:04:32 +0100 Subject: [PATCH 09/13] fix: update build scripts since we need lumina-node types --- Cargo.lock | 1 + node-uniffi/Cargo.toml | 1 + node-uniffi/build-android.sh | 6 +- node-uniffi/build-ios.sh | 51 ++++++----- node-uniffi/src/error.rs | 72 ++++++++++++++++ node-uniffi/src/lib.rs | 159 +++++------------------------------ node-uniffi/src/types.rs | 153 ++++++++++++++++++++++++++++----- node/Cargo.toml | 7 +- node/src/network.rs | 3 +- 9 files changed, 270 insertions(+), 183 deletions(-) create mode 100644 node-uniffi/src/error.rs diff --git a/Cargo.lock b/Cargo.lock index 778fafff..75ca3570 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3561,6 +3561,7 @@ name = "lumina-node-uniffi" version = "0.1.0" dependencies = [ "celestia-types", + "directories", "libp2p", "lumina-node", "redb", diff --git a/node-uniffi/Cargo.toml b/node-uniffi/Cargo.toml index ea737524..05c5333e 100644 --- a/node-uniffi/Cargo.toml +++ b/node-uniffi/Cargo.toml @@ -19,5 +19,6 @@ libp2p.workspace = true redb = "2.1.1" thiserror = "1.0.61" serde_json = "1.0.64" +directories = "5.0.1" uniffi = { version = "0.28.3", features = ["bindgen", "tokio", "cli"] } tokio = { version = "1.38.0", features = ["macros", "sync"] } \ No newline at end of file diff --git a/node-uniffi/build-android.sh b/node-uniffi/build-android.sh index 335998e1..54c3273d 100755 --- a/node-uniffi/build-android.sh +++ b/node-uniffi/build-android.sh @@ -1,6 +1,6 @@ #!/bin/bash -cargo build -p native +cargo build -p lumina-node-uniffi rustup target add \ aarch64-linux-android \ @@ -16,4 +16,6 @@ cargo ndk -o ./app/src/main/jniLibs \ -t x86_64 \ build --release -cargo run --bin uniffi-bindgen generate --library ../target/debug/libnative.dylib --language kotlin --out-dir ./app/src/main/java/tech/forgen/native/rust \ No newline at end of file +cargo run --bin uniffi-bindgen generate --library ../target/debug/liblumina_node_uniffi.dylib --language kotlin --out-dir ./app/src/main/java/tech/forgen/lumina_node_uniffi/rust + +echo "Android build complete" \ No newline at end of file diff --git a/node-uniffi/build-ios.sh b/node-uniffi/build-ios.sh index 9cf73bce..fdc326dd 100755 --- a/node-uniffi/build-ios.sh +++ b/node-uniffi/build-ios.sh @@ -1,32 +1,37 @@ #!/bin/bash - -cargo build -p native -mkdir -p ./bindings -mkdir -p ./ios - -cargo run --bin uniffi-bindgen generate --library ../target/debug/libnative.dylib --language swift --out-dir ./bindings - +cd .. + for TARGET in \ - aarch64-apple-darwin \ aarch64-apple-ios \ - aarch64-apple-ios-sim \ - x86_64-apple-darwin \ - x86_64-apple-ios + aarch64-apple-ios-sim do rustup target add $TARGET cargo build --release --target=$TARGET done - -mv ./bindings/nativeFFI.modulemap ./bindings/module.modulemap - -rm ./ios/Native.swift -mv ./bindings/native.swift ./ios/Native.swift - -rm -rf "ios/Native.xcframework" + +cd node-uniffi + +rm -rf ./bindings ./ios +mkdir -p ./bindings +mkdir -p ./ios +mkdir -p ./bindings/Headers + +cargo run --bin uniffi-bindgen generate --library ../target/debug/liblumina_node_uniffi.dylib --language swift --out-dir ./bindings + +cat "./bindings/lumina_node_uniffiFFI.modulemap" "./bindings/lumina_nodeFFI.modulemap" > "./bindings/Headers/module.modulemap" + +cp ./bindings/*.h ./bindings/Headers/ + +rm -rf "ios/lumina.xcframework" + xcodebuild -create-xcframework \ - -library ../target/aarch64-apple-ios-sim/release/libnative.a -headers ./bindings \ - -library ../target/aarch64-apple-ios/release/libnative.a -headers ./bindings \ - -output "ios/Native.xcframework" - -rm -rf bindings \ No newline at end of file + -library ../target/aarch64-apple-ios-sim/release/liblumina_node_uniffi.a -headers ./bindings/Headers \ + -library ../target/aarch64-apple-ios/release/liblumina_node_uniffi.a -headers ./bindings/Headers \ + -output "ios/lumina.xcframework" + +cp ./bindings/*.swift ./ios/ + +rm -rf bindings + +echo "iOS build complete" \ No newline at end of file diff --git a/node-uniffi/src/error.rs b/node-uniffi/src/error.rs new file mode 100644 index 00000000..646188cf --- /dev/null +++ b/node-uniffi/src/error.rs @@ -0,0 +1,72 @@ +use lumina_node::NodeError; +use thiserror::Error; + +/// Result type alias for LuminaNode operations that can fail with a LuminaError +pub type Result = std::result::Result; + +/// Represents all possible errors that can occur in the LuminaNode. +#[derive(Error, Debug, uniffi::Error)] +pub enum LuminaError { + /// Error returned when trying to perform operations on a node that isn't running + #[error("Node is not running")] + NodeNotRunning, + + /// Error returned when network operations fail + #[error("Network error: {msg}")] + NetworkError { + /// Description of the network error + msg: String, + }, + + /// Error returned when storage operations fail + #[error("Storage error: {msg}")] + StorageError { + /// Description of the storage error + msg: String, + }, + + /// Error returned when trying to start a node that's already running + #[error("Node is already running")] + AlreadyRunning, + + /// Error returned when a mutex lock operation fails + #[error("Lock error")] + LockError, + + /// Error returned when a hash string is invalid or malformed + #[error("Invalid hash format: {msg}")] + InvalidHash { + /// Description of why the hash is invalid + msg: String, + }, + + /// Error returned when a header is invalid or malformed + #[error("Invalid header format: {msg}")] + InvalidHeader { + /// Description of why the header is invalid + msg: String, + }, + + /// Error returned when storage initialization fails + #[error("Storage initialization failed: {msg}")] + StorageInit { + /// Description of why storage initialization failed + msg: String, + }, +} + +impl From for LuminaError { + fn from(error: NodeError) -> Self { + LuminaError::NetworkError { + msg: error.to_string(), + } + } +} + +impl From for LuminaError { + fn from(e: libp2p::multiaddr::Error) -> Self { + LuminaError::NetworkError { + msg: format!("Invalid multiaddr: {}", e), + } + } +} diff --git a/node-uniffi/src/lib.rs b/node-uniffi/src/lib.rs index 442bc152..39ce6a3f 100644 --- a/node-uniffi/src/lib.rs +++ b/node-uniffi/src/lib.rs @@ -4,125 +4,29 @@ //! allowing it to be used from iOS and Android applications. #![cfg(not(target_arch = "wasm32"))] +mod error; mod types; use celestia_types::ExtendedHeader; -use libp2p::identity::Keypair; +use error::{LuminaError, Result}; use lumina_node::{ blockstore::RedbBlockstore, events::{EventSubscriber, TryRecvError}, network::Network, node::PeerTrackerInfo, store::RedbStore, - Node, NodeError, + Node, }; -use std::{path::PathBuf, str::FromStr, sync::Arc}; +use std::{str::FromStr, sync::Arc}; use tendermint::hash::Hash; -use thiserror::Error; use tokio::sync::Mutex; -use types::{NetworkInfo, NodeEvent, PeerId, SyncingInfo}; +use types::{NetworkInfo, NodeEvent, NodeStartConfig, PeerId, SyncingInfo}; use uniffi::Object; uniffi::setup_scaffolding!(); lumina_node::uniffi_reexport_scaffolding!(); -/// Result type alias for LuminaNode operations that can fail with a LuminaError -pub type Result = std::result::Result; - -/// Returns the platform-specific base path for storing Lumina data. -/// -/// The function determines the base path based on the target operating system: -/// - **iOS**: `~/Library/Application Support/lumina` -/// - **Android**: Value of the `LUMINA_DATA_DIR` environment variable -/// - **Other platforms**: Returns an error indicating unsupported platform. -fn get_base_path() -> Result { - #[cfg(target_os = "ios")] - { - std::env::var("HOME") - .map(PathBuf::from) - .map(|p| p.join("Library/Application Support/lumina")) - .map_err(|e| LuminaError::StorageError { - msg: format!("Could not get HOME directory: {}", e), - }) - } - - #[cfg(target_os = "android")] - { - std::env::var("LUMINA_DATA_DIR") - .map(PathBuf::from) - .map_err(|e| LuminaError::StorageError { - msg: format!("Could not get LUMINA_DATA_DIR: {}", e), - }) - } - - #[cfg(not(any(target_os = "ios", target_os = "android")))] - { - Err(LuminaError::StorageError { - msg: "Unsupported platform".to_string(), - }) - } -} - -/// Represents all possible errors that can occur in the LuminaNode. -#[derive(Error, Debug, uniffi::Error)] -pub enum LuminaError { - /// Error returned when trying to perform operations on a node that isn't running - #[error("Node is not running")] - NodeNotRunning, - - /// Error returned when network operations fail - #[error("Network error: {msg}")] - NetworkError { - /// Description of the network error - msg: String, - }, - - /// Error returned when storage operations fail - #[error("Storage error: {msg}")] - StorageError { - /// Description of the storage error - msg: String, - }, - - /// Error returned when trying to start a node that's already running - #[error("Node is already running")] - AlreadyRunning, - - /// Error returned when a mutex lock operation fails - #[error("Lock error")] - LockError, - - /// Error returned when a hash string is invalid or malformed - #[error("Invalid hash format: {msg}")] - InvalidHash { - /// Description of why the hash is invalid - msg: String, - }, - - /// Error returned when a header is invalid or malformed - #[error("Invalid header format: {msg}")] - InvalidHeader { - /// Description of why the header is invalid - msg: String, - }, - - /// Error returned when storage initialization fails - #[error("Storage initialization failed: {msg}")] - StorageInit { - /// Description of why storage initialization failed - msg: String, - }, -} - -impl From for LuminaError { - fn from(error: NodeError) -> Self { - LuminaError::NetworkError { - msg: error.to_string(), - } - } -} - /// The main Lumina node that manages the connection to the Celestia network. #[derive(Object)] pub struct LuminaNode { @@ -143,47 +47,30 @@ impl LuminaNode { })) } - /// Starts the Lumina node. Returns true if successfully started. + /// Start the node without optional configuration. + /// UniFFI needs explicit handling for optional parameters to generate correct bindings for different languages. pub async fn start(&self) -> Result { + self.start_with_config(None).await + } + + /// Start the node with specific configuration + pub async fn start_with_config(&self, config: Option) -> Result { let mut node_guard = self.node.lock().await; if node_guard.is_some() { return Err(LuminaError::AlreadyRunning); } - let network_id = self.network.id(); - - let base_path = get_base_path()?; - - std::fs::create_dir_all(&base_path).map_err(|e| LuminaError::StorageError { - msg: format!("Failed to create data directory: {}", e), - })?; + let config = config.unwrap_or_else(|| NodeStartConfig { + network: self.network.clone(), + bootnodes: None, + syncing_window_secs: None, + pruning_delay_secs: None, + batch_size: None, + ed25519_secret_key_bytes: None, + }); - let store_path = base_path.join(format!("store-{}", network_id)); - let db = Arc::new(redb::Database::create(&store_path).map_err(|e| { - LuminaError::StorageInit { - msg: format!("Failed to create database: {}", e), - } - })?); - - let store = RedbStore::new(db.clone()) - .await - .map_err(|e| LuminaError::StorageInit { - msg: format!("Failed to initialize store: {}", e), - })?; - - let blockstore = RedbBlockstore::new(db); - - let p2p_bootnodes = self.network.canonical_bootnodes().collect::>(); - let p2p_local_keypair = Keypair::generate_ed25519(); - - let builder = Node::builder() - .store(store) - .blockstore(blockstore) - .network(self.network.clone()) - .bootnodes(p2p_bootnodes) - .keypair(p2p_local_keypair) - .sync_batch_size(128); + let builder = config.into_node_builder().await?; let (new_node, subscriber) = builder .start_subscribed() @@ -191,8 +78,8 @@ impl LuminaNode { .map_err(|e| LuminaError::NetworkError { msg: e.to_string() })?; let mut events_guard = self.events_subscriber.lock().await; - *events_guard = Some(subscriber); + *events_guard = Some(subscriber); *node_guard = Some(new_node); Ok(true) } @@ -268,7 +155,7 @@ impl LuminaNode { let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; let peer_id = peer_id .to_libp2p() - .map_err(|e| LuminaError::NetworkError { msg: e })?; + .map_err(|e| LuminaError::NetworkError { msg: e.to_string() })?; Ok(node.set_peer_trust(peer_id, is_trusted).await?) } diff --git a/node-uniffi/src/types.rs b/node-uniffi/src/types.rs index 35db5040..6a568dc2 100644 --- a/node-uniffi/src/types.rs +++ b/node-uniffi/src/types.rs @@ -1,38 +1,153 @@ +use libp2p::identity::Keypair; use libp2p::swarm::ConnectionCounters as Libp2pConnectionCounters; use libp2p::swarm::NetworkInfo as Libp2pNetworkInfo; use libp2p::PeerId as Libp2pPeerId; use lumina_node::block_ranges::BlockRange as LuminaBlockRange; use lumina_node::events::{NodeEvent as LuminaNodeEvent, NodeEventInfo as LuminaNodeEventInfo}; use lumina_node::node::SyncingInfo as LuminaSyncingInfo; -use std::str::FromStr; -use std::time::SystemTime; +use lumina_node::{blockstore::RedbBlockstore, network, NodeBuilder}; +use std::sync::Arc; +use std::{ + path::PathBuf, + str::FromStr, + time::{Duration, SystemTime}, +}; use uniffi::Record; +use lumina_node::store::RedbStore; + +use crate::{error::Result, LuminaError}; + +#[cfg(target_os = "ios")] +use directories::ProjectDirs; + +#[cfg(target_os = "ios")] +/// Returns the platform-specific base path for storing on iOS. +fn get_base_path_impl() -> Result { + if let Some(proj_dirs) = ProjectDirs::from("com", "example", "Lumina") { + Ok(proj_dirs.data_dir().to_path_buf()) + } else { + Err(LuminaError::StorageError { + msg: "Could not determine a platform-specific data directory".to_string(), + }) + } +} + +#[cfg(target_os = "android")] +/// Returns the platform-specific base path for storing on Android. +/// +/// On Android, this function attempts to read the `LUMINA_DATA_DIR` environment variable. +/// If `LUMINA_DATA_DIR` is not set, it falls back to `/data/data/com.example.lumina/files`. +fn get_base_path_impl() -> Result { + match std::env::var("LUMINA_DATA_DIR") { + Ok(dir) => Ok(PathBuf::from(dir)), + Err(_) => { + let fallback = "/data/data/com.example.lumina/files"; + Ok(PathBuf::from(fallback)) + } + } +} + +#[cfg(not(any(target_os = "ios", target_os = "android")))] +/// Returns an error for unsupported platforms. +fn get_base_path_impl() -> Result { + Err(LuminaError::StorageError { + msg: "Unsupported platform".to_string(), + }) +} + +/// Returns the platform-specific base path for storing Lumina data. +/// +/// The function determines the base path based on the target operating system: +/// - **iOS**: `~/Library/Application Support/lumina` +/// - **Android**: Value of the `LUMINA_DATA_DIR` environment variable +/// - **Other platforms**: Returns an error indicating unsupported platform. +fn get_base_path() -> Result { + get_base_path_impl() +} + /// Configuration options for the Lumina node #[derive(Debug, Clone, Record)] pub struct NodeStartConfig { - /// Custom syncing window in seconds, defines maximum age of headers - /// considered for syncing and sampling + /// Network to connect to + pub network: network::Network, + /// Custom list of bootstrap peers to connect to. + /// If None, uses the canonical bootnodes for the network. + pub bootnodes: Option>, + /// Custom syncing window in seconds. Default is 30 days. pub syncing_window_secs: Option, - - /// Custom pruning delay after the syncing window in seconds + /// Custom pruning delay after syncing window in seconds. Default is 1 hour. pub pruning_delay_secs: Option, + /// Maximum number of headers in batch while syncing. Default is 128. + pub batch_size: Option, + /// Optional Set the keypair to be used as Node's identity. If None, generates a new Ed25519 keypair. + pub ed25519_secret_key_bytes: Option>, +} - /// Maximum number of headers in batch while syncing - pub sync_batch_size: Option, +impl NodeStartConfig { + /// Convert into NodeBuilder for the implementation + pub(crate) async fn into_node_builder(self) -> Result> { + let base_path = get_base_path()?; + let network_id = self.network.id(); + let store_path = base_path.join(format!("store-{}", network_id)); + std::fs::create_dir_all(&base_path).map_err(|e| LuminaError::StorageError { + msg: format!("Failed to create data directory: {}", e), + })?; + let db = Arc::new(redb::Database::create(&store_path).map_err(|e| { + LuminaError::StorageInit { + msg: format!("Failed to create database: {}", e), + } + })?); - /// Whether to listen for incoming connections - pub enable_listener: bool, -} + let store = RedbStore::new(db.clone()) + .await + .map_err(|e| LuminaError::StorageInit { + msg: format!("Failed to initialize store: {}", e), + })?; -impl Default for NodeStartConfig { - fn default() -> Self { - Self { - syncing_window_secs: None, - pruning_delay_secs: None, - sync_batch_size: None, - enable_listener: false, + let blockstore = RedbBlockstore::new(db); + + let bootnodes = if let Some(bootnodes) = self.bootnodes { + let mut resolved = Vec::with_capacity(bootnodes.len()); + for addr in bootnodes { + resolved.push(addr.parse()?); + } + resolved + } else { + self.network.canonical_bootnodes().collect::>() + }; + + let keypair = if let Some(key_bytes) = self.ed25519_secret_key_bytes { + if key_bytes.len() != 32 { + return Err(LuminaError::NetworkError { + msg: "Ed25519 private key must be 32 bytes".into(), + }); + } + + Keypair::ed25519_from_bytes(key_bytes).map_err(|e| LuminaError::NetworkError { + msg: format!("Invalid Ed25519 key: {}", e), + })? + } else { + libp2p::identity::Keypair::generate_ed25519() + }; + + let mut builder = NodeBuilder::new() + .store(store) + .blockstore(blockstore) + .network(self.network) + .bootnodes(bootnodes) + .keypair(keypair) + .sync_batch_size(self.batch_size.unwrap_or(128)); + + if let Some(secs) = self.syncing_window_secs { + builder = builder.sampling_window(Duration::from_secs(secs.into())); } + + if let Some(secs) = self.pruning_delay_secs { + builder = builder.pruning_delay(Duration::from_secs(secs.into())); + } + + Ok(builder) } } @@ -132,7 +247,7 @@ pub struct PeerId { } impl PeerId { - pub fn to_libp2p(&self) -> Result { + pub fn to_libp2p(&self) -> std::result::Result { Libp2pPeerId::from_str(&self.peer_id).map_err(|e| format!("Invalid peer ID format: {}", e)) } diff --git a/node/Cargo.toml b/node/Cargo.toml index ce04d344..6cf8af2e 100644 --- a/node/Cargo.toml +++ b/node/Cargo.toml @@ -18,6 +18,9 @@ categories = [ "wasm", ] +[lib] +crate-type = ["lib", "staticlib", "cdylib"] + [dependencies] celestia-proto.workspace = true celestia-types.workspace = true @@ -52,6 +55,8 @@ tokio-util = "0.7.11" tracing = "0.1.40" void = "1.0.2" web-time = "1.1.0" +uniffi = { version = "0.28.0", optional = true } + [target.'cfg(not(target_arch = "wasm32"))'.dependencies] backoff = { version = "0.4.0", features = ["tokio"] } @@ -69,7 +74,6 @@ libp2p = { workspace = true, features = [ redb = "2.1.1" rustls-pemfile = "2.1.2" rustls-pki-types = "1.7.0" -uniffi = { version = "0.28.0", optional = true } [target.'cfg(target_arch = "wasm32")'.dependencies] backoff = { version = "0.4.0", features = ["wasm-bindgen"] } @@ -111,7 +115,6 @@ serde_json = "1.0.117" tempfile = "3.10.1" [features] -default-features = [] test-utils = ["celestia-types/test-utils"] uniffi = ["dep:uniffi", "celestia-types/uniffi"] diff --git a/node/src/network.rs b/node/src/network.rs index c57b2aca..969a21b5 100644 --- a/node/src/network.rs +++ b/node/src/network.rs @@ -32,7 +32,8 @@ pub struct InvalidNetworkId(String); #[cfg_attr(feature = "uniffi", derive(uniffi::Record))] #[derive(Debug, Clone, PartialEq, Eq)] pub struct NetworkId { - pub id: String, // / Rename from 0 to id since uniffi doesn't support tuple structs + /// The network identifier string + pub id: String, } impl NetworkId { From e5021f9ffefb01328727c5f79f43bdf16a72c91e Mon Sep 17 00:00:00 2001 From: sebasti810 Date: Tue, 17 Dec 2024 11:34:35 +0100 Subject: [PATCH 10/13] fix: udeps --- Cargo.lock | 1 - node-uniffi/Cargo.toml | 8 +++++--- node/Cargo.toml | 2 +- types/Cargo.toml | 2 -- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 75ca3570..a9bd83bf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -942,7 +942,6 @@ dependencies = [ "tendermint-proto", "thiserror 1.0.69", "time", - "uniffi", "wasm-bindgen-test", ] diff --git a/node-uniffi/Cargo.toml b/node-uniffi/Cargo.toml index 05c5333e..57b77bbc 100644 --- a/node-uniffi/Cargo.toml +++ b/node-uniffi/Cargo.toml @@ -13,12 +13,14 @@ path = "./src/bin/uniffi-bindgen.rs" [dependencies] lumina-node = { workspace = true, features = ["uniffi"] } -celestia-types = { workspace = true, features = ["uniffi"] } +celestia-types.workspace = true tendermint.workspace = true libp2p.workspace = true redb = "2.1.1" thiserror = "1.0.61" serde_json = "1.0.64" -directories = "5.0.1" uniffi = { version = "0.28.3", features = ["bindgen", "tokio", "cli"] } -tokio = { version = "1.38.0", features = ["macros", "sync"] } \ No newline at end of file +tokio = { version = "1.38.0", features = ["macros", "sync"] } + +[target.'cfg(target_os = "ios")'.dependencies] +directories = "5.0.1" \ No newline at end of file diff --git a/node/Cargo.toml b/node/Cargo.toml index 6cf8af2e..1a36d7e3 100644 --- a/node/Cargo.toml +++ b/node/Cargo.toml @@ -116,7 +116,7 @@ tempfile = "3.10.1" [features] test-utils = ["celestia-types/test-utils"] -uniffi = ["dep:uniffi", "celestia-types/uniffi"] +uniffi = ["dep:uniffi"] [package.metadata.docs.rs] features = ["test-utils"] diff --git a/types/Cargo.toml b/types/Cargo.toml index dc18003d..3084e80e 100644 --- a/types/Cargo.toml +++ b/types/Cargo.toml @@ -40,7 +40,6 @@ serde_repr = { version = "0.1.19", optional = true } sha2 = "0.10.6" thiserror = "1.0.61" time = { version = "0.3.36", default-features = false } -uniffi = { version = "0.28.0", optional = true } [dev-dependencies] ed25519-consensus = "2.1.0" @@ -63,7 +62,6 @@ wasm-bindgen = ["time/wasm-bindgen"] [package.metadata.docs.rs] features = ["p2p", "test-utils"] rustdoc-args = ["--cfg", "docsrs"] -uniffi = ["dep:uniffi"] [package.metadata.cargo-udeps.ignore] development = ["indoc"] From fe67e4eb378c35caa8b54a3c39e874fc8e6bfef5 Mon Sep 17 00:00:00 2001 From: sebasti810 Date: Fri, 20 Dec 2024 08:56:16 +0100 Subject: [PATCH 11/13] fix: return bool, remove async from new --- node-uniffi/Cargo.toml | 2 +- node-uniffi/build-android.sh | 2 +- node-uniffi/build-ios.sh | 4 +- node-uniffi/src/lib.rs | 212 +++++++------ node-uniffi/src/types.rs | 516 ------------------------------- node-uniffi/src/types/config.rs | 109 +++++++ node-uniffi/src/types/event.rs | 251 +++++++++++++++ node-uniffi/src/types/mod.rs | 9 + node-uniffi/src/types/network.rs | 53 ++++ node-uniffi/src/types/sync.rs | 42 +++ 10 files changed, 588 insertions(+), 612 deletions(-) delete mode 100644 node-uniffi/src/types.rs create mode 100644 node-uniffi/src/types/config.rs create mode 100644 node-uniffi/src/types/event.rs create mode 100644 node-uniffi/src/types/mod.rs create mode 100644 node-uniffi/src/types/network.rs create mode 100644 node-uniffi/src/types/sync.rs diff --git a/node-uniffi/Cargo.toml b/node-uniffi/Cargo.toml index 57b77bbc..c444f0d9 100644 --- a/node-uniffi/Cargo.toml +++ b/node-uniffi/Cargo.toml @@ -23,4 +23,4 @@ uniffi = { version = "0.28.3", features = ["bindgen", "tokio", "cli"] } tokio = { version = "1.38.0", features = ["macros", "sync"] } [target.'cfg(target_os = "ios")'.dependencies] -directories = "5.0.1" \ No newline at end of file +directories = "5.0.1" diff --git a/node-uniffi/build-android.sh b/node-uniffi/build-android.sh index 54c3273d..f406a5d4 100755 --- a/node-uniffi/build-android.sh +++ b/node-uniffi/build-android.sh @@ -18,4 +18,4 @@ cargo ndk -o ./app/src/main/jniLibs \ cargo run --bin uniffi-bindgen generate --library ../target/debug/liblumina_node_uniffi.dylib --language kotlin --out-dir ./app/src/main/java/tech/forgen/lumina_node_uniffi/rust -echo "Android build complete" \ No newline at end of file +echo "Android build complete" diff --git a/node-uniffi/build-ios.sh b/node-uniffi/build-ios.sh index fdc326dd..8d02bcca 100755 --- a/node-uniffi/build-ios.sh +++ b/node-uniffi/build-ios.sh @@ -1,5 +1,7 @@ #!/bin/bash +cargo build + cd .. for TARGET in \ @@ -34,4 +36,4 @@ cp ./bindings/*.swift ./ios/ rm -rf bindings -echo "iOS build complete" \ No newline at end of file +echo "iOS build complete" diff --git a/node-uniffi/src/lib.rs b/node-uniffi/src/lib.rs index 39ce6a3f..e7ff6b1c 100644 --- a/node-uniffi/src/lib.rs +++ b/node-uniffi/src/lib.rs @@ -10,17 +10,13 @@ mod types; use celestia_types::ExtendedHeader; use error::{LuminaError, Result}; use lumina_node::{ - blockstore::RedbBlockstore, - events::{EventSubscriber, TryRecvError}, - network::Network, - node::PeerTrackerInfo, - store::RedbStore, + blockstore::RedbBlockstore, events::EventSubscriber, node::PeerTrackerInfo, store::RedbStore, Node, }; -use std::{str::FromStr, sync::Arc}; +use std::str::FromStr; use tendermint::hash::Hash; -use tokio::sync::Mutex; -use types::{NetworkInfo, NodeEvent, NodeStartConfig, PeerId, SyncingInfo}; +use tokio::sync::{Mutex, RwLock}; +use types::{NetworkInfo, NodeConfig, NodeEvent, PeerId, SyncingInfo}; use uniffi::Object; uniffi::setup_scaffolding!(); @@ -30,129 +26,134 @@ lumina_node::uniffi_reexport_scaffolding!(); /// The main Lumina node that manages the connection to the Celestia network. #[derive(Object)] pub struct LuminaNode { - node: Arc>>>, - network: Network, - events_subscriber: Arc>>, + node: RwLock>>, + events_subscriber: Mutex>, + config: NodeConfig, } #[uniffi::export(async_runtime = "tokio")] impl LuminaNode { /// Sets a new connection to the Lumina node for the specified network. #[uniffi::constructor] - pub fn new(network: Network) -> Result> { - Ok(Arc::new(Self { - node: Arc::new(Mutex::new(None)), - network, - events_subscriber: Arc::new(Mutex::new(None)), - })) + pub fn new(config: NodeConfig) -> Result { + Ok(Self { + node: RwLock::new(None), + events_subscriber: Mutex::new(None), + config, + }) } - /// Start the node without optional configuration. - /// UniFFI needs explicit handling for optional parameters to generate correct bindings for different languages. + /// Starts the node and connects to the network. pub async fn start(&self) -> Result { - self.start_with_config(None).await - } - - /// Start the node with specific configuration - pub async fn start_with_config(&self, config: Option) -> Result { - let mut node_guard = self.node.lock().await; - - if node_guard.is_some() { - return Err(LuminaError::AlreadyRunning); + let mut node_lock = self.node.write().await; + if node_lock.is_some() { + return Err(LuminaError::NetworkError { + msg: "Node is already running".to_string(), + }); } - let config = config.unwrap_or_else(|| NodeStartConfig { - network: self.network.clone(), - bootnodes: None, - syncing_window_secs: None, - pruning_delay_secs: None, - batch_size: None, - ed25519_secret_key_bytes: None, - }); - - let builder = config.into_node_builder().await?; - + let builder = self.config.clone().into_node_builder().await?; let (new_node, subscriber) = builder .start_subscribed() .await .map_err(|e| LuminaError::NetworkError { msg: e.to_string() })?; - let mut events_guard = self.events_subscriber.lock().await; + *self.events_subscriber.lock().await = Some(subscriber); + *node_lock = Some(new_node); - *events_guard = Some(subscriber); - *node_guard = Some(new_node); Ok(true) } /// Stops the running node and closes all network connections. pub async fn stop(&self) -> Result<()> { - let mut node_guard = self.node.lock().await; - let node = node_guard.take().ok_or(LuminaError::NodeNotRunning)?; - node.stop().await; - Ok(()) + let mut node = self.node.write().await; + if let Some(node) = node.take() { + node.stop().await; + Ok(()) + } else { + Err(LuminaError::NetworkError { + msg: "Node is already stopped".to_string(), + }) + } } /// Checks if the node is currently running. pub async fn is_running(&self) -> bool { - self.node.lock().await.is_some() + self.node.read().await.is_some() } /// Gets the local peer ID as a string. pub async fn local_peer_id(&self) -> Result { - let node_guard = self.node.lock().await; - let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; + let node = self.node.read().await; + let node = node.as_ref().ok_or(LuminaError::NetworkError { + msg: "Node not initialized".to_string(), + })?; Ok(node.local_peer_id().to_base58()) } /// Gets information about connected peers. pub async fn peer_tracker_info(&self) -> Result { - let node_guard = self.node.lock().await; - let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; + let node = self.node.read().await; + let node = node.as_ref().ok_or(LuminaError::NetworkError { + msg: "Node not initialized".to_string(), + })?; Ok(node.peer_tracker_info()) } /// Waits until the node is connected to at least one peer. pub async fn wait_connected(&self) -> Result<()> { - let node_guard = self.node.lock().await; - let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; + let node = self.node.read().await; + let node = node.as_ref().ok_or(LuminaError::NetworkError { + msg: "Node not initialized".to_string(), + })?; Ok(node.wait_connected().await?) } /// Waits until the node is connected to at least one trusted peer. pub async fn wait_connected_trusted(&self) -> Result<()> { - let node_guard = self.node.lock().await; - let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; + let node = self.node.read().await; + let node = node.as_ref().ok_or(LuminaError::NetworkError { + msg: "Node not initialized".to_string(), + })?; Ok(node.wait_connected_trusted().await?) } /// Gets current network information. pub async fn network_info(&self) -> Result { - let node_guard = self.node.lock().await; - let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; + let node = self.node.read().await; + let node = node.as_ref().ok_or(LuminaError::NetworkError { + msg: "Node not initialized".to_string(), + })?; let info = node.network_info().await?; Ok(info.into()) } /// Gets list of addresses the node is listening to. pub async fn listeners(&self) -> Result> { - let node_guard = self.node.lock().await; - let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; + let node = self.node.read().await; + let node = node.as_ref().ok_or(LuminaError::NetworkError { + msg: "Node not initialized".to_string(), + })?; let listeners = node.listeners().await?; Ok(listeners.into_iter().map(|l| l.to_string()).collect()) } /// Gets list of currently connected peer IDs. pub async fn connected_peers(&self) -> Result> { - let node_guard = self.node.lock().await; - let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; + let node = self.node.read().await; + let node = node.as_ref().ok_or(LuminaError::NetworkError { + msg: "Node not initialized".to_string(), + })?; let peers = node.connected_peers().await?; Ok(peers.into_iter().map(PeerId::from).collect()) } /// Sets whether a peer with give ID is trusted. pub async fn set_peer_trust(&self, peer_id: PeerId, is_trusted: bool) -> Result<()> { - let node_guard = self.node.lock().await; - let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; + let node = self.node.read().await; + let node = node.as_ref().ok_or(LuminaError::NetworkError { + msg: "Node not initialized".to_string(), + })?; let peer_id = peer_id .to_libp2p() .map_err(|e| LuminaError::NetworkError { msg: e.to_string() })?; @@ -163,16 +164,20 @@ impl LuminaNode { /// /// Returns a serialized ExtendedHeader string. pub async fn request_head_header(&self) -> Result { - let node_guard = self.node.lock().await; - let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; + let node = self.node.read().await; + let node = node.as_ref().ok_or(LuminaError::NetworkError { + msg: "Node not initialized".to_string(), + })?; let header = node.request_head_header().await?; Ok(header.to_string()) //if extended header is needed, we need a wrapper } /// Request a header for the block with a given hash from the network. pub async fn request_header_by_hash(&self, hash: String) -> Result { - let node_guard = self.node.lock().await; - let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; + let node = self.node.read().await; + let node = node.as_ref().ok_or(LuminaError::NetworkError { + msg: "Node not initialized".to_string(), + })?; let hash = Hash::from_str(&hash).map_err(|e| LuminaError::InvalidHash { msg: e.to_string() })?; let header = node.request_header_by_hash(&hash).await?; @@ -181,23 +186,27 @@ impl LuminaNode { /// Requests a header by its height. pub async fn request_header_by_height(&self, height: u64) -> Result { - let node_guard = self.node.lock().await; - let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; + let node = self.node.read().await; + let node = node.as_ref().ok_or(LuminaError::NetworkError { + msg: "Node not initialized".to_string(), + })?; let header = node.request_header_by_height(height).await?; Ok(header.to_string()) } /// Request headers in range (from, from + amount] from the network. /// - /// The headers will be verified with the `from` header. + /// The headers will be verified with the from header. /// Returns array of serialized ExtendedHeader strings. pub async fn request_verified_headers( &self, from: String, // serialized header like its done for WASM amount: u64, ) -> Result> { - let node_guard = self.node.lock().await; - let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; + let node = self.node.read().await; + let node = node.as_ref().ok_or(LuminaError::NetworkError { + msg: "Node not initialized".to_string(), + })?; let from: ExtendedHeader = serde_json::from_str(&from).map_err(|e| LuminaError::InvalidHeader { msg: format!("Invalid header JSON: {}", e), @@ -208,16 +217,20 @@ impl LuminaNode { /// Gets current syncing information. pub async fn syncer_info(&self) -> Result { - let node_guard = self.node.lock().await; - let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; + let node = self.node.read().await; + let node = node.as_ref().ok_or(LuminaError::NetworkError { + msg: "Node not initialized".to_string(), + })?; let info = node.syncer_info().await?; Ok(info.into()) } /// Gets the latest header announced in the network. pub async fn get_network_head_header(&self) -> Result { - let node_guard = self.node.lock().await; - let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; + let node = self.node.read().await; + let node = node.as_ref().ok_or(LuminaError::NetworkError { + msg: "Node not initialized".to_string(), + })?; let header = node.get_network_head_header().await?; header.map_or( // todo: better error handling, its undefined in wasm @@ -230,16 +243,20 @@ impl LuminaNode { /// Gets the latest locally synced header. pub async fn get_local_head_header(&self) -> Result { - let node_guard = self.node.lock().await; - let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; + let node = self.node.read().await; + let node = node.as_ref().ok_or(LuminaError::NetworkError { + msg: "Node not initialized".to_string(), + })?; let header = node.get_local_head_header().await?; Ok(header.to_string()) } /// Get a synced header for the block with a given hash. pub async fn get_header_by_hash(&self, hash: String) -> Result { - let node_guard = self.node.lock().await; - let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; + let node = self.node.read().await; + let node = node.as_ref().ok_or(LuminaError::NetworkError { + msg: "Node not initialized".to_string(), + })?; let hash = Hash::from_str(&hash).map_err(|e| LuminaError::InvalidHash { msg: e.to_string() })?; let header = node.get_header_by_hash(&hash).await?; @@ -248,8 +265,10 @@ impl LuminaNode { /// Get a synced header for the block with a given height. pub async fn get_header_by_height(&self, height: u64) -> Result { - let node_guard = self.node.lock().await; - let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; + let node = self.node.read().await; + let node = node.as_ref().ok_or(LuminaError::NetworkError { + msg: "Node not initialized".to_string(), + })?; let header = node.get_header_by_height(height).await?; Ok(header.to_string()) } @@ -266,8 +285,10 @@ impl LuminaNode { start_height: Option, end_height: Option, ) -> Result> { - let node_guard = self.node.lock().await; - let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; + let node = self.node.read().await; + let node = node.as_ref().ok_or(LuminaError::NetworkError { + msg: "Node not initialized".to_string(), + })?; let headers = match (start_height, end_height) { (None, None) => node.get_headers(..).await, @@ -283,21 +304,26 @@ impl LuminaNode { /// /// Returns serialized SamplingMetadata string if metadata exists for the height. pub async fn get_sampling_metadata(&self, height: u64) -> Result> { - let node_guard = self.node.lock().await; - let node = node_guard.as_ref().ok_or(LuminaError::NodeNotRunning)?; + let node = self.node.read().await; + let node = node.as_ref().ok_or(LuminaError::NetworkError { + msg: "Node not initialized".to_string(), + })?; + let metadata = node.get_sampling_metadata(height).await?; Ok(metadata.map(|m| serde_json::to_string(&m).unwrap())) } /// Returns the next event from the node's event channel. pub async fn events_channel(&self) -> Result> { - let mut events_guard = self.events_subscriber.lock().await; - let subscriber = events_guard.as_mut().ok_or(LuminaError::NodeNotRunning)?; - - match subscriber.try_recv() { - Ok(event) => Ok(Some(event.event.into())), - Err(TryRecvError::Empty) => Ok(None), - Err(e) => Err(LuminaError::NetworkError { msg: e.to_string() }), + let mut events_subscriber = self.events_subscriber.lock().await; + match events_subscriber.as_mut() { + Some(subscriber) => match subscriber.try_recv() { + Ok(event) => Ok(Some(event.event.into())), + Err(e) => Err(LuminaError::NetworkError { msg: e.to_string() }), + }, + None => Err(LuminaError::NetworkError { + msg: "Node is not running".to_string(), + }), } } } diff --git a/node-uniffi/src/types.rs b/node-uniffi/src/types.rs deleted file mode 100644 index 6a568dc2..00000000 --- a/node-uniffi/src/types.rs +++ /dev/null @@ -1,516 +0,0 @@ -use libp2p::identity::Keypair; -use libp2p::swarm::ConnectionCounters as Libp2pConnectionCounters; -use libp2p::swarm::NetworkInfo as Libp2pNetworkInfo; -use libp2p::PeerId as Libp2pPeerId; -use lumina_node::block_ranges::BlockRange as LuminaBlockRange; -use lumina_node::events::{NodeEvent as LuminaNodeEvent, NodeEventInfo as LuminaNodeEventInfo}; -use lumina_node::node::SyncingInfo as LuminaSyncingInfo; -use lumina_node::{blockstore::RedbBlockstore, network, NodeBuilder}; -use std::sync::Arc; -use std::{ - path::PathBuf, - str::FromStr, - time::{Duration, SystemTime}, -}; -use uniffi::Record; - -use lumina_node::store::RedbStore; - -use crate::{error::Result, LuminaError}; - -#[cfg(target_os = "ios")] -use directories::ProjectDirs; - -#[cfg(target_os = "ios")] -/// Returns the platform-specific base path for storing on iOS. -fn get_base_path_impl() -> Result { - if let Some(proj_dirs) = ProjectDirs::from("com", "example", "Lumina") { - Ok(proj_dirs.data_dir().to_path_buf()) - } else { - Err(LuminaError::StorageError { - msg: "Could not determine a platform-specific data directory".to_string(), - }) - } -} - -#[cfg(target_os = "android")] -/// Returns the platform-specific base path for storing on Android. -/// -/// On Android, this function attempts to read the `LUMINA_DATA_DIR` environment variable. -/// If `LUMINA_DATA_DIR` is not set, it falls back to `/data/data/com.example.lumina/files`. -fn get_base_path_impl() -> Result { - match std::env::var("LUMINA_DATA_DIR") { - Ok(dir) => Ok(PathBuf::from(dir)), - Err(_) => { - let fallback = "/data/data/com.example.lumina/files"; - Ok(PathBuf::from(fallback)) - } - } -} - -#[cfg(not(any(target_os = "ios", target_os = "android")))] -/// Returns an error for unsupported platforms. -fn get_base_path_impl() -> Result { - Err(LuminaError::StorageError { - msg: "Unsupported platform".to_string(), - }) -} - -/// Returns the platform-specific base path for storing Lumina data. -/// -/// The function determines the base path based on the target operating system: -/// - **iOS**: `~/Library/Application Support/lumina` -/// - **Android**: Value of the `LUMINA_DATA_DIR` environment variable -/// - **Other platforms**: Returns an error indicating unsupported platform. -fn get_base_path() -> Result { - get_base_path_impl() -} - -/// Configuration options for the Lumina node -#[derive(Debug, Clone, Record)] -pub struct NodeStartConfig { - /// Network to connect to - pub network: network::Network, - /// Custom list of bootstrap peers to connect to. - /// If None, uses the canonical bootnodes for the network. - pub bootnodes: Option>, - /// Custom syncing window in seconds. Default is 30 days. - pub syncing_window_secs: Option, - /// Custom pruning delay after syncing window in seconds. Default is 1 hour. - pub pruning_delay_secs: Option, - /// Maximum number of headers in batch while syncing. Default is 128. - pub batch_size: Option, - /// Optional Set the keypair to be used as Node's identity. If None, generates a new Ed25519 keypair. - pub ed25519_secret_key_bytes: Option>, -} - -impl NodeStartConfig { - /// Convert into NodeBuilder for the implementation - pub(crate) async fn into_node_builder(self) -> Result> { - let base_path = get_base_path()?; - let network_id = self.network.id(); - let store_path = base_path.join(format!("store-{}", network_id)); - std::fs::create_dir_all(&base_path).map_err(|e| LuminaError::StorageError { - msg: format!("Failed to create data directory: {}", e), - })?; - let db = Arc::new(redb::Database::create(&store_path).map_err(|e| { - LuminaError::StorageInit { - msg: format!("Failed to create database: {}", e), - } - })?); - - let store = RedbStore::new(db.clone()) - .await - .map_err(|e| LuminaError::StorageInit { - msg: format!("Failed to initialize store: {}", e), - })?; - - let blockstore = RedbBlockstore::new(db); - - let bootnodes = if let Some(bootnodes) = self.bootnodes { - let mut resolved = Vec::with_capacity(bootnodes.len()); - for addr in bootnodes { - resolved.push(addr.parse()?); - } - resolved - } else { - self.network.canonical_bootnodes().collect::>() - }; - - let keypair = if let Some(key_bytes) = self.ed25519_secret_key_bytes { - if key_bytes.len() != 32 { - return Err(LuminaError::NetworkError { - msg: "Ed25519 private key must be 32 bytes".into(), - }); - } - - Keypair::ed25519_from_bytes(key_bytes).map_err(|e| LuminaError::NetworkError { - msg: format!("Invalid Ed25519 key: {}", e), - })? - } else { - libp2p::identity::Keypair::generate_ed25519() - }; - - let mut builder = NodeBuilder::new() - .store(store) - .blockstore(blockstore) - .network(self.network) - .bootnodes(bootnodes) - .keypair(keypair) - .sync_batch_size(self.batch_size.unwrap_or(128)); - - if let Some(secs) = self.syncing_window_secs { - builder = builder.sampling_window(Duration::from_secs(secs.into())); - } - - if let Some(secs) = self.pruning_delay_secs { - builder = builder.pruning_delay(Duration::from_secs(secs.into())); - } - - Ok(builder) - } -} - -#[derive(Record)] -pub struct NetworkInfo { - /// The total number of connected peers. - pub num_peers: u32, - /// Counters of ongoing network connections. - pub connection_counters: ConnectionCounters, -} - -/// Counters of ongoing network connections. -#[derive(Record)] -pub struct ConnectionCounters { - /// The current number of connections. - pub num_connections: u32, - /// The current number of pending connections. - pub num_pending: u32, - /// The current number of incoming connections. - pub num_pending_incoming: u32, - /// The current number of outgoing connections. - pub num_pending_outgoing: u32, - /// The current number of established connections. - pub num_established: u32, - /// The current number of established inbound connections. - pub num_established_incoming: u32, - /// The current number of established outbound connections. - pub num_established_outgoing: u32, -} - -impl From for NetworkInfo { - fn from(info: Libp2pNetworkInfo) -> Self { - Self { - num_peers: info.num_peers() as u32, - connection_counters: info.connection_counters().into(), - } - } -} - -impl From<&Libp2pConnectionCounters> for ConnectionCounters { - fn from(counters: &Libp2pConnectionCounters) -> Self { - Self { - num_connections: counters.num_connections(), - num_pending: counters.num_pending(), - num_pending_incoming: counters.num_pending_incoming(), - num_pending_outgoing: counters.num_pending_outgoing(), - num_established: counters.num_established(), - num_established_incoming: counters.num_established_incoming(), - num_established_outgoing: counters.num_established_outgoing(), - } - } -} - -/// A range of blocks. -#[derive(Record)] -pub struct BlockRange { - pub start: u64, - pub end: u64, -} - -impl From for BlockRange { - fn from(range: LuminaBlockRange) -> Self { - Self { - start: *range.start(), - end: *range.end(), - } - } -} - -/// Status of the node syncing. -#[derive(Record)] -pub struct SyncingInfo { - /// Ranges of headers that are already synchronised - pub stored_headers: Vec, - /// Syncing target. The latest height seen in the network that was successfully verified. - pub subjective_head: u64, -} - -impl From for SyncingInfo { - fn from(info: LuminaSyncingInfo) -> Self { - Self { - stored_headers: info - .stored_headers - .into_inner() - .into_iter() - .map(BlockRange::from) - .collect(), - subjective_head: info.subjective_head, - } - } -} - -#[derive(Record, Clone, Debug)] -pub struct PeerId { - /// The peer ID stored as base58 string. - pub peer_id: String, -} - -impl PeerId { - pub fn to_libp2p(&self) -> std::result::Result { - Libp2pPeerId::from_str(&self.peer_id).map_err(|e| format!("Invalid peer ID format: {}", e)) - } - - pub fn from_libp2p(peer_id: &Libp2pPeerId) -> Self { - Self { - peer_id: peer_id.to_string(), - } - } -} - -impl From for PeerId { - fn from(peer_id: Libp2pPeerId) -> Self { - Self { - peer_id: peer_id.to_string(), - } - } -} - -#[derive(Record)] -pub struct ShareCoordinate { - pub row: u16, - pub column: u16, -} - -/// Events emitted by the node. -#[derive(uniffi::Enum)] -pub enum NodeEvent { - /// Node is connecting to bootnodes - ConnectingToBootnodes, - /// Peer just connected - PeerConnected { - /// The ID of the peer. - id: PeerId, - /// Whether peer was in the trusted list or not. - trusted: bool, - }, - PeerDisconnected { - /// The ID of the peer. - id: PeerId, - /// Whether peer was in the trusted list or not. - trusted: bool, - }, - /// Sampling just started. - SamplingStarted { - /// The block height that will be sampled. - height: u64, - /// The square width of the block. - square_width: u16, - /// The coordinates of the shares that will be sampled. - shares: Vec, - }, - /// A share was sampled. - ShareSamplingResult { - /// The block height of the share. - height: u64, - /// The square width of the block. - square_width: u16, - /// The row of the share. - row: u16, - /// The column of the share. - column: u16, - /// The result of the sampling of the share. - accepted: bool, - }, - /// Sampling just finished. - SamplingFinished { - /// The block height that was sampled. - height: u64, - /// The overall result of the sampling. - accepted: bool, - /// How much time sampling took in milliseconds. - took_ms: u64, - }, - /// Data sampling fatal error. - FatalDaserError { - /// A human readable error. - error: String, - }, - /// A new header was added from HeaderSub. - AddedHeaderFromHeaderSub { - /// The height of the header. - height: u64, - }, - /// Fetching header of network head just started. - FetchingHeadHeaderStarted, - /// Fetching header of network head just finished. - FetchingHeadHeaderFinished { - /// The height of the network head. - height: u64, - /// How much time fetching took in milliseconds. - took_ms: u64, - }, - /// Fetching headers of a specific block range just started. - FetchingHeadersStarted { - /// Start of the range. - from_height: u64, - /// End of the range (included). - to_height: u64, - }, - /// Fetching headers of a specific block range just finished. - FetchingHeadersFinished { - /// Start of the range. - from_height: u64, - /// End of the range (included). - to_height: u64, - /// How much time fetching took in milliseconds. - took_ms: u64, - }, - /// Fetching headers of a specific block range just failed. - FetchingHeadersFailed { - /// Start of the range. - from_height: u64, - /// End of the range (included). - to_height: u64, - /// A human readable error. - error: String, - /// How much time fetching took in milliseconds. - took_ms: u64, - }, - /// Header syncing fatal error. - FatalSyncerError { - /// A human readable error. - error: String, - }, - /// Pruned headers up to and including specified height. - PrunedHeaders { - /// Last header height that was pruned - to_height: u64, - }, - /// Pruning fatal error. - FatalPrunerError { - /// A human readable error. - error: String, - }, - /// Network was compromised. - /// - /// This happens when a valid bad encoding fraud proof is received. - /// Ideally it would never happen, but protection needs to exist. - /// In case of compromised network, syncing and data sampling will - /// stop immediately. - NetworkCompromised, - /// Node stopped. - NodeStopped, -} - -impl From for NodeEvent { - fn from(event: LuminaNodeEvent) -> Self { - match event { - LuminaNodeEvent::ConnectingToBootnodes => NodeEvent::ConnectingToBootnodes, - LuminaNodeEvent::PeerConnected { id, trusted } => NodeEvent::PeerConnected { - id: PeerId::from_libp2p(&id), - trusted, - }, - LuminaNodeEvent::PeerDisconnected { id, trusted } => NodeEvent::PeerDisconnected { - id: PeerId::from_libp2p(&id), - trusted, - }, - LuminaNodeEvent::SamplingStarted { - height, - square_width, - shares, - } => NodeEvent::SamplingStarted { - height, - square_width, - shares: shares - .into_iter() - .map(|(row, col)| ShareCoordinate { row, column: col }) - .collect(), - }, - LuminaNodeEvent::ShareSamplingResult { - height, - square_width, - row, - column, - accepted, - } => NodeEvent::ShareSamplingResult { - height, - square_width, - row, - column, - accepted, - }, - LuminaNodeEvent::SamplingFinished { - height, - accepted, - took, - } => NodeEvent::SamplingFinished { - height, - accepted, - took_ms: took.as_millis() as u64, - }, - LuminaNodeEvent::FatalDaserError { error } => NodeEvent::FatalDaserError { error }, - LuminaNodeEvent::AddedHeaderFromHeaderSub { height } => { - NodeEvent::AddedHeaderFromHeaderSub { height } - } - LuminaNodeEvent::FetchingHeadHeaderStarted => NodeEvent::FetchingHeadHeaderStarted, - LuminaNodeEvent::FetchingHeadHeaderFinished { height, took } => { - NodeEvent::FetchingHeadHeaderFinished { - height, - took_ms: took.as_millis() as u64, - } - } - LuminaNodeEvent::FetchingHeadersStarted { - from_height, - to_height, - } => NodeEvent::FetchingHeadersStarted { - from_height, - to_height, - }, - LuminaNodeEvent::FetchingHeadersFinished { - from_height, - to_height, - took, - } => NodeEvent::FetchingHeadersFinished { - from_height, - to_height, - took_ms: took.as_millis() as u64, - }, - LuminaNodeEvent::FetchingHeadersFailed { - from_height, - to_height, - error, - took, - } => NodeEvent::FetchingHeadersFailed { - from_height, - to_height, - error, - took_ms: took.as_millis() as u64, - }, - LuminaNodeEvent::FatalSyncerError { error } => NodeEvent::FatalSyncerError { error }, - LuminaNodeEvent::PrunedHeaders { to_height } => NodeEvent::PrunedHeaders { to_height }, - LuminaNodeEvent::FatalPrunerError { error } => NodeEvent::FatalPrunerError { error }, - LuminaNodeEvent::NetworkCompromised => NodeEvent::NetworkCompromised, - LuminaNodeEvent::NodeStopped => NodeEvent::NodeStopped, - _ => panic!("Unknown event: {:?}", event), - } - } -} - -/// Information about a node event. -#[derive(Record)] -pub struct NodeEventInfo { - /// The event that occurred. - pub event: NodeEvent, - /// Unix timestamp in milliseconds when the event occurred. - pub timestamp: u64, - /// Source file path where the event was emitted. - pub file_path: String, - /// Line number in source file where event was emitted. - pub file_line: u32, -} - -impl From for NodeEventInfo { - fn from(info: LuminaNodeEventInfo) -> Self { - Self { - event: info.event.into(), - timestamp: info - .time - .duration_since(SystemTime::UNIX_EPOCH) - .unwrap_or_default() - .as_millis() as u64, - file_path: info.file_path.to_string(), - file_line: info.file_line, - } - } -} diff --git a/node-uniffi/src/types/config.rs b/node-uniffi/src/types/config.rs new file mode 100644 index 00000000..7c8ddcf1 --- /dev/null +++ b/node-uniffi/src/types/config.rs @@ -0,0 +1,109 @@ +use std::{path::PathBuf, sync::Arc, time::Duration}; + +use libp2p::identity::Keypair; +use lumina_node::{blockstore::RedbBlockstore, network, store::RedbStore, NodeBuilder}; +use tokio::task::spawn_blocking; +use uniffi::Record; + +use crate::error::{LuminaError, Result}; + +/// Configuration options for the Lumina node +#[derive(Debug, Clone, Record)] +pub struct NodeConfig { + /// Base path for storing node data as a string + pub base_path: String, + /// Network to connect to + pub network: network::Network, + /// Custom list of bootstrap peers to connect to. + /// If None, uses the canonical bootnodes for the network. + pub bootnodes: Option>, + /// Custom syncing window in seconds. Default is 30 days. + pub syncing_window_secs: Option, + /// Custom pruning delay after syncing window in seconds. Default is 1 hour. + pub pruning_delay_secs: Option, + /// Maximum number of headers in batch while syncing. Default is 128. + pub batch_size: Option, + /// Optional Set the keypair to be used as Node's identity. If None, generates a new Ed25519 keypair. + pub ed25519_secret_key_bytes: Option>, +} + +impl NodeConfig { + /// Convert into NodeBuilder for the implementation + pub(crate) async fn into_node_builder(self) -> Result> { + let network_id = self.network.id(); + let base_path = PathBuf::from(self.base_path); + let store_path = base_path.join(format!("store-{}", network_id)); + + spawn_blocking(move || { + std::fs::create_dir_all(&base_path).map_err(|e| LuminaError::StorageError { + msg: format!("Failed to create data directory: {}", e), + }) + }) + .await + .map_err(|e| LuminaError::StorageError { + msg: format!("Task join error: {}", e), + })??; + + let db = spawn_blocking(move || { + redb::Database::create(&store_path) + .map(Arc::new) + .map_err(|e| LuminaError::StorageInit { + msg: format!("Failed to create database: {}", e), + }) + }) + .await + .map_err(|e| LuminaError::StorageError { + msg: format!("Task join error: {}", e), + })??; + + let store = RedbStore::new(db.clone()) + .await + .map_err(|e| LuminaError::StorageInit { + msg: format!("Failed to initialize store: {}", e), + })?; + + let blockstore = RedbBlockstore::new(db); + + let bootnodes = if let Some(bootnodes) = self.bootnodes { + let mut resolved = Vec::with_capacity(bootnodes.len()); + for addr in bootnodes { + resolved.push(addr.parse()?); + } + resolved + } else { + self.network.canonical_bootnodes().collect::>() + }; + + let keypair = if let Some(key_bytes) = self.ed25519_secret_key_bytes { + if key_bytes.len() != 32 { + return Err(LuminaError::NetworkError { + msg: "Ed25519 private key must be 32 bytes".into(), + }); + } + + Keypair::ed25519_from_bytes(key_bytes).map_err(|e| LuminaError::NetworkError { + msg: format!("Invalid Ed25519 key: {}", e), + })? + } else { + libp2p::identity::Keypair::generate_ed25519() + }; + + let mut builder = NodeBuilder::new() + .store(store) + .blockstore(blockstore) + .network(self.network) + .bootnodes(bootnodes) + .keypair(keypair) + .sync_batch_size(self.batch_size.unwrap_or(128)); + + if let Some(secs) = self.syncing_window_secs { + builder = builder.sampling_window(Duration::from_secs(secs.into())); + } + + if let Some(secs) = self.pruning_delay_secs { + builder = builder.pruning_delay(Duration::from_secs(secs.into())); + } + + Ok(builder) + } +} diff --git a/node-uniffi/src/types/event.rs b/node-uniffi/src/types/event.rs new file mode 100644 index 00000000..01917ab6 --- /dev/null +++ b/node-uniffi/src/types/event.rs @@ -0,0 +1,251 @@ +use libp2p::PeerId as Libp2pPeerId; +use lumina_node::events::NodeEvent as LuminaNodeEvent; +use std::str::FromStr; +use uniffi::Record; + +#[derive(Record, Clone, Debug)] +pub struct PeerId { + /// The peer ID stored as base58 string. + pub peer_id: String, +} + +impl PeerId { + pub fn to_libp2p(&self) -> std::result::Result { + Libp2pPeerId::from_str(&self.peer_id).map_err(|e| format!("Invalid peer ID format: {}", e)) + } + + pub fn from_libp2p(peer_id: &Libp2pPeerId) -> Self { + Self { + peer_id: peer_id.to_string(), + } + } +} + +impl From for PeerId { + fn from(peer_id: Libp2pPeerId) -> Self { + Self { + peer_id: peer_id.to_string(), + } + } +} + +#[derive(Record)] +pub struct ShareCoordinate { + row: u16, + column: u16, +} + +/// Events emitted by the node. +#[derive(uniffi::Enum)] +pub enum NodeEvent { + /// Node is connecting to bootnodes + ConnectingToBootnodes, + /// Peer just connected + PeerConnected { + /// The ID of the peer. + id: PeerId, + /// Whether peer was in the trusted list or not. + trusted: bool, + }, + PeerDisconnected { + /// The ID of the peer. + id: PeerId, + /// Whether peer was in the trusted list or not. + trusted: bool, + }, + /// Sampling just started. + SamplingStarted { + /// The block height that will be sampled. + height: u64, + /// The square width of the block. + square_width: u16, + /// The coordinates of the shares that will be sampled. + shares: Vec, + }, + /// A share was sampled. + ShareSamplingResult { + /// The block height of the share. + height: u64, + /// The square width of the block. + square_width: u16, + /// The row of the share. + row: u16, + /// The column of the share. + column: u16, + /// The result of the sampling of the share. + accepted: bool, + }, + /// Sampling just finished. + SamplingFinished { + /// The block height that was sampled. + height: u64, + /// The overall result of the sampling. + accepted: bool, + /// How much time sampling took in milliseconds. + took_ms: u64, + }, + /// Data sampling fatal error. + FatalDaserError { + /// A human readable error. + error: String, + }, + /// A new header was added from HeaderSub. + AddedHeaderFromHeaderSub { + /// The height of the header. + height: u64, + }, + /// Fetching header of network head just started. + FetchingHeadHeaderStarted, + /// Fetching header of network head just finished. + FetchingHeadHeaderFinished { + /// The height of the network head. + height: u64, + /// How much time fetching took in milliseconds. + took_ms: u64, + }, + /// Fetching headers of a specific block range just started. + FetchingHeadersStarted { + /// Start of the range. + from_height: u64, + /// End of the range (included). + to_height: u64, + }, + /// Fetching headers of a specific block range just finished. + FetchingHeadersFinished { + /// Start of the range. + from_height: u64, + /// End of the range (included). + to_height: u64, + /// How much time fetching took in milliseconds. + took_ms: u64, + }, + /// Fetching headers of a specific block range just failed. + FetchingHeadersFailed { + /// Start of the range. + from_height: u64, + /// End of the range (included). + to_height: u64, + /// A human readable error. + error: String, + /// How much time fetching took in milliseconds. + took_ms: u64, + }, + /// Header syncing fatal error. + FatalSyncerError { + /// A human readable error. + error: String, + }, + /// Pruned headers up to and including specified height. + PrunedHeaders { + /// Last header height that was pruned + to_height: u64, + }, + /// Pruning fatal error. + FatalPrunerError { + /// A human readable error. + error: String, + }, + /// Network was compromised. + /// + /// This happens when a valid bad encoding fraud proof is received. + /// Ideally it would never happen, but protection needs to exist. + /// In case of compromised network, syncing and data sampling will + /// stop immediately. + NetworkCompromised, + /// Node stopped. + NodeStopped, +} + +impl From for NodeEvent { + fn from(event: LuminaNodeEvent) -> Self { + match event { + LuminaNodeEvent::ConnectingToBootnodes => NodeEvent::ConnectingToBootnodes, + LuminaNodeEvent::PeerConnected { id, trusted } => NodeEvent::PeerConnected { + id: PeerId::from_libp2p(&id), + trusted, + }, + LuminaNodeEvent::PeerDisconnected { id, trusted } => NodeEvent::PeerDisconnected { + id: PeerId::from_libp2p(&id), + trusted, + }, + LuminaNodeEvent::SamplingStarted { + height, + square_width, + shares, + } => NodeEvent::SamplingStarted { + height, + square_width, + shares: shares + .into_iter() + .map(|(row, col)| ShareCoordinate { row, column: col }) + .collect(), + }, + LuminaNodeEvent::ShareSamplingResult { + height, + square_width, + row, + column, + accepted, + } => NodeEvent::ShareSamplingResult { + height, + square_width, + row, + column, + accepted, + }, + LuminaNodeEvent::SamplingFinished { + height, + accepted, + took, + } => NodeEvent::SamplingFinished { + height, + accepted, + took_ms: took.as_millis() as u64, + }, + LuminaNodeEvent::FatalDaserError { error } => NodeEvent::FatalDaserError { error }, + LuminaNodeEvent::AddedHeaderFromHeaderSub { height } => { + NodeEvent::AddedHeaderFromHeaderSub { height } + } + LuminaNodeEvent::FetchingHeadHeaderStarted => NodeEvent::FetchingHeadHeaderStarted, + LuminaNodeEvent::FetchingHeadHeaderFinished { height, took } => { + NodeEvent::FetchingHeadHeaderFinished { + height, + took_ms: took.as_millis() as u64, + } + } + LuminaNodeEvent::FetchingHeadersStarted { + from_height, + to_height, + } => NodeEvent::FetchingHeadersStarted { + from_height, + to_height, + }, + LuminaNodeEvent::FetchingHeadersFinished { + from_height, + to_height, + took, + } => NodeEvent::FetchingHeadersFinished { + from_height, + to_height, + took_ms: took.as_millis() as u64, + }, + LuminaNodeEvent::FetchingHeadersFailed { + from_height, + to_height, + error, + took, + } => NodeEvent::FetchingHeadersFailed { + from_height, + to_height, + error, + took_ms: took.as_millis() as u64, + }, + LuminaNodeEvent::FatalSyncerError { error } => NodeEvent::FatalSyncerError { error }, + LuminaNodeEvent::PrunedHeaders { to_height } => NodeEvent::PrunedHeaders { to_height }, + LuminaNodeEvent::FatalPrunerError { error } => NodeEvent::FatalPrunerError { error }, + LuminaNodeEvent::NetworkCompromised => NodeEvent::NetworkCompromised, + LuminaNodeEvent::NodeStopped => NodeEvent::NodeStopped, + _ => panic!("Unknown event: {:?}", event), + } + } +} diff --git a/node-uniffi/src/types/mod.rs b/node-uniffi/src/types/mod.rs new file mode 100644 index 00000000..a66c1beb --- /dev/null +++ b/node-uniffi/src/types/mod.rs @@ -0,0 +1,9 @@ +mod config; +mod event; +mod network; +mod sync; + +pub use config::NodeConfig; +pub use event::{NodeEvent, PeerId}; +pub use network::NetworkInfo; +pub use sync::SyncingInfo; diff --git a/node-uniffi/src/types/network.rs b/node-uniffi/src/types/network.rs new file mode 100644 index 00000000..dc7d0a1c --- /dev/null +++ b/node-uniffi/src/types/network.rs @@ -0,0 +1,53 @@ +use libp2p::swarm::ConnectionCounters as Libp2pConnectionCounters; +use libp2p::swarm::NetworkInfo as Libp2pNetworkInfo; +use uniffi::Record; + +#[derive(Record)] +pub struct NetworkInfo { + /// The total number of connected peers. + pub num_peers: u32, + /// Counters of ongoing network connections. + connection_counters: ConnectionCounters, +} + +/// Counters of ongoing network connections. +#[derive(Record)] +struct ConnectionCounters { + /// The current number of connections. + pub num_connections: u32, + /// The current number of pending connections. + pub num_pending: u32, + /// The current number of incoming connections. + pub num_pending_incoming: u32, + /// The current number of outgoing connections. + pub num_pending_outgoing: u32, + /// The current number of established connections. + pub num_established: u32, + /// The current number of established inbound connections. + pub num_established_incoming: u32, + /// The current number of established outbound connections. + pub num_established_outgoing: u32, +} + +impl From for NetworkInfo { + fn from(info: Libp2pNetworkInfo) -> Self { + Self { + num_peers: info.num_peers() as u32, + connection_counters: info.connection_counters().into(), + } + } +} + +impl From<&Libp2pConnectionCounters> for ConnectionCounters { + fn from(counters: &Libp2pConnectionCounters) -> Self { + Self { + num_connections: counters.num_connections(), + num_pending: counters.num_pending(), + num_pending_incoming: counters.num_pending_incoming(), + num_pending_outgoing: counters.num_pending_outgoing(), + num_established: counters.num_established(), + num_established_incoming: counters.num_established_incoming(), + num_established_outgoing: counters.num_established_outgoing(), + } + } +} diff --git a/node-uniffi/src/types/sync.rs b/node-uniffi/src/types/sync.rs new file mode 100644 index 00000000..764676dc --- /dev/null +++ b/node-uniffi/src/types/sync.rs @@ -0,0 +1,42 @@ +use lumina_node::block_ranges::BlockRange as LuminaBlockRange; +use lumina_node::node::SyncingInfo as LuminaSyncingInfo; +use uniffi::Record; + +/// A range of blocks. +#[derive(Record)] +struct BlockRange { + start: u64, + end: u64, +} + +impl From for BlockRange { + fn from(range: LuminaBlockRange) -> Self { + Self { + start: *range.start(), + end: *range.end(), + } + } +} + +/// Status of the node syncing. +#[derive(Record)] +pub struct SyncingInfo { + /// Ranges of headers that are already synchronised + stored_headers: Vec, + /// Syncing target. The latest height seen in the network that was successfully verified. + subjective_head: u64, +} + +impl From for SyncingInfo { + fn from(info: LuminaSyncingInfo) -> Self { + Self { + stored_headers: info + .stored_headers + .into_inner() + .into_iter() + .map(BlockRange::from) + .collect(), + subjective_head: info.subjective_head, + } + } +} From 5a80419985eaeb21e7faae83451f5ee7c1845c2d Mon Sep 17 00:00:00 2001 From: sebasti810 Date: Mon, 23 Dec 2024 12:06:58 +0100 Subject: [PATCH 12/13] refac: simplify error handling --- node-uniffi/src/error.rs | 36 ++++++-- node-uniffi/src/lib.rs | 148 ++++++++++++++------------------ node-uniffi/src/types/config.rs | 25 ++---- 3 files changed, 101 insertions(+), 108 deletions(-) diff --git a/node-uniffi/src/error.rs b/node-uniffi/src/error.rs index 646188cf..68840b9d 100644 --- a/node-uniffi/src/error.rs +++ b/node-uniffi/src/error.rs @@ -13,14 +13,14 @@ pub enum LuminaError { /// Error returned when network operations fail #[error("Network error: {msg}")] - NetworkError { + Network { /// Description of the network error msg: String, }, /// Error returned when storage operations fail #[error("Storage error: {msg}")] - StorageError { + Storage { /// Description of the storage error msg: String, }, @@ -31,7 +31,7 @@ pub enum LuminaError { /// Error returned when a mutex lock operation fails #[error("Lock error")] - LockError, + Lock, /// Error returned when a hash string is invalid or malformed #[error("Invalid hash format: {msg}")] @@ -55,18 +55,36 @@ pub enum LuminaError { }, } +impl LuminaError { + pub fn network(msg: impl Into) -> Self { + Self::Network { msg: msg.into() } + } + + pub fn storage(msg: impl Into) -> Self { + Self::Storage { msg: msg.into() } + } + + pub fn invalid_hash(msg: impl Into) -> Self { + Self::InvalidHash { msg: msg.into() } + } + + pub fn invalid_header(msg: impl Into) -> Self { + Self::InvalidHeader { msg: msg.into() } + } + + pub fn storage_init(msg: impl Into) -> Self { + Self::StorageInit { msg: msg.into() } + } +} + impl From for LuminaError { fn from(error: NodeError) -> Self { - LuminaError::NetworkError { - msg: error.to_string(), - } + LuminaError::network(error.to_string()) } } impl From for LuminaError { fn from(e: libp2p::multiaddr::Error) -> Self { - LuminaError::NetworkError { - msg: format!("Invalid multiaddr: {}", e), - } + LuminaError::network(format!("Invalid multiaddr: {}", e)) } } diff --git a/node-uniffi/src/lib.rs b/node-uniffi/src/lib.rs index e7ff6b1c..46976a7b 100644 --- a/node-uniffi/src/lib.rs +++ b/node-uniffi/src/lib.rs @@ -47,16 +47,11 @@ impl LuminaNode { pub async fn start(&self) -> Result { let mut node_lock = self.node.write().await; if node_lock.is_some() { - return Err(LuminaError::NetworkError { - msg: "Node is already running".to_string(), - }); + return Err(LuminaError::network("Node is already running")); } let builder = self.config.clone().into_node_builder().await?; - let (new_node, subscriber) = builder - .start_subscribed() - .await - .map_err(|e| LuminaError::NetworkError { msg: e.to_string() })?; + let (new_node, subscriber) = builder.start_subscribed().await?; *self.events_subscriber.lock().await = Some(subscriber); *node_lock = Some(new_node); @@ -71,9 +66,7 @@ impl LuminaNode { node.stop().await; Ok(()) } else { - Err(LuminaError::NetworkError { - msg: "Node is already stopped".to_string(), - }) + Err(LuminaError::network("Node is already stopped")) } } @@ -85,45 +78,45 @@ impl LuminaNode { /// Gets the local peer ID as a string. pub async fn local_peer_id(&self) -> Result { let node = self.node.read().await; - let node = node.as_ref().ok_or(LuminaError::NetworkError { - msg: "Node not initialized".to_string(), - })?; + let node = node + .as_ref() + .ok_or(LuminaError::network("Node not initialized"))?; Ok(node.local_peer_id().to_base58()) } /// Gets information about connected peers. pub async fn peer_tracker_info(&self) -> Result { let node = self.node.read().await; - let node = node.as_ref().ok_or(LuminaError::NetworkError { - msg: "Node not initialized".to_string(), - })?; + let node = node + .as_ref() + .ok_or(LuminaError::network("Node not initialized"))?; Ok(node.peer_tracker_info()) } /// Waits until the node is connected to at least one peer. pub async fn wait_connected(&self) -> Result<()> { let node = self.node.read().await; - let node = node.as_ref().ok_or(LuminaError::NetworkError { - msg: "Node not initialized".to_string(), - })?; + let node = node + .as_ref() + .ok_or(LuminaError::network("Node not initialized"))?; Ok(node.wait_connected().await?) } /// Waits until the node is connected to at least one trusted peer. pub async fn wait_connected_trusted(&self) -> Result<()> { let node = self.node.read().await; - let node = node.as_ref().ok_or(LuminaError::NetworkError { - msg: "Node not initialized".to_string(), - })?; + let node = node + .as_ref() + .ok_or(LuminaError::network("Node not initialized"))?; Ok(node.wait_connected_trusted().await?) } /// Gets current network information. pub async fn network_info(&self) -> Result { let node = self.node.read().await; - let node = node.as_ref().ok_or(LuminaError::NetworkError { - msg: "Node not initialized".to_string(), - })?; + let node = node + .as_ref() + .ok_or(LuminaError::network("Node not initialized"))?; let info = node.network_info().await?; Ok(info.into()) } @@ -131,9 +124,9 @@ impl LuminaNode { /// Gets list of addresses the node is listening to. pub async fn listeners(&self) -> Result> { let node = self.node.read().await; - let node = node.as_ref().ok_or(LuminaError::NetworkError { - msg: "Node not initialized".to_string(), - })?; + let node = node + .as_ref() + .ok_or(LuminaError::network("Node not initialized"))?; let listeners = node.listeners().await?; Ok(listeners.into_iter().map(|l| l.to_string()).collect()) } @@ -141,9 +134,9 @@ impl LuminaNode { /// Gets list of currently connected peer IDs. pub async fn connected_peers(&self) -> Result> { let node = self.node.read().await; - let node = node.as_ref().ok_or(LuminaError::NetworkError { - msg: "Node not initialized".to_string(), - })?; + let node = node + .as_ref() + .ok_or(LuminaError::network("Node not initialized"))?; let peers = node.connected_peers().await?; Ok(peers.into_iter().map(PeerId::from).collect()) } @@ -151,12 +144,10 @@ impl LuminaNode { /// Sets whether a peer with give ID is trusted. pub async fn set_peer_trust(&self, peer_id: PeerId, is_trusted: bool) -> Result<()> { let node = self.node.read().await; - let node = node.as_ref().ok_or(LuminaError::NetworkError { - msg: "Node not initialized".to_string(), - })?; - let peer_id = peer_id - .to_libp2p() - .map_err(|e| LuminaError::NetworkError { msg: e.to_string() })?; + let node = node + .as_ref() + .ok_or(LuminaError::network("Node not initialized"))?; + let peer_id = peer_id.to_libp2p().map_err(LuminaError::network)?; Ok(node.set_peer_trust(peer_id, is_trusted).await?) } @@ -165,9 +156,9 @@ impl LuminaNode { /// Returns a serialized ExtendedHeader string. pub async fn request_head_header(&self) -> Result { let node = self.node.read().await; - let node = node.as_ref().ok_or(LuminaError::NetworkError { - msg: "Node not initialized".to_string(), - })?; + let node = node + .as_ref() + .ok_or(LuminaError::network("Node not initialized"))?; let header = node.request_head_header().await?; Ok(header.to_string()) //if extended header is needed, we need a wrapper } @@ -175,11 +166,10 @@ impl LuminaNode { /// Request a header for the block with a given hash from the network. pub async fn request_header_by_hash(&self, hash: String) -> Result { let node = self.node.read().await; - let node = node.as_ref().ok_or(LuminaError::NetworkError { - msg: "Node not initialized".to_string(), - })?; - let hash = - Hash::from_str(&hash).map_err(|e| LuminaError::InvalidHash { msg: e.to_string() })?; + let node = node + .as_ref() + .ok_or(LuminaError::network("Node not initialized"))?; + let hash = Hash::from_str(&hash).map_err(|e| LuminaError::invalid_hash(e.to_string()))?; let header = node.request_header_by_hash(&hash).await?; Ok(header.to_string()) //if extended header is needed, we need a wrapper } @@ -187,9 +177,9 @@ impl LuminaNode { /// Requests a header by its height. pub async fn request_header_by_height(&self, height: u64) -> Result { let node = self.node.read().await; - let node = node.as_ref().ok_or(LuminaError::NetworkError { - msg: "Node not initialized".to_string(), - })?; + let node = node + .as_ref() + .ok_or(LuminaError::network("Node not initialized"))?; let header = node.request_header_by_height(height).await?; Ok(header.to_string()) } @@ -204,9 +194,9 @@ impl LuminaNode { amount: u64, ) -> Result> { let node = self.node.read().await; - let node = node.as_ref().ok_or(LuminaError::NetworkError { - msg: "Node not initialized".to_string(), - })?; + let node = node + .as_ref() + .ok_or(LuminaError::network("Node not initialized"))?; let from: ExtendedHeader = serde_json::from_str(&from).map_err(|e| LuminaError::InvalidHeader { msg: format!("Invalid header JSON: {}", e), @@ -218,9 +208,9 @@ impl LuminaNode { /// Gets current syncing information. pub async fn syncer_info(&self) -> Result { let node = self.node.read().await; - let node = node.as_ref().ok_or(LuminaError::NetworkError { - msg: "Node not initialized".to_string(), - })?; + let node = node + .as_ref() + .ok_or(LuminaError::network("Node not initialized"))?; let info = node.syncer_info().await?; Ok(info.into()) } @@ -228,15 +218,12 @@ impl LuminaNode { /// Gets the latest header announced in the network. pub async fn get_network_head_header(&self) -> Result { let node = self.node.read().await; - let node = node.as_ref().ok_or(LuminaError::NetworkError { - msg: "Node not initialized".to_string(), - })?; + let node = node + .as_ref() + .ok_or(LuminaError::network("Node not initialized"))?; let header = node.get_network_head_header().await?; header.map_or( - // todo: better error handling, its undefined in wasm - Err(LuminaError::NetworkError { - msg: "No network head header available".to_string(), - }), + Err(LuminaError::network("No network head header available")), |h| Ok(h.to_string()), ) } @@ -244,9 +231,9 @@ impl LuminaNode { /// Gets the latest locally synced header. pub async fn get_local_head_header(&self) -> Result { let node = self.node.read().await; - let node = node.as_ref().ok_or(LuminaError::NetworkError { - msg: "Node not initialized".to_string(), - })?; + let node = node + .as_ref() + .ok_or(LuminaError::network("Node not initialized"))?; let header = node.get_local_head_header().await?; Ok(header.to_string()) } @@ -254,11 +241,10 @@ impl LuminaNode { /// Get a synced header for the block with a given hash. pub async fn get_header_by_hash(&self, hash: String) -> Result { let node = self.node.read().await; - let node = node.as_ref().ok_or(LuminaError::NetworkError { - msg: "Node not initialized".to_string(), - })?; - let hash = - Hash::from_str(&hash).map_err(|e| LuminaError::InvalidHash { msg: e.to_string() })?; + let node = node + .as_ref() + .ok_or(LuminaError::network("Node not initialized"))?; + let hash = Hash::from_str(&hash).map_err(|e| LuminaError::invalid_hash(e.to_string()))?; let header = node.get_header_by_hash(&hash).await?; Ok(header.to_string()) } @@ -266,9 +252,9 @@ impl LuminaNode { /// Get a synced header for the block with a given height. pub async fn get_header_by_height(&self, height: u64) -> Result { let node = self.node.read().await; - let node = node.as_ref().ok_or(LuminaError::NetworkError { - msg: "Node not initialized".to_string(), - })?; + let node = node + .as_ref() + .ok_or(LuminaError::network("Node not initialized"))?; let header = node.get_header_by_height(height).await?; Ok(header.to_string()) } @@ -286,9 +272,9 @@ impl LuminaNode { end_height: Option, ) -> Result> { let node = self.node.read().await; - let node = node.as_ref().ok_or(LuminaError::NetworkError { - msg: "Node not initialized".to_string(), - })?; + let node = node + .as_ref() + .ok_or(LuminaError::network("Node not initialized"))?; let headers = match (start_height, end_height) { (None, None) => node.get_headers(..).await, @@ -305,9 +291,9 @@ impl LuminaNode { /// Returns serialized SamplingMetadata string if metadata exists for the height. pub async fn get_sampling_metadata(&self, height: u64) -> Result> { let node = self.node.read().await; - let node = node.as_ref().ok_or(LuminaError::NetworkError { - msg: "Node not initialized".to_string(), - })?; + let node = node + .as_ref() + .ok_or(LuminaError::network("Node not initialized"))?; let metadata = node.get_sampling_metadata(height).await?; Ok(metadata.map(|m| serde_json::to_string(&m).unwrap())) @@ -319,11 +305,9 @@ impl LuminaNode { match events_subscriber.as_mut() { Some(subscriber) => match subscriber.try_recv() { Ok(event) => Ok(Some(event.event.into())), - Err(e) => Err(LuminaError::NetworkError { msg: e.to_string() }), + Err(e) => Err(LuminaError::network(e.to_string())), }, - None => Err(LuminaError::NetworkError { - msg: "Node is not running".to_string(), - }), + None => Err(LuminaError::network("Node is not running")), } } } diff --git a/node-uniffi/src/types/config.rs b/node-uniffi/src/types/config.rs index 7c8ddcf1..83c0b211 100644 --- a/node-uniffi/src/types/config.rs +++ b/node-uniffi/src/types/config.rs @@ -35,14 +35,12 @@ impl NodeConfig { let store_path = base_path.join(format!("store-{}", network_id)); spawn_blocking(move || { - std::fs::create_dir_all(&base_path).map_err(|e| LuminaError::StorageError { - msg: format!("Failed to create data directory: {}", e), + std::fs::create_dir_all(&base_path).map_err(|e| { + LuminaError::storage(format!("Failed to create base directory: {}", e)) }) }) .await - .map_err(|e| LuminaError::StorageError { - msg: format!("Task join error: {}", e), - })??; + .map_err(|e| LuminaError::storage(format!("Failed to create base directory: {}", e)))??; let db = spawn_blocking(move || { redb::Database::create(&store_path) @@ -52,15 +50,11 @@ impl NodeConfig { }) }) .await - .map_err(|e| LuminaError::StorageError { - msg: format!("Task join error: {}", e), - })??; + .map_err(|e| LuminaError::storage(format!("Failed to create base directory: {}", e)))??; let store = RedbStore::new(db.clone()) .await - .map_err(|e| LuminaError::StorageInit { - msg: format!("Failed to initialize store: {}", e), - })?; + .map_err(|e| LuminaError::storage_init(format!("Failed to initialize store: {}", e)))?; let blockstore = RedbBlockstore::new(db); @@ -76,14 +70,11 @@ impl NodeConfig { let keypair = if let Some(key_bytes) = self.ed25519_secret_key_bytes { if key_bytes.len() != 32 { - return Err(LuminaError::NetworkError { - msg: "Ed25519 private key must be 32 bytes".into(), - }); + return Err(LuminaError::network("Ed25519 private key must be 32 bytes")); } - Keypair::ed25519_from_bytes(key_bytes).map_err(|e| LuminaError::NetworkError { - msg: format!("Invalid Ed25519 key: {}", e), - })? + Keypair::ed25519_from_bytes(key_bytes) + .map_err(|e| LuminaError::network(format!("Invalid Ed25519 key: {}", e)))? } else { libp2p::identity::Keypair::generate_ed25519() }; From f88d95d4eed6b41d3051095af39f4ff1219eae8e Mon Sep 17 00:00:00 2001 From: sebasti810 Date: Fri, 27 Dec 2024 15:21:48 +0100 Subject: [PATCH 13/13] refac: errors and event channel method --- node-uniffi/src/error.rs | 4 -- node-uniffi/src/lib.rs | 101 +++++++++++++-------------------------- 2 files changed, 32 insertions(+), 73 deletions(-) diff --git a/node-uniffi/src/error.rs b/node-uniffi/src/error.rs index 68840b9d..374e5394 100644 --- a/node-uniffi/src/error.rs +++ b/node-uniffi/src/error.rs @@ -29,10 +29,6 @@ pub enum LuminaError { #[error("Node is already running")] AlreadyRunning, - /// Error returned when a mutex lock operation fails - #[error("Lock error")] - Lock, - /// Error returned when a hash string is invalid or malformed #[error("Invalid hash format: {msg}")] InvalidHash { diff --git a/node-uniffi/src/lib.rs b/node-uniffi/src/lib.rs index 46976a7b..7bb46544 100644 --- a/node-uniffi/src/lib.rs +++ b/node-uniffi/src/lib.rs @@ -47,7 +47,7 @@ impl LuminaNode { pub async fn start(&self) -> Result { let mut node_lock = self.node.write().await; if node_lock.is_some() { - return Err(LuminaError::network("Node is already running")); + return Err(LuminaError::AlreadyRunning); } let builder = self.config.clone().into_node_builder().await?; @@ -66,7 +66,7 @@ impl LuminaNode { node.stop().await; Ok(()) } else { - Err(LuminaError::network("Node is already stopped")) + Err(LuminaError::NodeNotRunning) } } @@ -78,45 +78,35 @@ impl LuminaNode { /// Gets the local peer ID as a string. pub async fn local_peer_id(&self) -> Result { let node = self.node.read().await; - let node = node - .as_ref() - .ok_or(LuminaError::network("Node not initialized"))?; + let node = node.as_ref().ok_or(LuminaError::NodeNotRunning)?; Ok(node.local_peer_id().to_base58()) } /// Gets information about connected peers. pub async fn peer_tracker_info(&self) -> Result { let node = self.node.read().await; - let node = node - .as_ref() - .ok_or(LuminaError::network("Node not initialized"))?; + let node = node.as_ref().ok_or(LuminaError::NodeNotRunning)?; Ok(node.peer_tracker_info()) } /// Waits until the node is connected to at least one peer. pub async fn wait_connected(&self) -> Result<()> { let node = self.node.read().await; - let node = node - .as_ref() - .ok_or(LuminaError::network("Node not initialized"))?; + let node = node.as_ref().ok_or(LuminaError::NodeNotRunning)?; Ok(node.wait_connected().await?) } /// Waits until the node is connected to at least one trusted peer. pub async fn wait_connected_trusted(&self) -> Result<()> { let node = self.node.read().await; - let node = node - .as_ref() - .ok_or(LuminaError::network("Node not initialized"))?; + let node = node.as_ref().ok_or(LuminaError::NodeNotRunning)?; Ok(node.wait_connected_trusted().await?) } /// Gets current network information. pub async fn network_info(&self) -> Result { let node = self.node.read().await; - let node = node - .as_ref() - .ok_or(LuminaError::network("Node not initialized"))?; + let node = node.as_ref().ok_or(LuminaError::NodeNotRunning)?; let info = node.network_info().await?; Ok(info.into()) } @@ -124,9 +114,7 @@ impl LuminaNode { /// Gets list of addresses the node is listening to. pub async fn listeners(&self) -> Result> { let node = self.node.read().await; - let node = node - .as_ref() - .ok_or(LuminaError::network("Node not initialized"))?; + let node = node.as_ref().ok_or(LuminaError::NodeNotRunning)?; let listeners = node.listeners().await?; Ok(listeners.into_iter().map(|l| l.to_string()).collect()) } @@ -134,9 +122,7 @@ impl LuminaNode { /// Gets list of currently connected peer IDs. pub async fn connected_peers(&self) -> Result> { let node = self.node.read().await; - let node = node - .as_ref() - .ok_or(LuminaError::network("Node not initialized"))?; + let node = node.as_ref().ok_or(LuminaError::NodeNotRunning)?; let peers = node.connected_peers().await?; Ok(peers.into_iter().map(PeerId::from).collect()) } @@ -144,9 +130,7 @@ impl LuminaNode { /// Sets whether a peer with give ID is trusted. pub async fn set_peer_trust(&self, peer_id: PeerId, is_trusted: bool) -> Result<()> { let node = self.node.read().await; - let node = node - .as_ref() - .ok_or(LuminaError::network("Node not initialized"))?; + let node = node.as_ref().ok_or(LuminaError::NodeNotRunning)?; let peer_id = peer_id.to_libp2p().map_err(LuminaError::network)?; Ok(node.set_peer_trust(peer_id, is_trusted).await?) } @@ -156,9 +140,7 @@ impl LuminaNode { /// Returns a serialized ExtendedHeader string. pub async fn request_head_header(&self) -> Result { let node = self.node.read().await; - let node = node - .as_ref() - .ok_or(LuminaError::network("Node not initialized"))?; + let node = node.as_ref().ok_or(LuminaError::NodeNotRunning)?; let header = node.request_head_header().await?; Ok(header.to_string()) //if extended header is needed, we need a wrapper } @@ -166,9 +148,7 @@ impl LuminaNode { /// Request a header for the block with a given hash from the network. pub async fn request_header_by_hash(&self, hash: String) -> Result { let node = self.node.read().await; - let node = node - .as_ref() - .ok_or(LuminaError::network("Node not initialized"))?; + let node = node.as_ref().ok_or(LuminaError::NodeNotRunning)?; let hash = Hash::from_str(&hash).map_err(|e| LuminaError::invalid_hash(e.to_string()))?; let header = node.request_header_by_hash(&hash).await?; Ok(header.to_string()) //if extended header is needed, we need a wrapper @@ -177,9 +157,7 @@ impl LuminaNode { /// Requests a header by its height. pub async fn request_header_by_height(&self, height: u64) -> Result { let node = self.node.read().await; - let node = node - .as_ref() - .ok_or(LuminaError::network("Node not initialized"))?; + let node = node.as_ref().ok_or(LuminaError::NodeNotRunning)?; let header = node.request_header_by_height(height).await?; Ok(header.to_string()) } @@ -194,13 +172,9 @@ impl LuminaNode { amount: u64, ) -> Result> { let node = self.node.read().await; - let node = node - .as_ref() - .ok_or(LuminaError::network("Node not initialized"))?; - let from: ExtendedHeader = - serde_json::from_str(&from).map_err(|e| LuminaError::InvalidHeader { - msg: format!("Invalid header JSON: {}", e), - })?; + let node = node.as_ref().ok_or(LuminaError::NodeNotRunning)?; + let from: ExtendedHeader = serde_json::from_str(&from) + .map_err(|e| LuminaError::invalid_header(format!("Invalid header JSON: {}", e)))?; let headers = node.request_verified_headers(&from, amount).await?; Ok(headers.into_iter().map(|h| h.to_string()).collect()) } @@ -208,9 +182,7 @@ impl LuminaNode { /// Gets current syncing information. pub async fn syncer_info(&self) -> Result { let node = self.node.read().await; - let node = node - .as_ref() - .ok_or(LuminaError::network("Node not initialized"))?; + let node = node.as_ref().ok_or(LuminaError::NodeNotRunning)?; let info = node.syncer_info().await?; Ok(info.into()) } @@ -218,9 +190,7 @@ impl LuminaNode { /// Gets the latest header announced in the network. pub async fn get_network_head_header(&self) -> Result { let node = self.node.read().await; - let node = node - .as_ref() - .ok_or(LuminaError::network("Node not initialized"))?; + let node = node.as_ref().ok_or(LuminaError::NodeNotRunning)?; let header = node.get_network_head_header().await?; header.map_or( Err(LuminaError::network("No network head header available")), @@ -231,9 +201,7 @@ impl LuminaNode { /// Gets the latest locally synced header. pub async fn get_local_head_header(&self) -> Result { let node = self.node.read().await; - let node = node - .as_ref() - .ok_or(LuminaError::network("Node not initialized"))?; + let node = node.as_ref().ok_or(LuminaError::NodeNotRunning)?; let header = node.get_local_head_header().await?; Ok(header.to_string()) } @@ -241,9 +209,7 @@ impl LuminaNode { /// Get a synced header for the block with a given hash. pub async fn get_header_by_hash(&self, hash: String) -> Result { let node = self.node.read().await; - let node = node - .as_ref() - .ok_or(LuminaError::network("Node not initialized"))?; + let node = node.as_ref().ok_or(LuminaError::NodeNotRunning)?; let hash = Hash::from_str(&hash).map_err(|e| LuminaError::invalid_hash(e.to_string()))?; let header = node.get_header_by_hash(&hash).await?; Ok(header.to_string()) @@ -252,9 +218,7 @@ impl LuminaNode { /// Get a synced header for the block with a given height. pub async fn get_header_by_height(&self, height: u64) -> Result { let node = self.node.read().await; - let node = node - .as_ref() - .ok_or(LuminaError::network("Node not initialized"))?; + let node = node.as_ref().ok_or(LuminaError::NodeNotRunning)?; let header = node.get_header_by_height(height).await?; Ok(header.to_string()) } @@ -272,9 +236,7 @@ impl LuminaNode { end_height: Option, ) -> Result> { let node = self.node.read().await; - let node = node - .as_ref() - .ok_or(LuminaError::network("Node not initialized"))?; + let node = node.as_ref().ok_or(LuminaError::NodeNotRunning)?; let headers = match (start_height, end_height) { (None, None) => node.get_headers(..).await, @@ -291,23 +253,24 @@ impl LuminaNode { /// Returns serialized SamplingMetadata string if metadata exists for the height. pub async fn get_sampling_metadata(&self, height: u64) -> Result> { let node = self.node.read().await; - let node = node - .as_ref() - .ok_or(LuminaError::network("Node not initialized"))?; + let node = node.as_ref().ok_or(LuminaError::NodeNotRunning)?; let metadata = node.get_sampling_metadata(height).await?; Ok(metadata.map(|m| serde_json::to_string(&m).unwrap())) } /// Returns the next event from the node's event channel. - pub async fn events_channel(&self) -> Result> { + pub async fn next_event(&self) -> Result { let mut events_subscriber = self.events_subscriber.lock().await; match events_subscriber.as_mut() { - Some(subscriber) => match subscriber.try_recv() { - Ok(event) => Ok(Some(event.event.into())), - Err(e) => Err(LuminaError::network(e.to_string())), - }, - None => Err(LuminaError::network("Node is not running")), + Some(subscriber) => { + let event = subscriber + .recv() + .await + .map_err(|_| LuminaError::NodeNotRunning)?; + Ok(event.event.into()) + } + None => Err(LuminaError::NodeNotRunning), } } }