From 3f3f76d7417963caceac7748ac17d7f6a815e234 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Fri, 20 Dec 2024 11:43:40 +0100 Subject: [PATCH] chore: WIP --- Cargo.lock | 304 ++++++++++++++++-- Cargo.toml | 2 +- packages/rs-dapi-client/Cargo.toml | 28 +- packages/rs-dapi-client/src/address_list.rs | 2 +- .../rs-dapi-client/src/connection_pool.rs | 2 +- packages/rs-dapi-client/src/dapi_client.rs | 14 +- packages/rs-dapi-client/src/executor.rs | 8 +- packages/rs-dapi-client/src/lib.rs | 7 + .../rs-dapi-client/src/request_settings.rs | 4 + packages/rs-dapi-client/src/transport.rs | 13 +- packages/rs-dapi-client/src/transport/grpc.rs | 49 +-- .../src/transport/tonic_channel.rs | 57 ++++ .../src/transport/wasm_channel.rs | 67 ++++ packages/rs-dpp/src/balances/credits.rs | 4 - packages/rs-drive-abci/Cargo.toml | 5 +- packages/rs-drive-proof-verifier/Cargo.toml | 5 +- packages/rs-sdk/Cargo.toml | 23 +- .../platform/transition/broadcast_identity.rs | 29 +- packages/rs-sdk/src/sdk.rs | 8 +- packages/rs-sdk/src/sync.rs | 17 +- packages/wasm-sdk/Cargo.toml | 31 ++ packages/wasm-sdk/index.html | 59 ++++ packages/wasm-sdk/src/lib.rs | 11 + 23 files changed, 645 insertions(+), 104 deletions(-) create mode 100644 packages/rs-dapi-client/src/transport/tonic_channel.rs create mode 100644 packages/rs-dapi-client/src/transport/wasm_channel.rs create mode 100644 packages/wasm-sdk/Cargo.toml create mode 100644 packages/wasm-sdk/index.html create mode 100644 packages/wasm-sdk/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index ea460381688..d518d867684 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -183,17 +183,113 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9" +[[package]] +name = "async-channel" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" +dependencies = [ + "concurrent-queue", + "event-listener 2.5.3", + "futures-core", +] + +[[package]] +name = "async-channel" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" +dependencies = [ + "concurrent-queue", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-executor" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30ca9a001c1e8ba5149f91a74362376cc6bc5b919d92d988668657bd570bdcec" +dependencies = [ + "async-task", + "concurrent-queue", + "fastrand", + "futures-lite", + "slab", +] + +[[package]] +name = "async-global-executor" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c" +dependencies = [ + "async-channel 2.3.1", + "async-executor", + "async-io", + "async-lock", + "blocking", + "futures-lite", + "once_cell", +] + +[[package]] +name = "async-io" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a2b323ccce0a1d90b449fd71f2a06ca7faa7c54c2751f06c9bd851fc061059" +dependencies = [ + "async-lock", + "cfg-if", + "concurrent-queue", + "futures-io", + "futures-lite", + "parking", + "polling", + "rustix", + "slab", + "tracing", + "windows-sys 0.59.0", +] + [[package]] name = "async-lock" version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" dependencies = [ - "event-listener", + "event-listener 5.3.1", "event-listener-strategy", "pin-project-lite", ] +[[package]] +name = "async-std" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c634475f29802fde2b8f0b505b1bd00dfe4df7d4a000f0b36f7671197d5c3615" +dependencies = [ + "async-channel 1.9.0", + "async-global-executor", + "async-io", + "async-lock", + "crossbeam-utils", + "futures-channel", + "futures-core", + "futures-io", + "futures-lite", + "gloo-timers", + "kv-log-macro", + "log", + "memchr", + "once_cell", + "pin-project-lite", + "pin-utils", + "slab", + "wasm-bindgen-futures", +] + [[package]] name = "async-stream" version = "0.3.5" @@ -216,6 +312,12 @@ dependencies = [ "syn 2.0.75", ] +[[package]] +name = "async-task" +version = "4.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" + [[package]] name = "async-trait" version = "0.1.83" @@ -309,9 +411,9 @@ dependencies = [ [[package]] name = "backon" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4fa97bb310c33c811334143cf64c5bb2b7b3c06e453db6b095d7061eff8f113" +checksum = "ba5289ec98f68f28dd809fd601059e6aa908bb8f6108620930828283d4ee23d7" dependencies = [ "fastrand", "gloo-timers", @@ -518,6 +620,19 @@ dependencies = [ "generic-array 0.14.7", ] +[[package]] +name = "blocking" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea" +dependencies = [ + "async-channel 2.3.1", + "async-task", + "futures-io", + "futures-lite", + "piper", +] + [[package]] name = "bls-dash-sys" version = "1.2.5" @@ -1139,7 +1254,7 @@ dependencies = [ "serde", "serde_bytes", "serde_json", - "tenderdash-proto", + "tenderdash-proto 1.2.1+1.3.0", "tonic", "tonic-build", ] @@ -1791,6 +1906,12 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "event-listener" +version = "2.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" + [[package]] name = "event-listener" version = "5.3.1" @@ -1808,7 +1929,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" dependencies = [ - "event-listener", + "event-listener 5.3.1", "pin-project-lite", ] @@ -1841,8 +1962,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "531e46835a22af56d1e3b66f04844bed63158bc094a628bec1d321d9b4c44bf2" dependencies = [ "bit-set", - "regex-automata 0.4.7", - "regex-syntax 0.8.4", + "regex-automata 0.4.9", + "regex-syntax 0.8.5", ] [[package]] @@ -2025,6 +2146,19 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +[[package]] +name = "futures-lite" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cef40d21ae2c515b51041df9ed313ed21e572df340ea58a922a0aefe7e8891a1" +dependencies = [ + "fastrand", + "futures-core", + "futures-io", + "parking", + "pin-project-lite", +] + [[package]] name = "futures-macro" version = "0.3.30" @@ -2850,6 +2984,15 @@ dependencies = [ "cpufeatures", ] +[[package]] +name = "kv-log-macro" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f" +dependencies = [ + "log", +] + [[package]] name = "lazy_static" version = "1.5.0" @@ -2944,6 +3087,9 @@ name = "log" version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +dependencies = [ + "value-bag", +] [[package]] name = "lru" @@ -3140,7 +3286,7 @@ dependencies = [ "crossbeam-channel", "crossbeam-epoch", "crossbeam-utils", - "event-listener", + "event-listener 5.3.1", "futures-util", "once_cell", "parking_lot", @@ -3566,6 +3712,17 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "piper" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" +dependencies = [ + "atomic-waker", + "fastrand", + "futures-io", +] + [[package]] name = "pkcs8" version = "0.10.2" @@ -3677,6 +3834,21 @@ dependencies = [ "plotters-backend", ] +[[package]] +name = "polling" +version = "3.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a604568c3202727d1507653cb121dbd627a58684eb09a820fd746bee38b4442f" +dependencies = [ + "cfg-if", + "concurrent-queue", + "hermit-abi 0.4.0", + "pin-project-lite", + "rustix", + "tracing", + "windows-sys 0.59.0", +] + [[package]] name = "portable-atomic" version = "1.7.0" @@ -3977,14 +4149,14 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.6" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" +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]] @@ -3998,13 +4170,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]] @@ -4015,9 +4187,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 = "rend" @@ -4139,11 +4311,14 @@ dependencies = [ name = "rs-dapi-client" version = "1.7.0" dependencies = [ + "async-std", "backon", "chrono", "dapi-grpc", "futures", + "getrandom", "hex", + "http", "http-serde", "lru", "rand", @@ -4152,6 +4327,7 @@ dependencies = [ "sha2", "thiserror", "tokio", + "tonic-web-wasm-client", "tracing", ] @@ -4293,11 +4469,10 @@ dependencies = [ [[package]] name = "sanitize-filename" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ed72fbaf78e6f2d41744923916966c4fbe3d7c74e3037a8ee482f1115572603" +checksum = "bc984f4f9ceb736a7bb755c3e3bd17dc56370af2600c9780dcc48c66453da34d" dependencies = [ - "lazy_static", "regex", ] @@ -4899,7 +5074,7 @@ dependencies = [ "lhash", "semver", "serde_json", - "tenderdash-proto", + "tenderdash-proto 1.2.1+1.3.0 (git+https://github.com/dashpay/rs-tenderdash-abci?tag=v1.2.1%2B1.3.0)", "thiserror", "tokio", "tokio-util", @@ -4909,6 +5084,24 @@ dependencies = [ "uuid", ] +[[package]] +name = "tenderdash-proto" +version = "1.2.1+1.3.0" +dependencies = [ + "bytes", + "chrono", + "derive_more 1.0.0", + "flex-error", + "num-derive", + "num-traits", + "prost", + "serde", + "subtle-encoding", + "tenderdash-proto-compiler 1.2.1+1.3.0", + "time", + "tonic", +] + [[package]] name = "tenderdash-proto" version = "1.2.1+1.3.0" @@ -4923,11 +5116,25 @@ dependencies = [ "prost", "serde", "subtle-encoding", - "tenderdash-proto-compiler", + "tenderdash-proto-compiler 1.2.1+1.3.0 (git+https://github.com/dashpay/rs-tenderdash-abci?tag=v1.2.1%2B1.3.0)", "time", "tonic", ] +[[package]] +name = "tenderdash-proto-compiler" +version = "1.2.1+1.3.0" +dependencies = [ + "fs_extra", + "prost-build", + "regex", + "tempfile", + "tonic-build", + "ureq", + "walkdir", + "zip 2.2.0", +] + [[package]] name = "tenderdash-proto-compiler" version = "1.2.1+1.3.0" @@ -5298,6 +5505,31 @@ dependencies = [ "syn 2.0.75", ] +[[package]] +name = "tonic-web-wasm-client" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef5ca6e7bdd0042c440d36b6df97c1436f1d45871ce18298091f114004b1beb4" +dependencies = [ + "base64 0.22.1", + "byteorder", + "bytes", + "futures-util", + "http", + "http-body", + "http-body-util", + "httparse", + "js-sys", + "pin-project", + "thiserror", + "tonic", + "tower-service", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-streams", + "web-sys", +] + [[package]] name = "tower" version = "0.4.13" @@ -5554,6 +5786,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" +[[package]] +name = "value-bag" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ef4c4aa54d5d05a279399bfa921ec387b7aba77caf7a682ae8d86785b8fdad2" + [[package]] name = "vcpkg" version = "0.2.15" @@ -5746,6 +5984,28 @@ dependencies = [ "web-sys", ] +[[package]] +name = "wasm-sdk" +version = "0.1.0" +dependencies = [ + "dash-sdk", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-streams" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e072d4e72f700fb3443d8fe94a39315df013eef1104903cdb0a2abd322bbecd" +dependencies = [ + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + [[package]] name = "web-sys" version = "0.3.76" diff --git a/Cargo.toml b/Cargo.toml index 02295b6b475..88767db3719 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,7 +28,7 @@ members = [ "packages/simple-signer", "packages/rs-json-schema-compatibility-validator", "packages/check-features", - "packages/wallet-utils-contract", + "packages/wallet-utils-contract", "packages/wasm-sdk", ] [workspace.package] diff --git a/packages/rs-dapi-client/Cargo.toml b/packages/rs-dapi-client/Cargo.toml index c6f32b443df..f3ad5aaa288 100644 --- a/packages/rs-dapi-client/Cargo.toml +++ b/packages/rs-dapi-client/Cargo.toml @@ -4,7 +4,8 @@ version = "1.7.0" edition = "2021" [features] -default = ["mocks", "offline-testing"] +# TODO we should not enable deps features in default +default = ["mocks", "offline-testing", "dapi-grpc/client", "backon/tokio-sleep"] mocks = [ "dep:sha2", "dep:hex", @@ -17,17 +18,34 @@ mocks = [ dump = ["mocks"] # skip tests that require connection to the platform; enabled by default offline-testing = [] +wasm = [ + "dapi-grpc/wasm", + "dapi-grpc/platform", + "dapi-grpc/core", + # "backon/gloo-timers-sleep", + # "backon/std-blocking-sleep", + "dep:async-std", + "dep:tonic-web-wasm-client", + "dep:http", + "getrandom/js", +] [dependencies] -backon = { version = "1.2", features = ["tokio-sleep"] } +backon = { version = "1.3", default-features = false } + dapi-grpc = { path = "../dapi-grpc", features = [ "core", "platform", - "client", ], default-features = false } futures = "0.3.28" +http = { version = "1.1.0", default-features = false, optional = true } http-serde = { version = "2.1", optional = true } -rand = { version = "0.8.5", features = ["small_rng"] } +getrandom = { version = "0.2", optional = true } +tonic-web-wasm-client = { version = "0.6.0", optional = true } +rand = { version = "0.8.5", features = [ + "small_rng", + "getrandom", +], default-features = false } thiserror = "1.0.64" tracing = "0.1.40" tokio = { version = "1.40", default-features = false } @@ -37,6 +55,6 @@ lru = { version = "0.12.3" } serde = { version = "1.0.197", optional = true, features = ["derive"] } serde_json = { version = "1.0.120", optional = true } chrono = { version = "0.4.38", features = ["serde"] } - +async-std = { version = "1.13", optional = true } [dev-dependencies] tokio = { version = "1.40", features = ["macros"] } diff --git a/packages/rs-dapi-client/src/address_list.rs b/packages/rs-dapi-client/src/address_list.rs index 2f59b22c3bc..eeea7be8a22 100644 --- a/packages/rs-dapi-client/src/address_list.rs +++ b/packages/rs-dapi-client/src/address_list.rs @@ -1,7 +1,7 @@ //! Subsystem to manage DAPI nodes. +use crate::Uri; use chrono::Utc; -use dapi_grpc::tonic::transport::Uri; use rand::{rngs::SmallRng, seq::IteratorRandom, SeedableRng}; use std::collections::hash_map::Entry; use std::collections::HashMap; diff --git a/packages/rs-dapi-client/src/connection_pool.rs b/packages/rs-dapi-client/src/connection_pool.rs index 97dd991d509..99effb4ac76 100644 --- a/packages/rs-dapi-client/src/connection_pool.rs +++ b/packages/rs-dapi-client/src/connection_pool.rs @@ -3,12 +3,12 @@ use std::{ sync::{Arc, Mutex}, }; -use dapi_grpc::tonic::transport::Uri; use lru::LruCache; use crate::{ request_settings::AppliedRequestSettings, transport::{CoreGrpcClient, PlatformGrpcClient}, + Uri, }; /// ConnectionPool represents pool of connections to DAPI nodes. diff --git a/packages/rs-dapi-client/src/dapi_client.rs b/packages/rs-dapi-client/src/dapi_client.rs index 126d820e1ca..1ff986b3896 100644 --- a/packages/rs-dapi-client/src/dapi_client.rs +++ b/packages/rs-dapi-client/src/dapi_client.rs @@ -3,6 +3,7 @@ use backon::{ConstantBuilder, Retryable}; use dapi_grpc::mock::Mockable; use dapi_grpc::tonic::async_trait; +#[cfg(not(feature = "wasm"))] use dapi_grpc::tonic::transport::Certificate; use std::fmt::{Debug, Display}; use std::sync::atomic::AtomicUsize; @@ -13,7 +14,7 @@ use tracing::Instrument; use crate::address_list::AddressListError; use crate::connection_pool::ConnectionPool; use crate::request_settings::AppliedRequestSettings; -use crate::transport::TransportError; +use crate::transport::{self, TransportError}; use crate::{ transport::{TransportClient, TransportRequest}, AddressList, CanRetry, DapiRequestExecutor, ExecutionError, ExecutionResponse, ExecutionResult, @@ -77,6 +78,7 @@ pub struct DapiClient { address_list: AddressList, settings: RequestSettings, pool: ConnectionPool, + #[cfg(not(feature = "wasm"))] /// Certificate Authority certificate to use for verifying the server's certificate. pub ca_certificate: Option, #[cfg(feature = "dump")] @@ -95,6 +97,7 @@ impl DapiClient { pool: ConnectionPool::new(address_count), #[cfg(feature = "dump")] dump_dir: None, + #[cfg(not(feature = "wasm"))] ca_certificate: None, } } @@ -107,6 +110,7 @@ impl DapiClient { /// /// # Returns /// [DapiClient] with CA certificate set. + #[cfg(not(feature = "wasm"))] pub fn with_ca_certificate(mut self, ca_cert: Certificate) -> Self { self.ca_certificate = Some(ca_cert); @@ -200,8 +204,9 @@ impl DapiRequestExecutor for DapiClient { .settings .override_by(R::SETTINGS_OVERRIDES) .override_by(settings) - .finalize() - .with_ca_certificate(self.ca_certificate.clone()); + .finalize(); + #[cfg(not(feature = "wasm"))] + let applied_settings = applied_settings.with_ca_certificate(self.ca_certificate.clone()); // Setup retry policy: let retry_settings = ConstantBuilder::default() @@ -310,10 +315,13 @@ impl DapiRequestExecutor for DapiClient { } }; + let sleeper = transport::channel_impl::BackonSleeper::default(); + // Start the routine with retry policy applied: // We allow let_and_return because `result` is used later if dump feature is enabled let result = routine .retry(retry_settings) + .sleep(sleeper) .notify(|error, duration| { let retries_counter = Arc::clone(&retries_counter_arc); retries_counter.fetch_add(1, std::sync::atomic::Ordering::Relaxed); diff --git a/packages/rs-dapi-client/src/executor.rs b/packages/rs-dapi-client/src/executor.rs index 0afb8f57054..c87b2f9336b 100644 --- a/packages/rs-dapi-client/src/executor.rs +++ b/packages/rs-dapi-client/src/executor.rs @@ -34,7 +34,7 @@ pub trait InnerInto { } /// Error happened during request execution. -#[derive(Debug, Clone, thiserror::Error, Eq, PartialEq)] +#[derive(Debug, Clone, thiserror::Error, Eq)] #[error("{inner}")] pub struct ExecutionError { /// The cause of error @@ -45,6 +45,12 @@ pub struct ExecutionError { pub address: Option
, } +impl PartialEq for ExecutionError { + fn eq(&self, other: &Self) -> bool { + self.inner == other.inner && self.retries == other.retries && self.address == other.address + } +} + impl InnerInto> for ExecutionError where F: Into, diff --git a/packages/rs-dapi-client/src/lib.rs b/packages/rs-dapi-client/src/lib.rs index e820a714a0e..9603bb8e492 100644 --- a/packages/rs-dapi-client/src/lib.rs +++ b/packages/rs-dapi-client/src/lib.rs @@ -19,6 +19,8 @@ pub use address_list::AddressListError; pub use address_list::AddressStatus; pub use connection_pool::ConnectionPool; pub use dapi_client::{update_address_ban_status, DapiClient, DapiClientError}; +#[cfg(not(feature = "wasm"))] +pub use dapi_grpc::tonic::transport::http; #[cfg(feature = "dump")] pub use dump::DumpData; pub use executor::{ @@ -26,6 +28,11 @@ pub use executor::{ WrapToExecutionResult, }; use futures::{future::BoxFuture, FutureExt}; +#[cfg(feature = "wasm")] +pub use http::Uri; +#[cfg(not(feature = "wasm"))] +pub use http_serde::http::Uri; + pub use request_settings::RequestSettings; /// A DAPI request could be executed with an initialized [DapiClient]. diff --git a/packages/rs-dapi-client/src/request_settings.rs b/packages/rs-dapi-client/src/request_settings.rs index df89112322b..0767e15337a 100644 --- a/packages/rs-dapi-client/src/request_settings.rs +++ b/packages/rs-dapi-client/src/request_settings.rs @@ -1,5 +1,6 @@ //! DAPI client request settings processing. +#[cfg(not(feature = "wasm"))] use dapi_grpc::tonic::transport::Certificate; use std::time::Duration; @@ -65,6 +66,7 @@ impl RequestSettings { ban_failed_address: self .ban_failed_address .unwrap_or(DEFAULT_BAN_FAILED_ADDRESS), + #[cfg(not(feature = "wasm"))] ca_certificate: None, } } @@ -82,12 +84,14 @@ pub struct AppliedRequestSettings { /// Ban DAPI address if node not responded or responded with error. pub ban_failed_address: bool, /// Certificate Authority certificate to use for verifying the server's certificate. + #[cfg(not(feature = "wasm"))] pub ca_certificate: Option, } impl AppliedRequestSettings { /// Use provided CA certificate for verifying the server's certificate. /// /// If set to None, the system's default CA certificates will be used. + #[cfg(not(feature = "wasm"))] pub fn with_ca_certificate(mut self, ca_cert: Option) -> Self { self.ca_certificate = ca_cert; self diff --git a/packages/rs-dapi-client/src/transport.rs b/packages/rs-dapi-client/src/transport.rs index 26c394ff034..9a06459e4c6 100644 --- a/packages/rs-dapi-client/src/transport.rs +++ b/packages/rs-dapi-client/src/transport.rs @@ -1,16 +1,23 @@ //! Transport options that DAPI requests use under the hood. pub(crate) mod grpc; +#[cfg(not(feature = "wasm"))] +pub(crate) mod tonic_channel; +#[cfg(feature = "wasm")] +pub(crate) mod wasm_channel; use crate::connection_pool::ConnectionPool; pub use crate::request_settings::AppliedRequestSettings; -use crate::{CanRetry, RequestSettings}; +use crate::{CanRetry, RequestSettings, Uri}; +pub use channel_impl::{BackonSleeper, CoreGrpcClient, PlatformGrpcClient}; use dapi_grpc::mock::Mockable; -use dapi_grpc::tonic::transport::Uri; pub use futures::future::BoxFuture; -pub use grpc::{CoreGrpcClient, PlatformGrpcClient}; use std::any; use std::fmt::Debug; +#[cfg(not(feature = "wasm"))] +pub(crate) use tonic_channel as channel_impl; +#[cfg(feature = "wasm")] +pub(crate) use wasm_channel as channel_impl; /// Generic transport layer request. /// Requires [Clone] as could be retried and a client in general consumes a request. diff --git a/packages/rs-dapi-client/src/transport/grpc.rs b/packages/rs-dapi-client/src/transport/grpc.rs index 77b98acf812..c4ffc4f7cbe 100644 --- a/packages/rs-dapi-client/src/transport/grpc.rs +++ b/packages/rs-dapi-client/src/transport/grpc.rs @@ -2,52 +2,19 @@ use std::time::Duration; +#[cfg(not(feature = "wasm"))] +use super::tonic_channel::create_channel; +#[cfg(feature = "wasm")] +use super::wasm_channel::create_channel; use super::{CanRetry, TransportClient, TransportError, TransportRequest}; +use super::{CoreGrpcClient, PlatformGrpcClient}; use crate::connection_pool::{ConnectionPool, PoolPrefix}; -use crate::{request_settings::AppliedRequestSettings, RequestSettings}; -use dapi_grpc::core::v0::core_client::CoreClient; +use crate::{request_settings::AppliedRequestSettings, RequestSettings, Uri}; use dapi_grpc::core::v0::{self as core_proto}; -use dapi_grpc::platform::v0::{self as platform_proto, platform_client::PlatformClient}; -use dapi_grpc::tonic::transport::{Certificate, ClientTlsConfig, Uri}; -use dapi_grpc::tonic::Streaming; -use dapi_grpc::tonic::{transport::Channel, IntoRequest}; +use dapi_grpc::platform::v0::{self as platform_proto}; +use dapi_grpc::tonic::{IntoRequest, Streaming}; use futures::{future::BoxFuture, FutureExt, TryFutureExt}; -/// Platform Client using gRPC transport. -pub type PlatformGrpcClient = PlatformClient; -/// Core Client using gRPC transport. -pub type CoreGrpcClient = CoreClient; - -fn create_channel( - uri: Uri, - settings: Option<&AppliedRequestSettings>, -) -> Result { - let host = uri.host().expect("Failed to get host from URI").to_string(); - - let mut builder = Channel::builder(uri); - let mut tls_config = ClientTlsConfig::new() - .with_native_roots() - .with_webpki_roots() - .assume_http2(true); - - if let Some(settings) = settings { - if let Some(timeout) = settings.connect_timeout { - builder = builder.connect_timeout(timeout); - } - - if let Some(pem) = settings.ca_certificate.as_ref() { - let cert = Certificate::from_pem(pem); - tls_config = tls_config.ca_certificate(cert).domain_name(host); - }; - } - - builder = builder - .tls_config(tls_config) - .expect("Failed to set TLS config"); - - Ok(builder.connect_lazy()) -} - impl TransportClient for PlatformGrpcClient { fn with_uri(uri: Uri, pool: &ConnectionPool) -> Result { Ok(pool diff --git a/packages/rs-dapi-client/src/transport/tonic_channel.rs b/packages/rs-dapi-client/src/transport/tonic_channel.rs new file mode 100644 index 00000000000..f1e9de97038 --- /dev/null +++ b/packages/rs-dapi-client/src/transport/tonic_channel.rs @@ -0,0 +1,57 @@ +use std::time::Duration; + +use super::{CanRetry, TransportClient, TransportError, TransportRequest}; +use crate::connection_pool::{ConnectionPool, PoolPrefix}; +use crate::{request_settings::AppliedRequestSettings, RequestSettings, Uri}; +use dapi_grpc::core::v0::core_client::CoreClient; +use dapi_grpc::core::v0::{self as core_proto}; +use dapi_grpc::platform::v0::{self as platform_proto, platform_client::PlatformClient}; +use dapi_grpc::tonic::transport::{Certificate, Channel, ClientTlsConfig, Uri}; +use dapi_grpc::tonic::{IntoRequest, Streaming}; +use futures::{future::BoxFuture, FutureExt, TryFutureExt}; + +/// Platform Client using gRPC transport. +pub type PlatformGrpcClient = PlatformClient; +/// Core Client using gRPC transport. +pub type CoreGrpcClient = CoreClient; + +/// backon::Sleeper +#[derive(Default, Clone, Debug)] +pub(crate) struct Sleeper(backon::TokioSleeper); + +impl backon::Sleeper for Sleeper { + type Sleep = backon::TokioSleeper::Sleep; + fn sleep(&self, dur: Duration) -> Self::Sleep { + self.0.sleep(dur) + } +} + +fn create_channel( + uri: Uri, + settings: Option<&AppliedRequestSettings>, +) -> Result { + let host = uri.host().expect("Failed to get host from URI").to_string(); + + let mut builder = Channel::builder(uri); + let mut tls_config = ClientTlsConfig::new() + .with_native_roots() + .with_webpki_roots() + .assume_http2(true); + + if let Some(settings) = settings { + if let Some(timeout) = settings.connect_timeout { + builder = builder.connect_timeout(timeout); + } + + if let Some(pem) = settings.ca_certificate.as_ref() { + let cert = Certificate::from_pem(pem); + tls_config = tls_config.ca_certificate(cert).domain_name(host); + }; + } + + builder = builder + .tls_config(tls_config) + .expect("Failed to set TLS config"); + + Ok(builder.connect_lazy()) +} diff --git a/packages/rs-dapi-client/src/transport/wasm_channel.rs b/packages/rs-dapi-client/src/transport/wasm_channel.rs new file mode 100644 index 00000000000..9315558ff48 --- /dev/null +++ b/packages/rs-dapi-client/src/transport/wasm_channel.rs @@ -0,0 +1,67 @@ +//! Listing of gRPC requests used in DAPI. + +use std::thread::sleep; +use std::time::Duration; + +use super::TransportError; +use crate::{request_settings::AppliedRequestSettings, Uri}; +use dapi_grpc::core::v0::core_client::CoreClient; + +use dapi_grpc::platform::v0::platform_client::PlatformClient; +use dapi_grpc::tonic::{self as tonic}; +use futures::FutureExt; +// use tonic_web_wasm_client::Client as WasmClient; + +#[derive(Clone, Debug)] +// TODO impleent WasmClient using `tonic_web_wasm_client::Client` +pub struct WasmClient; + +impl tonic::client::GrpcService for WasmClient { + type ResponseBody = tonic::body::BoxBody; + fn call(&mut self, request: http::Request) -> Self::Future { + unimplemented!() + } + fn poll_ready( + &mut self, + cx: &mut std::task::Context<'_>, + ) -> std::task::Poll> { + unimplemented!() + } + type Error = tonic::Status; + type Future = std::pin::Pin< + Box< + dyn std::future::Future< + Output = Result, Self::Error>, + > + Send, + >, + >; +} + +/// Platform Client using gRPC transport. +pub type PlatformGrpcClient = PlatformClient; +/// Core Client using gRPC transport. +pub type CoreGrpcClient = CoreClient; + +type S = futures::future::BoxFuture<'static, ()>; +/// backon::Sleeper +#[derive(Default, Clone, Debug)] +pub struct BackonSleeper {} +// TODO move somewhere else +impl backon::Sleeper for BackonSleeper { + type Sleep = S; + fn sleep(&self, dur: Duration) -> Self::Sleep { + // TODO: blocking sleep is not the best solution + sleep(dur); + async {}.boxed() + } +} + +pub(super) fn create_channel( + uri: Uri, + settings: Option<&AppliedRequestSettings>, +) -> Result { + // let host = uri.host().expect("Failed to get host from URI").to_string(); + // let client = tonic_web_wasm_client::Client::new(uri.to_string()); + + Ok(WasmClient {}) +} diff --git a/packages/rs-dpp/src/balances/credits.rs b/packages/rs-dpp/src/balances/credits.rs index d0f9e2805b9..8db94c32386 100644 --- a/packages/rs-dpp/src/balances/credits.rs +++ b/packages/rs-dpp/src/balances/credits.rs @@ -16,22 +16,18 @@ use std::convert::TryFrom; pub type Duffs = u64; /// Credits type - pub type Credits = u64; /// Signed Credits type is used for internal computations and total credits /// balance verification - pub type SignedCredits = i64; /// Maximum value of credits - pub const MAX_CREDITS: Credits = 9223372036854775807 as Credits; //i64 Max pub const CREDITS_PER_DUFF: Credits = 1000; /// Trait for signed and unsigned credits - pub trait Creditable { /// Convert unsigned credit to singed fn to_signed(&self) -> Result; diff --git a/packages/rs-drive-abci/Cargo.toml b/packages/rs-drive-abci/Cargo.toml index d637b3225d0..b722827034a 100644 --- a/packages/rs-drive-abci/Cargo.toml +++ b/packages/rs-drive-abci/Cargo.toml @@ -39,7 +39,10 @@ tracing = { version = "0.1.37", default-features = false, features = [] } clap = { version = "4.4.10", features = ["derive"] } envy = { version = "0.4.2" } dotenvy = { version = "0.15.7" } -dapi-grpc = { path = "../dapi-grpc", features = ["server"] } +dapi-grpc = { path = "../dapi-grpc", default-features = false, features = [ + "server", + "platform", +] } tracing-subscriber = { version = "0.3.16", default-features = false, features = [ "env-filter", "ansi", diff --git a/packages/rs-drive-proof-verifier/Cargo.toml b/packages/rs-drive-proof-verifier/Cargo.toml index e19a9ced1b5..632f87a8170 100644 --- a/packages/rs-drive-proof-verifier/Cargo.toml +++ b/packages/rs-drive-proof-verifier/Cargo.toml @@ -21,7 +21,10 @@ mocks = [ [dependencies] thiserror = { version = "1.0.63" } -dapi-grpc = { path = "../dapi-grpc" } +dapi-grpc = { path = "../dapi-grpc", default-features = false, features = [ + "platform", +] } + drive = { path = "../rs-drive", default-features = false, features = [ "verify", ] } diff --git a/packages/rs-sdk/Cargo.toml b/packages/rs-sdk/Cargo.toml index 1d781bfa9fa..a252e0d1ac2 100644 --- a/packages/rs-sdk/Cargo.toml +++ b/packages/rs-sdk/Cargo.toml @@ -11,17 +11,19 @@ chrono = { version = "0.4.38" } dpp = { path = "../rs-dpp", default-features = false, features = [ "dash-sdk-features", ] } -dapi-grpc = { path = "../dapi-grpc" } + +dapi-grpc = { path = "../dapi-grpc", default-features = false } rs-dapi-client = { path = "../rs-dapi-client", default-features = false } drive = { path = "../rs-drive", default-features = false, features = [ "verify", ] } + drive-proof-verifier = { path = "../rs-drive-proof-verifier" } dapi-grpc-macros = { path = "../rs-dapi-grpc-macros" } http = { version = "1.1" } rustls-pemfile = { version = "2.0.0" } thiserror = "1.0.64" -tokio = { version = "1.40", features = ["macros", "rt-multi-thread"] } +tokio = { version = "1.40", features = ["macros", "time"] } tokio-util = { version = "0.7.12" } async-trait = { version = "0.1.83" } ciborium = { git = "https://github.com/qrayven/ciborium", branch = "feat-ser-null-as-undefined" } @@ -42,8 +44,8 @@ bip37-bloom-filter = { git = "https://github.com/dashpay/rs-bip37-bloom-filter", zeroize = { version = "1.8", features = ["derive"] } [dev-dependencies] +rs-dapi-client = { path = "../rs-dapi-client" } tokio = { version = "1.40", features = ["macros", "rt-multi-thread"] } -rs-dapi-client = { path = "../rs-dapi-client", features = ["mocks"] } base64 = { version = "0.22.1" } tracing-subscriber = { version = "0.3.18", features = ["env-filter"] } dpp = { path = "../rs-dpp", features = [ @@ -54,11 +56,19 @@ dpp = { path = "../rs-dpp", features = [ data-contracts = { path = "../data-contracts" } tokio-test = { version = "0.4.4" } clap = { version = "4.5.4", features = ["derive"] } -sanitize-filename = { version = "0.5.0" } +sanitize-filename = { version = "0.6.0" } test-case = { version = "3.3.1" } [features] -default = ["mocks", "offline-testing"] +# TODO make a way to enable "tokio/rt-multi-thread" if someone uses --no-default-features +default = [ + "mocks", + "offline-testing", + "dapi-grpc/client", + "tokio/rt-multi-thread", +] + +wasm = ["dapi-grpc/wasm", "rs-dapi-client/wasm"] mocks = [ "dep:serde", @@ -106,3 +116,6 @@ system-data-contracts = ["dpp/data-contracts"] name = "read_contract" required-features = ["mocks"] + +[lib] +crate-type = ["cdylib", "rlib"] diff --git a/packages/rs-sdk/src/platform/transition/broadcast_identity.rs b/packages/rs-sdk/src/platform/transition/broadcast_identity.rs index 5bce4205cfe..f92bd77def4 100644 --- a/packages/rs-sdk/src/platform/transition/broadcast_identity.rs +++ b/packages/rs-sdk/src/platform/transition/broadcast_identity.rs @@ -10,6 +10,7 @@ use std::fmt::Debug; use dapi_grpc::platform::v0::{self as proto, BroadcastStateTransitionRequest}; use dpp::dashcore::PrivateKey; use dpp::identity::signer::Signer; +#[cfg(not(feature = "wasm"))] use dpp::native_bls::NativeBlsModule; use dpp::prelude::{AssetLockProof, Identity}; use dpp::state_transition::identity_create_transition::methods::IdentityCreateTransitionMethodsV0; @@ -104,16 +105,22 @@ impl BroadcastRequestForNewIdentity Result<(StateTransition, BroadcastStateTransitionRequest), Error> { - let identity_create_transition = IdentityCreateTransition::try_from_identity_with_signer( - self, - asset_lock_proof, - asset_lock_proof_private_key.inner.as_ref(), - signer, - &NativeBlsModule, - 0, - platform_version, - )?; - let request = identity_create_transition.broadcast_request_for_state_transition()?; - Ok((identity_create_transition, request)) + #[cfg(feature = "wasm")] + unimplemented!("NativeBlsModule not implemented for wasm32"); + #[cfg(not(feature = "wasm"))] + { + let identity_create_transition = + IdentityCreateTransition::try_from_identity_with_signer( + self, + asset_lock_proof, + asset_lock_proof_private_key.inner.as_ref(), + signer, + &NativeBlsModule, + 0, + platform_version, + )?; + let request = identity_create_transition.broadcast_request_for_state_transition()?; + Ok((identity_create_transition, request)) + } } } diff --git a/packages/rs-sdk/src/sdk.rs b/packages/rs-sdk/src/sdk.rs index 64a5db66457..6cc6d1deef5 100644 --- a/packages/rs-sdk/src/sdk.rs +++ b/packages/rs-sdk/src/sdk.rs @@ -10,6 +10,7 @@ use crate::platform::{Fetch, Identifier}; use arc_swap::{ArcSwapAny, ArcSwapOption}; use dapi_grpc::mock::Mockable; use dapi_grpc::platform::v0::{Proof, ResponseMetadata}; +#[cfg(not(feature = "wasm"))] use dapi_grpc::tonic::transport::Certificate; use dpp::bincode; use dpp::bincode::error::DecodeError; @@ -753,6 +754,7 @@ pub struct SdkBuilder { pub(crate) cancel_token: CancellationToken, /// CA certificate to use for TLS connections. + #[cfg(not(feature = "wasm"))] ca_certificate: Option, } @@ -784,7 +786,7 @@ impl Default for SdkBuilder { cancel_token: CancellationToken::new(), version: PlatformVersion::latest(), - + #[cfg(not(feature = "wasm"))] ca_certificate: None, #[cfg(feature = "mocks")] @@ -841,6 +843,7 @@ impl SdkBuilder { /// Used mainly for testing purposes and local networks. /// /// If not set, uses standard system CA certificates. + #[cfg(not(feature = "wasm"))] pub fn with_ca_certificate(mut self, pem_certificate: Certificate) -> Self { self.ca_certificate = Some(pem_certificate); self @@ -850,6 +853,7 @@ impl SdkBuilder { /// /// This is a convenience method that reads the certificate from a file and sets it using /// [SdkBuilder::with_ca_certificate()]. + #[cfg(not(feature = "wasm"))] pub fn with_ca_certificate_file( self, certificate_file_path: impl AsRef, @@ -1003,7 +1007,9 @@ impl SdkBuilder { let sdk= match self.addresses { // non-mock mode Some(addresses) => { + #[allow(unused_mut)] // needs to be mutable for features other than wasm let mut dapi = DapiClient::new(addresses, dapi_client_settings); + #[cfg(not(feature = "wasm"))] if let Some(pem) = self.ca_certificate { dapi = dapi.with_ca_certificate(pem); } diff --git a/packages/rs-sdk/src/sync.rs b/packages/rs-sdk/src/sync.rs index 5f5d2666699..d0bf327501e 100644 --- a/packages/rs-sdk/src/sync.rs +++ b/packages/rs-sdk/src/sync.rs @@ -15,13 +15,14 @@ use std::{ future::Future, sync::{mpsc::SendError, Arc}, }; -use tokio::{runtime::TryCurrentError, sync::Mutex}; +use tokio::sync::Mutex; #[derive(Debug, thiserror::Error)] pub enum AsyncError { /// Not running inside tokio runtime + #[cfg(not(feature = "wasm"))] #[error("not running inside tokio runtime: {0}")] - NotInTokioRuntime(#[from] TryCurrentError), + NotInTokioRuntime(#[from] tokio::runtime::TryCurrentError), /// Cannot receive response from async function #[error("cannot receive response from async function: {0}")] @@ -61,6 +62,7 @@ impl From for crate::Error { /// /// Due to limitations of tokio runtime, we cannot use `tokio::runtime::Runtime::block_on` if we are already inside a tokio runtime. /// This function is a workaround for that limitation. +#[cfg(not(feature = "wasm"))] pub fn block_on(fut: F) -> Result where F: Future + Send + 'static, @@ -83,6 +85,15 @@ where Ok(resp) } +#[cfg(feature = "wasm")] +pub fn block_on(_fut: F) -> Result +where + F: Future + Send + 'static, + F::Output: Send, +{ + unimplemented!("block_on is not supported in wasm"); +} + /// Worker function that runs the provided future and sends the result back to the caller using oneshot channel. async fn worker( fut: F, @@ -229,6 +240,7 @@ where false } }) + .sleep(rs_dapi_client::transport::BackonSleeper::default()) .notify(|error, duration| { tracing::warn!(?duration, ?error, "request failed, retrying"); }) @@ -244,7 +256,6 @@ where mod test { use super::*; use derive_more::Display; - use http::Uri; use rs_dapi_client::ExecutionError; use std::{ future::Future, diff --git a/packages/wasm-sdk/Cargo.toml b/packages/wasm-sdk/Cargo.toml new file mode 100644 index 00000000000..f93a19c161a --- /dev/null +++ b/packages/wasm-sdk/Cargo.toml @@ -0,0 +1,31 @@ +[package] +name = "wasm-sdk" +version = "0.1.0" +edition = "2021" +rust-version.workspace = true +publish = false +[lib] +crate-type = ["cdylib"] + +[dependencies] +web-sys = { version = "0.3.4", features = [ + 'Document', + 'Element', + 'HtmlElement', + 'Node', + 'Window', +] } +wasm-bindgen = { version = "=0.2.99" } +# tenderdash-proto = { path = "../../../rs-tenderdash-abci/proto", default-features = false, features = [ +# "client", +# ] } +dash-sdk = { path = "../rs-sdk", default-features = false, features = ["wasm"] } +# tonic = { version = "*", features = ["transport"], default-features = false } +# client = [ +# "tonic/channel", FAIL +# "tonic/transport", FAIL +# "tonic/tls", +# "tonic/tls-roots", +# "tonic/tls-webpki-roots", +# "platform", +# ] diff --git a/packages/wasm-sdk/index.html b/packages/wasm-sdk/index.html new file mode 100644 index 00000000000..f8f2197595d --- /dev/null +++ b/packages/wasm-sdk/index.html @@ -0,0 +1,59 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/wasm-sdk/src/lib.rs b/packages/wasm-sdk/src/lib.rs new file mode 100644 index 00000000000..f2e774f8ddc --- /dev/null +++ b/packages/wasm-sdk/src/lib.rs @@ -0,0 +1,11 @@ +use wasm_bindgen::prelude::*; + +#[wasm_bindgen] +extern "C" { + fn alert(s: &str); +} + +#[wasm_bindgen] +pub fn greet(name: &str) { + alert(&format!("Hello, {}!", name)); +}