From 9f74dcf58cdbf5059cef15951355f1cfae3eb954 Mon Sep 17 00:00:00 2001 From: ozkanonur Date: Wed, 23 Aug 2023 13:49:14 +0300 Subject: [PATCH 01/48] implement stremaing infrastructure Signed-off-by: ozkanonur --- Cargo.lock | 14 ++ Cargo.toml | 17 +- mm2src/mm2_core/Cargo.toml | 3 +- mm2src/mm2_core/src/mm_ctx.rs | 4 + mm2src/mm2_event_stream/Cargo.toml | 14 ++ mm2src/mm2_event_stream/src/controller.rs | 196 ++++++++++++++++++++++ mm2src/mm2_event_stream/src/lib.rs | 19 +++ mm2src/mm2_main/Cargo.toml | 2 + mm2src/mm2_main/src/rpc.rs | 9 + mm2src/mm2_main/src/sse.rs | 47 ++++++ 10 files changed, 316 insertions(+), 9 deletions(-) create mode 100644 mm2src/mm2_event_stream/Cargo.toml create mode 100644 mm2src/mm2_event_stream/src/controller.rs create mode 100644 mm2src/mm2_event_stream/src/lib.rs create mode 100644 mm2src/mm2_main/src/sse.rs diff --git a/Cargo.lock b/Cargo.lock index 8bdd4d52cd..236fffa37a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4114,6 +4114,7 @@ dependencies = [ "gstuff", "hex 0.4.3", "lazy_static", + "mm2_event_stream", "mm2_metrics", "mm2_rpc", "primitives", @@ -4182,6 +4183,17 @@ dependencies = [ "web3", ] +[[package]] +name = "mm2_event_stream" +version = "0.1.0" +dependencies = [ + "async-stream", + "parking_lot 0.12.0", + "serde", + "serde_json", + "tokio", +] + [[package]] name = "mm2_git" version = "0.1.0" @@ -4237,6 +4249,7 @@ name = "mm2_main" version = "0.1.0" dependencies = [ "async-std", + "async-stream", "async-trait", "bitcrypto", "blake2", @@ -4277,6 +4290,7 @@ dependencies = [ "mm2_core", "mm2_db", "mm2_err_handle", + "mm2_event_stream", "mm2_gui_storage", "mm2_io", "mm2_metrics", diff --git a/Cargo.toml b/Cargo.toml index 7a92ac1426..7da3bcb1a2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,43 +1,44 @@ [workspace] members = [ + "mm2src/coins_activation", "mm2src/coins", "mm2src/coins/utxo_signer", - "mm2src/coins_activation", "mm2src/common/shared_ref_counter", "mm2src/crypto", "mm2src/db_common", "mm2src/derives/enum_from", - "mm2src/derives/ser_error", "mm2src/derives/ser_error_derive", + "mm2src/derives/ser_error", "mm2src/floodsub", "mm2src/gossipsub", - "mm2src/mm2_gui_storage", "mm2src/hw_common", "mm2src/mm2_bin_lib", - "mm2src/mm2_bitcoin/crypto", "mm2src/mm2_bitcoin/chain", + "mm2src/mm2_bitcoin/crypto", "mm2src/mm2_bitcoin/keys", - "mm2src/mm2_bitcoin/rpc", "mm2src/mm2_bitcoin/primitives", + "mm2src/mm2_bitcoin/rpc", "mm2src/mm2_bitcoin/script", - "mm2src/mm2_bitcoin/serialization", "mm2src/mm2_bitcoin/serialization_derive", + "mm2src/mm2_bitcoin/serialization", "mm2src/mm2_bitcoin/test_helpers", "mm2src/mm2_core", "mm2src/mm2_db", "mm2src/mm2_err_handle", "mm2src/mm2_eth", + "mm2src/mm2_event_stream", "mm2src/mm2_git", + "mm2src/mm2_gui_storage", "mm2src/mm2_io", "mm2src/mm2_libp2p", + "mm2src/mm2_main", "mm2src/mm2_metamask", "mm2src/mm2_metrics", - "mm2src/mm2_main", "mm2src/mm2_net", "mm2src/mm2_number", "mm2src/mm2_rpc", - "mm2src/rpc_task", "mm2src/mm2_test_helpers", + "mm2src/rpc_task", "mm2src/trezor", ] diff --git a/mm2src/mm2_core/Cargo.toml b/mm2src/mm2_core/Cargo.toml index b8e34b34e4..566d778b8b 100644 --- a/mm2src/mm2_core/Cargo.toml +++ b/mm2src/mm2_core/Cargo.toml @@ -7,8 +7,8 @@ edition = "2021" doctest = false [dependencies] -async-trait = "0.1" arrayref = "0.3" +async-trait = "0.1" cfg-if = "1.0" common = { path = "../common" } db_common = { path = "../db_common" } @@ -16,6 +16,7 @@ derive_more = "0.99" futures = { version = "0.3", package = "futures", features = ["compat", "async-await", "thread-pool"] } hex = "0.4.2" lazy_static = "1.4" +mm2_event_stream = { path = "../mm2_event_stream" } mm2_metrics = { path = "../mm2_metrics" } primitives = { path = "../mm2_bitcoin/primitives" } rand = { version = "0.7", features = ["std", "small_rng", "wasm-bindgen"] } diff --git a/mm2src/mm2_core/src/mm_ctx.rs b/mm2src/mm2_core/src/mm_ctx.rs index 3717b76606..49b570d21c 100644 --- a/mm2src/mm2_core/src/mm_ctx.rs +++ b/mm2src/mm2_core/src/mm_ctx.rs @@ -6,6 +6,7 @@ use common::log::{self, LogLevel, LogOnError, LogState}; use common::{cfg_native, cfg_wasm32, small_rng}; use gstuff::{try_s, Constructible, ERR, ERRL}; use lazy_static::lazy_static; +use mm2_event_stream::{controller::Controller, Event}; use mm2_metrics::{MetricsArc, MetricsOps}; use primitives::hash::H160; use rand::Rng; @@ -72,6 +73,8 @@ pub struct MmCtx { pub initialized: Constructible, /// True if the RPC HTTP server was started. pub rpc_started: Constructible, + /// Channels for continuously streaming data to clients via SSE. + pub stream_channel_controller: Controller, /// True if the MarketMaker instance needs to stop. pub stop: Constructible, /// Unique context identifier, allowing us to more easily pass the context through the FFI boundaries. @@ -133,6 +136,7 @@ impl MmCtx { metrics: MetricsArc::new(), initialized: Constructible::default(), rpc_started: Constructible::default(), + stream_channel_controller: Controller::new(), stop: Constructible::default(), ffi_handle: Constructible::default(), ordermatch_ctx: Mutex::new(None), diff --git a/mm2src/mm2_event_stream/Cargo.toml b/mm2src/mm2_event_stream/Cargo.toml new file mode 100644 index 0000000000..6a16a7829f --- /dev/null +++ b/mm2src/mm2_event_stream/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "mm2_event_stream" +version = "0.1.0" +edition = "2021" + +[dependencies] +async-stream = "0.3" +parking_lot = "0.12" +serde = { version = "1", features = ["derive", "rc"] } +serde_json = "1" +tokio = { version = "1", features = ["sync"] } + +[dev-dependencies] +tokio = { version = "1", features = ["sync", "macros", "time", "rt"] } diff --git a/mm2src/mm2_event_stream/src/controller.rs b/mm2src/mm2_event_stream/src/controller.rs new file mode 100644 index 0000000000..e5fa105966 --- /dev/null +++ b/mm2src/mm2_event_stream/src/controller.rs @@ -0,0 +1,196 @@ +use parking_lot::Mutex; +use std::{collections::HashMap, sync::Arc}; +use tokio::sync::mpsc::{self, Receiver, Sender}; + +type ChannelId = u64; + +/// Root controller of streaming channels +pub struct Controller(Arc>>); + +impl Clone for Controller { + fn clone(&self) -> Self { Self(Arc::clone(&self.0)) } +} + +/// Inner part of the controller +pub struct ChannelsInner { + last_id: u64, + channels: HashMap>, +} + +struct Channel { + tx: Sender>, +} + +/// guard to trace channels disconnection +pub struct ChannelGuard { + channel_id: ChannelId, + controller: Controller, +} + +/// Receiver to cleanup resources on `Drop` +pub struct GuardedReceiver { + rx: Receiver>, + #[allow(dead_code)] + guard: ChannelGuard, +} + +impl Controller { + /// Creates a new channels controller + pub fn new() -> Self { Default::default() } + + /// Creates a new channel and returns it's events receiver + pub fn create_channel(&mut self, concurrency: usize) -> GuardedReceiver { + let (tx, rx) = mpsc::channel::>(concurrency); + let channel = Channel { tx }; + + let mut inner = self.0.lock(); + let channel_id = inner.last_id.overflowing_add(1).0; + inner.channels.insert(channel_id, channel); + inner.last_id = channel_id; + + let guard = ChannelGuard::new(channel_id, self.clone()); + GuardedReceiver { rx, guard } + } + + /// Returns number of active channels + pub fn num_connections(&self) -> usize { self.0.lock().channels.len() } + + /// Broadcast message to all channels + pub async fn broadcast(&self, message: M) { + let msg = Arc::new(message); + for rx in self.all_senders() { + rx.send(Arc::clone(&msg)).await.ok(); + } + } + + /// Removes the channel from the controller + fn remove_channel(&mut self, channel_id: &ChannelId) { + let mut inner = self.0.lock(); + inner.channels.remove(channel_id); + } + + /// Returns all the active channels + fn all_senders(&self) -> Vec>> { self.0.lock().channels.values().map(|c| c.tx.clone()).collect() } +} + +impl Default for Controller { + fn default() -> Self { + let inner = ChannelsInner { + last_id: 0, + channels: HashMap::new(), + }; + Self(Arc::new(Mutex::new(inner))) + } +} + +impl ChannelGuard { + fn new(channel_id: ChannelId, controller: Controller) -> Self { Self { channel_id, controller } } +} + +impl Drop for ChannelGuard { + fn drop(&mut self) { self.controller.remove_channel(&self.channel_id); } +} + +impl GuardedReceiver { + /// Receives the next event from the channel + pub async fn recv(&mut self) -> Option> { self.rx.recv().await } +} + +#[cfg(test)] +mod tests { + use super::*; + use tokio::time::{sleep, Duration}; + + #[tokio::test] + async fn test_create_channel_and_broadcast() { + let mut controller = Controller::new(); + let mut guard_receiver = controller.create_channel(1); + + controller.broadcast("Message".to_string()).await; + + let received_msg = guard_receiver.recv().await.unwrap(); + assert_eq!(*received_msg, "Message".to_string()); + } + + #[tokio::test] + async fn test_multiple_channels_and_broadcast() { + let mut controller = Controller::new(); + + let mut receivers = Vec::new(); + for _ in 0..3 { + receivers.push(controller.create_channel(1)); + } + + controller.broadcast("Message".to_string()).await; + + for receiver in &mut receivers { + let received_msg = receiver.recv().await.unwrap(); + assert_eq!(*received_msg, "Message".to_string()); + } + } + + #[tokio::test] + async fn test_channel_cleanup_on_drop() { + let mut controller: Controller<()> = Controller::new(); + let guard_receiver = controller.create_channel(1); + + assert_eq!(controller.num_connections(), 1); + + drop(guard_receiver); + + sleep(Duration::from_millis(10)).await; // Give time for the drop to execute + + assert_eq!(controller.num_connections(), 0); + } + + #[tokio::test] + async fn test_broadcast_across_channels() { + let mut controller = Controller::new(); + + let mut receivers = Vec::new(); + for _ in 0..3 { + receivers.push(controller.create_channel(1)); + } + + controller.broadcast("Message".to_string()).await; + + for receiver in &mut receivers { + let received_msg = receiver.recv().await.unwrap(); + assert_eq!(*received_msg, "Message".to_string()); + } + } + + #[tokio::test] + async fn test_multiple_messages_and_drop() { + let mut controller = Controller::new(); + let mut guard_receiver = controller.create_channel(6); + + controller.broadcast("Message 1".to_string()).await; + controller.broadcast("Message 2".to_string()).await; + controller.broadcast("Message 3".to_string()).await; + controller.broadcast("Message 4".to_string()).await; + controller.broadcast("Message 5".to_string()).await; + controller.broadcast("Message 6".to_string()).await; + + let mut received_msgs = Vec::new(); + for _ in 0..6 { + let received_msg = guard_receiver.recv().await.unwrap(); + received_msgs.push(received_msg); + } + + assert_eq!(*received_msgs[0], "Message 1".to_string()); + assert_eq!(*received_msgs[1], "Message 2".to_string()); + assert_eq!(*received_msgs[2], "Message 3".to_string()); + assert_eq!(*received_msgs[3], "Message 4".to_string()); + assert_eq!(*received_msgs[4], "Message 5".to_string()); + assert_eq!(*received_msgs[5], "Message 6".to_string()); + + // Consume the GuardedReceiver to trigger drop and channel cleanup + drop(guard_receiver); + + // Sleep for a short time to allow cleanup to complete + sleep(Duration::from_millis(10)).await; + + assert_eq!(controller.num_connections(), 0); + } +} diff --git a/mm2src/mm2_event_stream/src/lib.rs b/mm2src/mm2_event_stream/src/lib.rs new file mode 100644 index 0000000000..23b7c9478f --- /dev/null +++ b/mm2src/mm2_event_stream/src/lib.rs @@ -0,0 +1,19 @@ +use serde::{Deserialize, Serialize}; + +/// multi-purpose/generic event type that can easily be used over the event streaming +#[derive(Debug, Deserialize, Serialize)] +pub struct Event { + _type: String, + message: String, +} + +impl Event { + pub fn new(event_type: String, message: String) -> Self { + Self { + _type: event_type, + message, + } + } +} + +pub mod controller; diff --git a/mm2src/mm2_main/Cargo.toml b/mm2src/mm2_main/Cargo.toml index f1258d1827..f97253ca12 100644 --- a/mm2src/mm2_main/Cargo.toml +++ b/mm2src/mm2_main/Cargo.toml @@ -24,6 +24,7 @@ default = [] [dependencies] async-std = { version = "1.5", features = ["unstable"] } async-trait = "0.1" +async-stream = "0.3" bitcrypto = { path = "../mm2_bitcoin/crypto" } blake2 = "0.10.6" bytes = "0.4" @@ -57,6 +58,7 @@ lazy_static = "1.4" libc = "0.2" mm2_core = { path = "../mm2_core" } mm2_err_handle = { path = "../mm2_err_handle" } +mm2_event_stream = { path = "../mm2_event_stream"} mm2_gui_storage = { path = "../mm2_gui_storage" } mm2_io = { path = "../mm2_io" } mm2-libp2p = { path = "../mm2_libp2p" } diff --git a/mm2src/mm2_main/src/rpc.rs b/mm2src/mm2_main/src/rpc.rs index 8ca80d5274..456f99be1e 100644 --- a/mm2src/mm2_main/src/rpc.rs +++ b/mm2src/mm2_main/src/rpc.rs @@ -21,6 +21,7 @@ // use crate::mm2::rpc::rate_limiter::RateLimitError; +use crate::mm2::rpc::sse::{handle_sse_events, SSE_ENDPOINT}; use common::log::{error, info}; use common::{err_to_rpc_json_string, err_tp_rpc_json, HttpStatusCode, APPLICATION_JSON}; use derive_more::Display; @@ -47,6 +48,7 @@ mod dispatcher_legacy; #[path = "rpc/lp_commands/lp_commands_legacy.rs"] pub mod lp_commands_legacy; #[path = "rpc/rate_limiter.rs"] mod rate_limiter; +mod sse; /// Lists the RPC method not requiring the "userpass" authentication. /// None is also public to skip auth and display proper error in case of method is missing @@ -301,6 +303,8 @@ async fn rpc_service(req: Request, ctx_h: u32, client: SocketAddr) -> Resp Response::from_parts(parts, Body::from(body_escaped)) } +// TODO: This should exclude TCP internals, as including them results in having to +// handle various protocols within this function. #[cfg(not(target_arch = "wasm32"))] pub extern "C" fn spawn_rpc(ctx_h: u32) { use common::now_sec; @@ -353,6 +357,11 @@ pub extern "C" fn spawn_rpc(ctx_h: u32) { let make_svc_fut = move |remote_addr: SocketAddr| async move { Ok::<_, Infallible>(service_fn(move |req: Request| async move { + if req.uri().path() == SSE_ENDPOINT { + let res = handle_sse_events(ctx_h).await?; + return Ok::<_, Infallible>(res); + } + let res = rpc_service(req, ctx_h, remote_addr).await; Ok::<_, Infallible>(res) })) diff --git a/mm2src/mm2_main/src/sse.rs b/mm2src/mm2_main/src/sse.rs new file mode 100644 index 0000000000..3678333d32 --- /dev/null +++ b/mm2src/mm2_main/src/sse.rs @@ -0,0 +1,47 @@ +// TODO: handle this module inside the `mm2_event_stream` crate. + +use hyper::{body::Bytes, Body, Response}; +use mm2_core::mm_ctx::MmArc; +use std::convert::Infallible; + +pub(crate) const SSE_ENDPOINT: &str = "/event-stream"; + +/// Handles broadcasted messages from `mm2_event_stream` continuously. +pub async fn handle_sse_events(ctx_h: u32) -> Result, Infallible> { + // TODO: Query events from request and only stream the requested ones. + + let ctx = match MmArc::from_ffi_handle(ctx_h) { + Ok(ctx) => ctx, + Err(err) => return handle_internal_error(err).await, + }; + + let mut channel_controller = ctx.stream_channel_controller.clone(); + let mut rx = channel_controller.create_channel(1); // TODO: read this from configuration + let body = Body::wrap_stream(async_stream::stream! { + while let Some(msg) = rx.recv().await { + let Ok(json) = serde_json::to_string(&msg) else { continue }; // TODO: This is not a good idea. Refactor the event type. + yield Ok::<_, hyper::Error>(Bytes::from(format!("data: {json} \n\n"))); + } + }); + + let response = Response::builder() + .status(200) + .header("Content-Type", "text/event-stream") + .header("Cache-Control", "no-cache") + .header("Access-Control-Allow-Origin", "*") // TODO: read this from configuration + .body(body); + + match response { + Ok(res) => Ok(res), + Err(err) => return handle_internal_error(err.to_string()).await, + } +} + +async fn handle_internal_error(message: String) -> Result, Infallible> { + let response = Response::builder() + .status(500) + .body(Body::from(message)) + .expect("Returning 500 should never fail."); + + Ok(response) +} From 8e688c18f363fc62118d68a28eb4adf2ff820e43 Mon Sep 17 00:00:00 2001 From: ozkanonur Date: Wed, 23 Aug 2023 13:49:41 +0300 Subject: [PATCH 02/48] create basic client for SSE testing Signed-off-by: ozkanonur --- examples/sse/index.html | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 examples/sse/index.html diff --git a/examples/sse/index.html b/examples/sse/index.html new file mode 100644 index 0000000000..1c17c4db01 --- /dev/null +++ b/examples/sse/index.html @@ -0,0 +1,26 @@ + + + + + +

Events

+
+ + + + + + \ No newline at end of file From 6c1998d46f4444327eb7ef05777043e7bd01d36e Mon Sep 17 00:00:00 2001 From: ozkanonur Date: Wed, 23 Aug 2023 13:58:52 +0300 Subject: [PATCH 03/48] update examples README Signed-off-by: ozkanonur --- examples/wasm/README.md | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/examples/wasm/README.md b/examples/wasm/README.md index 6f2faff136..30b3e1146e 100644 --- a/examples/wasm/README.md +++ b/examples/wasm/README.md @@ -1,4 +1,5 @@ -# AtomicDEX-API WASM example +# Examples +## komodo-defi-framework WASM example **wasm_build** is an example of using **MarketMaker2** in webpages via [WebAssembly](https://developer.mozilla.org/en-US/docs/WebAssembly) @@ -16,3 +17,19 @@ via [WebAssembly](https://developer.mozilla.org/en-US/docs/WebAssembly) Read more about [running a simple local HTTP server](https://developer.mozilla.org/en-US/docs/Learn/Common_questions/set_up_a_local_testing_server#running_a_simple_local_http_server) 3. Open webpage in your browser http://localhost:8000/wasm_build/index.html + +## Listening event-stream from komodo-defi-framework + +1. Sart komodo-defi-framework with event streaming activated +2. Change directory to `sse`. +3. Run a local HTTP server + - if you use Python 3, run: + ``` + python3 -m http.server 8000 + ``` + - if you use Python 2, run: + ``` + python -m SimpleHTTPServer 8000 + ``` + +You should now be able to observe events from the komodo-defi-framework through the SSE. \ No newline at end of file From 5ee822b28d72690ea361b1d8198bb557a24961ce Mon Sep 17 00:00:00 2001 From: ozkanonur Date: Wed, 23 Aug 2023 22:29:30 +0300 Subject: [PATCH 04/48] implement client-side event filtering Signed-off-by: ozkanonur --- mm2src/mm2_event_stream/src/lib.rs | 4 ++++ mm2src/mm2_main/src/rpc.rs | 2 +- mm2src/mm2_main/src/sse.rs | 25 ++++++++++++++++++++----- 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/mm2src/mm2_event_stream/src/lib.rs b/mm2src/mm2_event_stream/src/lib.rs index 23b7c9478f..b2fbfdee6a 100644 --- a/mm2src/mm2_event_stream/src/lib.rs +++ b/mm2src/mm2_event_stream/src/lib.rs @@ -14,6 +14,10 @@ impl Event { message, } } + + pub fn event_type(&self) -> &str { &self._type } + + pub fn message(&self) -> &str { &self.message } } pub mod controller; diff --git a/mm2src/mm2_main/src/rpc.rs b/mm2src/mm2_main/src/rpc.rs index 456f99be1e..5ade053771 100644 --- a/mm2src/mm2_main/src/rpc.rs +++ b/mm2src/mm2_main/src/rpc.rs @@ -358,7 +358,7 @@ pub extern "C" fn spawn_rpc(ctx_h: u32) { let make_svc_fut = move |remote_addr: SocketAddr| async move { Ok::<_, Infallible>(service_fn(move |req: Request| async move { if req.uri().path() == SSE_ENDPOINT { - let res = handle_sse_events(ctx_h).await?; + let res = handle_sse_events(req, ctx_h).await?; return Ok::<_, Infallible>(res); } diff --git a/mm2src/mm2_main/src/sse.rs b/mm2src/mm2_main/src/sse.rs index 3678333d32..4dfaeca5d6 100644 --- a/mm2src/mm2_main/src/sse.rs +++ b/mm2src/mm2_main/src/sse.rs @@ -1,26 +1,41 @@ // TODO: handle this module inside the `mm2_event_stream` crate. -use hyper::{body::Bytes, Body, Response}; +use hyper::{body::Bytes, Body, Request, Response}; use mm2_core::mm_ctx::MmArc; use std::convert::Infallible; pub(crate) const SSE_ENDPOINT: &str = "/event-stream"; /// Handles broadcasted messages from `mm2_event_stream` continuously. -pub async fn handle_sse_events(ctx_h: u32) -> Result, Infallible> { - // TODO: Query events from request and only stream the requested ones. +pub async fn handle_sse_events(request: Request, ctx_h: u32) -> Result, Infallible> { + fn get_filtered_events(request: Request) -> Vec { + let query = request.uri().query().unwrap_or(""); + let events_param = query + .split('&') + .find(|param| param.starts_with("filter=")) + .map(|param| param.trim_start_matches("filter=")) + .unwrap_or(""); + + events_param.split(',').map(|event| event.to_string()).collect() + } let ctx = match MmArc::from_ffi_handle(ctx_h) { Ok(ctx) => ctx, Err(err) => return handle_internal_error(err).await, }; + let filtered_events = get_filtered_events(request); + let mut channel_controller = ctx.stream_channel_controller.clone(); let mut rx = channel_controller.create_channel(1); // TODO: read this from configuration let body = Body::wrap_stream(async_stream::stream! { while let Some(msg) = rx.recv().await { - let Ok(json) = serde_json::to_string(&msg) else { continue }; // TODO: This is not a good idea. Refactor the event type. - yield Ok::<_, hyper::Error>(Bytes::from(format!("data: {json} \n\n"))); + // If there are no filtered events, that means we want to + // stream out all the events. + if filtered_events.is_empty() || filtered_events.contains(&msg.event_type().to_owned()) { + let Ok(json) = serde_json::to_string(&msg) else { continue }; // TODO: This is not a good idea. Refactor the event type. + yield Ok::<_, hyper::Error>(Bytes::from(format!("data: {json} \n\n"))); + } } }); From b8e997aa4eebe511c768b18cec3fcc17261dfe57 Mon Sep 17 00:00:00 2001 From: ozkanonur Date: Wed, 23 Aug 2023 22:38:35 +0300 Subject: [PATCH 05/48] add explanatory comments in sse module Signed-off-by: ozkanonur --- mm2src/mm2_main/src/sse.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mm2src/mm2_main/src/sse.rs b/mm2src/mm2_main/src/sse.rs index 4dfaeca5d6..68426b9dff 100644 --- a/mm2src/mm2_main/src/sse.rs +++ b/mm2src/mm2_main/src/sse.rs @@ -19,6 +19,8 @@ pub async fn handle_sse_events(request: Request, ctx_h: u32) -> Result ctx, Err(err) => return handle_internal_error(err).await, @@ -52,6 +54,7 @@ pub async fn handle_sse_events(request: Request, ctx_h: u32) -> Result Result, Infallible> { let response = Response::builder() .status(500) From 04df80c1c68aba1f2431029e7cffc1bfecce9d09 Mon Sep 17 00:00:00 2001 From: ozkanonur Date: Wed, 23 Aug 2023 22:44:44 +0300 Subject: [PATCH 06/48] update SSE client example documentation Signed-off-by: ozkanonur --- examples/sse/README.md | 14 ++++++++++++++ examples/sse/index.html | 2 +- examples/wasm/README.md | 21 ++------------------- 3 files changed, 17 insertions(+), 20 deletions(-) create mode 100644 examples/sse/README.md diff --git a/examples/sse/README.md b/examples/sse/README.md new file mode 100644 index 0000000000..b43c213d02 --- /dev/null +++ b/examples/sse/README.md @@ -0,0 +1,14 @@ +# Listening event-stream from komodo-defi-framework + +1. Start komodo-defi-framework with event streaming activated +2. Run a local HTTP server + - if you use Python 3, run: + ``` + python3 -m http.server 8000 + ``` + - if you use Python 2, run: + ``` + python -m SimpleHTTPServer 8000 + ``` + +You should now be able to observe events from the komodo-defi-framework through the SSE. diff --git a/examples/sse/index.html b/examples/sse/index.html index 1c17c4db01..c064b7068d 100644 --- a/examples/sse/index.html +++ b/examples/sse/index.html @@ -23,4 +23,4 @@

Events

- \ No newline at end of file + diff --git a/examples/wasm/README.md b/examples/wasm/README.md index 30b3e1146e..849ff63773 100644 --- a/examples/wasm/README.md +++ b/examples/wasm/README.md @@ -1,5 +1,4 @@ -# Examples -## komodo-defi-framework WASM example +# AtomicDEX-API WASM example **wasm_build** is an example of using **MarketMaker2** in webpages via [WebAssembly](https://developer.mozilla.org/en-US/docs/WebAssembly) @@ -16,20 +15,4 @@ via [WebAssembly](https://developer.mozilla.org/en-US/docs/WebAssembly) ``` Read more about [running a simple local HTTP server](https://developer.mozilla.org/en-US/docs/Learn/Common_questions/set_up_a_local_testing_server#running_a_simple_local_http_server) -3. Open webpage in your browser http://localhost:8000/wasm_build/index.html - -## Listening event-stream from komodo-defi-framework - -1. Sart komodo-defi-framework with event streaming activated -2. Change directory to `sse`. -3. Run a local HTTP server - - if you use Python 3, run: - ``` - python3 -m http.server 8000 - ``` - - if you use Python 2, run: - ``` - python -m SimpleHTTPServer 8000 - ``` - -You should now be able to observe events from the komodo-defi-framework through the SSE. \ No newline at end of file +3. Open webpage in your browser http://localhost:8000/wasm_build/index.html \ No newline at end of file From fae50e43d8fba51533b5c89e0ba8a3853382e785 Mon Sep 17 00:00:00 2001 From: ozkanonur Date: Wed, 23 Aug 2023 22:48:41 +0300 Subject: [PATCH 07/48] format wasm html example Signed-off-by: ozkanonur --- examples/wasm/index.html | 37 +++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/examples/wasm/index.html b/examples/wasm/index.html index bd19234020..b9243b9bf8 100644 --- a/examples/wasm/index.html +++ b/examples/wasm/index.html @@ -1,27 +1,32 @@ + MM2 example + -
- -
- -
- - -
-
- -
- -
- -
+
+ +
+ +
+ + +
+
+ +
+ +
+ +
- + + \ No newline at end of file From b8eca5e4963c2fe4f6490edcef0b9860b8691761 Mon Sep 17 00:00:00 2001 From: ozkanonur Date: Thu, 24 Aug 2023 14:58:15 +0300 Subject: [PATCH 08/48] stream network events Signed-off-by: ozkanonur --- Cargo.lock | 9 +++-- examples/sse/index.html | 2 +- mm2src/mm2_event_stream/Cargo.toml | 2 - mm2src/mm2_main/Cargo.toml | 2 - mm2src/mm2_main/src/lp_native_dex.rs | 13 +++++- mm2src/mm2_main/src/lp_network.rs | 35 ++-------------- mm2src/mm2_main/src/ordermatch_tests.rs | 2 +- mm2src/mm2_main/src/rpc.rs | 11 ++--- .../src/rpc/lp_commands/lp_commands_legacy.rs | 6 +-- mm2src/mm2_net/Cargo.toml | 21 ++++++---- mm2src/mm2_net/src/lib.rs | 3 ++ mm2src/mm2_net/src/network_event.rs | 37 +++++++++++++++++ mm2src/mm2_net/src/p2p.rs | 40 +++++++++++++++++++ .../src/sse.rs => mm2_net/src/sse_handler.rs} | 14 ++++--- 14 files changed, 132 insertions(+), 65 deletions(-) create mode 100644 mm2src/mm2_net/src/network_event.rs create mode 100644 mm2src/mm2_net/src/p2p.rs rename mm2src/{mm2_main/src/sse.rs => mm2_net/src/sse_handler.rs} (85%) diff --git a/Cargo.lock b/Cargo.lock index 236fffa37a..ec2adc5a6c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4187,10 +4187,8 @@ dependencies = [ name = "mm2_event_stream" version = "0.1.0" dependencies = [ - "async-stream", "parking_lot 0.12.0", "serde", - "serde_json", "tokio", ] @@ -4249,7 +4247,6 @@ name = "mm2_main" version = "0.1.0" dependencies = [ "async-std", - "async-stream", "async-trait", "bitcrypto", "blake2", @@ -4290,7 +4287,6 @@ dependencies = [ "mm2_core", "mm2_db", "mm2_err_handle", - "mm2_event_stream", "mm2_gui_storage", "mm2_io", "mm2_metrics", @@ -4383,6 +4379,7 @@ dependencies = [ name = "mm2_net" version = "0.1.0" dependencies = [ + "async-stream", "async-trait", "bytes 1.1.0", "cfg-if 1.0.0", @@ -4396,8 +4393,12 @@ dependencies = [ "hyper", "js-sys", "lazy_static", + "mm2-libp2p", "mm2_core", "mm2_err_handle", + "mm2_event_stream", + "mocktopus", + "parking_lot 0.12.0", "prost", "rand 0.7.3", "rustls 0.20.4", diff --git a/examples/sse/index.html b/examples/sse/index.html index c064b7068d..e780004ccb 100644 --- a/examples/sse/index.html +++ b/examples/sse/index.html @@ -13,7 +13,7 @@

Events

}); source.onmessage = function (event) { var currentDatetime = new Date().toLocaleString(); - var eventData = currentDatetime + ": " + event.data + "
"; + var eventData = currentDatetime + ": " + event.data + "
"; document.getElementById("result").insertAdjacentHTML("afterbegin", eventData); }; } else { diff --git a/mm2src/mm2_event_stream/Cargo.toml b/mm2src/mm2_event_stream/Cargo.toml index 6a16a7829f..8329355c96 100644 --- a/mm2src/mm2_event_stream/Cargo.toml +++ b/mm2src/mm2_event_stream/Cargo.toml @@ -4,10 +4,8 @@ version = "0.1.0" edition = "2021" [dependencies] -async-stream = "0.3" parking_lot = "0.12" serde = { version = "1", features = ["derive", "rc"] } -serde_json = "1" tokio = { version = "1", features = ["sync"] } [dev-dependencies] diff --git a/mm2src/mm2_main/Cargo.toml b/mm2src/mm2_main/Cargo.toml index f97253ca12..f1258d1827 100644 --- a/mm2src/mm2_main/Cargo.toml +++ b/mm2src/mm2_main/Cargo.toml @@ -24,7 +24,6 @@ default = [] [dependencies] async-std = { version = "1.5", features = ["unstable"] } async-trait = "0.1" -async-stream = "0.3" bitcrypto = { path = "../mm2_bitcoin/crypto" } blake2 = "0.10.6" bytes = "0.4" @@ -58,7 +57,6 @@ lazy_static = "1.4" libc = "0.2" mm2_core = { path = "../mm2_core" } mm2_err_handle = { path = "../mm2_err_handle" } -mm2_event_stream = { path = "../mm2_event_stream"} mm2_gui_storage = { path = "../mm2_gui_storage" } mm2_io = { path = "../mm2_io" } mm2-libp2p = { path = "../mm2_libp2p" } diff --git a/mm2src/mm2_main/src/lp_native_dex.rs b/mm2src/mm2_main/src/lp_native_dex.rs index d11a47a2ca..30da1d6b82 100644 --- a/mm2src/mm2_main/src/lp_native_dex.rs +++ b/mm2src/mm2_main/src/lp_native_dex.rs @@ -31,6 +31,7 @@ use mm2_err_handle::prelude::*; use mm2_libp2p::{spawn_gossipsub, AdexBehaviourError, NodeType, RelayAddress, RelayAddressError, SwarmRuntime, WssCerts}; use mm2_metrics::mm_gauge; +use mm2_net::p2p::P2PContext; use rpc_task::RpcTaskError; use serde_json::{self as json}; use std::fs; @@ -42,7 +43,7 @@ use std::time::Duration; #[cfg(not(target_arch = "wasm32"))] use crate::mm2::database::init_and_migrate_db; use crate::mm2::lp_message_service::{init_message_service, InitMessageServiceError}; -use crate::mm2::lp_network::{lp_network_ports, p2p_event_process_loop, NetIdError, P2PContext}; +use crate::mm2::lp_network::{lp_network_ports, p2p_event_process_loop, NetIdError}; use crate::mm2::lp_ordermatch::{broadcast_maker_orders_keep_alive_loop, clean_memory_loop, init_ordermatch_context, lp_ordermatch_loop, orders_kick_start, BalanceUpdateOrdermatchHandler, OrdermatchInitError}; @@ -52,6 +53,7 @@ use crate::mm2::rpc::spawn_rpc; cfg_native! { use mm2_io::fs::{ensure_dir_is_writable, ensure_file_is_writable}; use mm2_net::ip_addr::myipaddr; + use mm2_net::network_event::start_network_event_stream; use db_common::sqlite::rusqlite::Error as SqlError; } @@ -410,11 +412,18 @@ pub async fn lp_init_continue(ctx: MmArc) -> MmInitResult<()> { // an order and start new swap that might get started 2 times because of kick-start kick_start(ctx.clone()).await?; + #[cfg(not(target_arch = "wasm32"))] + { + // TODO: this should be configurable from MM2 the config + ctx.spawner().spawn(start_network_event_stream(ctx.clone())); + } + ctx.spawner().spawn(lp_ordermatch_loop(ctx.clone())); ctx.spawner().spawn(broadcast_maker_orders_keep_alive_loop(ctx.clone())); ctx.spawner().spawn(clean_memory_loop(ctx.weak())); + Ok(()) } @@ -442,11 +451,13 @@ pub async fn lp_init(ctx: MmArc, version: String, datetime: String) -> MmInitRes spawn_rpc(ctx_id); let ctx_c = ctx.clone(); + ctx.spawner().spawn(async move { if let Err(err) = ctx_c.init_metrics() { warn!("Couldn't initialize metrics system: {}", err); } }); + // In the mobile version we might depend on `lp_init` staying around until the context stops. loop { if ctx.is_stopping() { diff --git a/mm2src/mm2_main/src/lp_network.rs b/mm2src/mm2_main/src/lp_network.rs index 7616429bf0..b5b97a91ac 100644 --- a/mm2src/mm2_main/src/lp_network.rs +++ b/mm2src/mm2_main/src/lp_network.rs @@ -1,3 +1,5 @@ +// TODO: a lof of these implementations should be handled in `mm2_net` + /****************************************************************************** * Copyright © 2022 Atomic Private Limited and its contributors * * * @@ -27,17 +29,15 @@ use instant::Instant; use keys::KeyPair; use mm2_core::mm_ctx::{MmArc, MmWeak}; use mm2_err_handle::prelude::*; -use mm2_libp2p::atomicdex_behaviour::{AdexBehaviourCmd, AdexBehaviourEvent, AdexCmdTx, AdexEventRx, AdexResponse, +use mm2_libp2p::atomicdex_behaviour::{AdexBehaviourCmd, AdexBehaviourEvent, AdexEventRx, AdexResponse, AdexResponseChannel}; use mm2_libp2p::peers_exchange::PeerAddresses; use mm2_libp2p::{decode_message, encode_message, DecodingError, GossipsubMessage, Libp2pPublic, Libp2pSecpPublic, MessageId, NetworkPorts, PeerId, TopicHash, TOPIC_SEPARATOR}; use mm2_metrics::{mm_label, mm_timing}; -#[cfg(test)] use mocktopus::macros::*; -use parking_lot::Mutex as PaMutex; +use mm2_net::p2p::P2PContext; use serde::de; use std::net::ToSocketAddrs; -use std::sync::Arc; use crate::mm2::lp_ordermatch; use crate::mm2::{lp_stats, lp_swap}; @@ -78,33 +78,6 @@ pub enum P2PRequest { NetworkInfo(lp_stats::NetworkInfoRequest), } -pub struct P2PContext { - /// Using Mutex helps to prevent cloning which can actually result to channel being unbounded in case of using 1 tx clone per 1 message. - pub cmd_tx: PaMutex, -} - -#[cfg_attr(test, mockable)] -impl P2PContext { - pub fn new(cmd_tx: AdexCmdTx) -> Self { - P2PContext { - cmd_tx: PaMutex::new(cmd_tx), - } - } - - pub fn store_to_mm_arc(self, ctx: &MmArc) { *ctx.p2p_ctx.lock().unwrap() = Some(Arc::new(self)) } - - pub fn fetch_from_mm_arc(ctx: &MmArc) -> Arc { - ctx.p2p_ctx - .lock() - .unwrap() - .as_ref() - .unwrap() - .clone() - .downcast() - .unwrap() - } -} - pub async fn p2p_event_process_loop(ctx: MmWeak, mut rx: AdexEventRx, i_am_relay: bool) { loop { let adex_event = rx.next().await; diff --git a/mm2src/mm2_main/src/ordermatch_tests.rs b/mm2src/mm2_main/src/ordermatch_tests.rs index 6f2af8a757..ec96d8f484 100644 --- a/mm2src/mm2_main/src/ordermatch_tests.rs +++ b/mm2src/mm2_main/src/ordermatch_tests.rs @@ -1,5 +1,4 @@ use super::*; -use crate::mm2::lp_network::P2PContext; use crate::mm2::lp_ordermatch::new_protocol::{MakerOrderUpdated, PubkeyKeepAlive}; use coins::{MmCoin, TestCoin}; use common::{block_on, executor::spawn}; @@ -9,6 +8,7 @@ use futures::{channel::mpsc, StreamExt}; use mm2_core::mm_ctx::{MmArc, MmCtx}; use mm2_libp2p::atomicdex_behaviour::AdexBehaviourCmd; use mm2_libp2p::{decode_message, PeerId}; +use mm2_net::p2p::P2PContext; use mm2_test_helpers::for_tests::mm_ctx_with_iguana; use mocktopus::mocking::*; use rand::{seq::SliceRandom, thread_rng, Rng}; diff --git a/mm2src/mm2_main/src/rpc.rs b/mm2src/mm2_main/src/rpc.rs index 5ade053771..1c06d76352 100644 --- a/mm2src/mm2_main/src/rpc.rs +++ b/mm2src/mm2_main/src/rpc.rs @@ -21,7 +21,6 @@ // use crate::mm2::rpc::rate_limiter::RateLimitError; -use crate::mm2::rpc::sse::{handle_sse_events, SSE_ENDPOINT}; use common::log::{error, info}; use common::{err_to_rpc_json_string, err_tp_rpc_json, HttpStatusCode, APPLICATION_JSON}; use derive_more::Display; @@ -29,8 +28,6 @@ use futures::future::{join_all, FutureExt}; use http::header::{HeaderValue, ACCESS_CONTROL_ALLOW_ORIGIN, CONTENT_TYPE}; use http::request::Parts; use http::{Method, Request, Response, StatusCode}; -#[cfg(not(target_arch = "wasm32"))] -use hyper::{self, Body, Server}; use lazy_static::lazy_static; use mm2_core::mm_ctx::MmArc; use mm2_err_handle::prelude::*; @@ -41,6 +38,11 @@ use serde_json::{self as json, Value as Json}; use std::borrow::Cow; use std::net::SocketAddr; +cfg_native! { + use hyper::{self, Body, Server}; + use mm2_net::sse_handler::{handle_sse, SSE_ENDPOINT}; +} + #[path = "rpc/dispatcher/dispatcher.rs"] mod dispatcher; #[path = "rpc/dispatcher/dispatcher_legacy.rs"] mod dispatcher_legacy; @@ -48,7 +50,6 @@ mod dispatcher_legacy; #[path = "rpc/lp_commands/lp_commands_legacy.rs"] pub mod lp_commands_legacy; #[path = "rpc/rate_limiter.rs"] mod rate_limiter; -mod sse; /// Lists the RPC method not requiring the "userpass" authentication. /// None is also public to skip auth and display proper error in case of method is missing @@ -358,7 +359,7 @@ pub extern "C" fn spawn_rpc(ctx_h: u32) { let make_svc_fut = move |remote_addr: SocketAddr| async move { Ok::<_, Infallible>(service_fn(move |req: Request| async move { if req.uri().path() == SSE_ENDPOINT { - let res = handle_sse_events(req, ctx_h).await?; + let res = handle_sse(req, ctx_h).await?; return Ok::<_, Infallible>(res); } diff --git a/mm2src/mm2_main/src/rpc/lp_commands/lp_commands_legacy.rs b/mm2src/mm2_main/src/rpc/lp_commands/lp_commands_legacy.rs index 7b5d68b8d0..e060175858 100644 --- a/mm2src/mm2_main/src/rpc/lp_commands/lp_commands_legacy.rs +++ b/mm2src/mm2_main/src/rpc/lp_commands/lp_commands_legacy.rs @@ -27,6 +27,7 @@ use futures::compat::Future01CompatExt; use http::Response; use mm2_core::mm_ctx::MmArc; use mm2_metrics::MetricsOps; +use mm2_net::p2p::P2PContext; use mm2_number::construct_detailed; use mm2_rpc::data::legacy::{BalanceResponse, CoinInitResponse, Mm2RpcResult, MmVersionResponse, Status}; use serde_json::{self as json, Value as Json}; @@ -306,7 +307,6 @@ pub fn version(ctx: MmArc) -> HyRes { } pub async fn get_peers_info(ctx: MmArc) -> Result>, String> { - use crate::mm2::lp_network::P2PContext; use mm2_libp2p::atomicdex_behaviour::get_peers_info; let ctx = P2PContext::fetch_from_mm_arc(&ctx); let cmd_tx = ctx.cmd_tx.lock().clone(); @@ -319,7 +319,6 @@ pub async fn get_peers_info(ctx: MmArc) -> Result>, String> { } pub async fn get_gossip_mesh(ctx: MmArc) -> Result>, String> { - use crate::mm2::lp_network::P2PContext; use mm2_libp2p::atomicdex_behaviour::get_gossip_mesh; let ctx = P2PContext::fetch_from_mm_arc(&ctx); let cmd_tx = ctx.cmd_tx.lock().clone(); @@ -332,7 +331,6 @@ pub async fn get_gossip_mesh(ctx: MmArc) -> Result>, String> { } pub async fn get_gossip_peer_topics(ctx: MmArc) -> Result>, String> { - use crate::mm2::lp_network::P2PContext; use mm2_libp2p::atomicdex_behaviour::get_gossip_peer_topics; let ctx = P2PContext::fetch_from_mm_arc(&ctx); let cmd_tx = ctx.cmd_tx.lock().clone(); @@ -345,7 +343,6 @@ pub async fn get_gossip_peer_topics(ctx: MmArc) -> Result>, Str } pub async fn get_gossip_topic_peers(ctx: MmArc) -> Result>, String> { - use crate::mm2::lp_network::P2PContext; use mm2_libp2p::atomicdex_behaviour::get_gossip_topic_peers; let ctx = P2PContext::fetch_from_mm_arc(&ctx); let cmd_tx = ctx.cmd_tx.lock().clone(); @@ -358,7 +355,6 @@ pub async fn get_gossip_topic_peers(ctx: MmArc) -> Result>, Str } pub async fn get_relay_mesh(ctx: MmArc) -> Result>, String> { - use crate::mm2::lp_network::P2PContext; use mm2_libp2p::atomicdex_behaviour::get_relay_mesh; let ctx = P2PContext::fetch_from_mm_arc(&ctx); let cmd_tx = ctx.cmd_tx.lock().clone(); diff --git a/mm2src/mm2_net/Cargo.toml b/mm2src/mm2_net/Cargo.toml index e567546f6c..44c22ce177 100644 --- a/mm2src/mm2_net/Cargo.toml +++ b/mm2src/mm2_net/Cargo.toml @@ -7,21 +7,25 @@ edition = "2018" doctest = false [dependencies] +async-stream = "0.3" async-trait = "0.1" -serde = "1" -serde_json = { version = "1", features = ["preserve_order", "raw_value"] } bytes = "1.1" cfg-if = "1.0" common = { path = "../common" } -ethkey = { git = "https://github.com/KomodoPlatform/mm2-parity-ethereum.git" } -mm2_err_handle = { path = "../mm2_err_handle" } -mm2_core = { path = "../mm2_core" } derive_more = "0.99" -http = "0.2" -rand = { version = "0.7", features = ["std", "small_rng", "wasm-bindgen"] } +ethkey = { git = "https://github.com/KomodoPlatform/mm2-parity-ethereum.git" } futures = { version = "0.3", package = "futures", features = ["compat", "async-await", "thread-pool"] } +http = "0.2" lazy_static = "1.4" +mm2_core = { path = "../mm2_core" } +mm2_err_handle = { path = "../mm2_err_handle" } +mm2_event_stream = { path = "../mm2_event_stream"} +mm2-libp2p = { path = "../mm2_libp2p" } +parking_lot = { version = "0.12.0", features = ["nightly"] } prost = "0.10" +rand = { version = "0.7", features = ["std", "small_rng", "wasm-bindgen"] } +serde = "1" +serde_json = { version = "1", features = ["preserve_order", "raw_value"] } [target.'cfg(target_arch = "wasm32")'.dependencies] gstuff = { version = "0.7", features = ["nightly"] } @@ -38,3 +42,6 @@ gstuff = { version = "0.7", features = ["nightly"] } rustls = { version = "0.20", default-features = false } tokio = { version = "1.20" } tokio-rustls = { version = "0.23", default-features = false } + +[dev-dependencies] +mocktopus = "0.8.0" diff --git a/mm2src/mm2_net/src/lib.rs b/mm2src/mm2_net/src/lib.rs index 99935bd25b..ed70e093fa 100644 --- a/mm2src/mm2_net/src/lib.rs +++ b/mm2src/mm2_net/src/lib.rs @@ -1,8 +1,11 @@ pub mod grpc_web; +pub mod p2p; pub mod transport; #[cfg(not(target_arch = "wasm32"))] pub mod ip_addr; #[cfg(not(target_arch = "wasm32"))] pub mod native_http; #[cfg(not(target_arch = "wasm32"))] pub mod native_tls; +#[cfg(not(target_arch = "wasm32"))] pub mod network_event; +#[cfg(not(target_arch = "wasm32"))] pub mod sse_handler; #[cfg(target_arch = "wasm32")] pub mod wasm_http; #[cfg(target_arch = "wasm32")] pub mod wasm_ws; diff --git a/mm2src/mm2_net/src/network_event.rs b/mm2src/mm2_net/src/network_event.rs new file mode 100644 index 0000000000..bc8fbb1ed5 --- /dev/null +++ b/mm2src/mm2_net/src/network_event.rs @@ -0,0 +1,37 @@ +use common::executor::Timer; +use mm2_core::mm_ctx::MmArc; +use mm2_event_stream::Event; +use mm2_libp2p::atomicdex_behaviour; +use serde_json::json; + +use crate::p2p::P2PContext; + +const NETWORK_EVENT_TYPE: &str = "NETWORK"; + +pub async fn start_network_event_stream(ctx: MmArc) { + let p2p_ctx = P2PContext::fetch_from_mm_arc(&ctx); + + loop { + let p2p_cmd_tx = p2p_ctx.cmd_tx.lock().clone(); + + let peers_info = atomicdex_behaviour::get_peers_info(p2p_cmd_tx.clone()).await; + let gossip_mesh = atomicdex_behaviour::get_gossip_mesh(p2p_cmd_tx.clone()).await; + let gossip_peer_topics = atomicdex_behaviour::get_gossip_peer_topics(p2p_cmd_tx.clone()).await; + let gossip_topic_peers = atomicdex_behaviour::get_gossip_topic_peers(p2p_cmd_tx.clone()).await; + let relay_mesh = atomicdex_behaviour::get_relay_mesh(p2p_cmd_tx).await; + + let event_data = json!({ + "peers_info": peers_info, + "gossip_mesh": gossip_mesh, + "gossip_peer_topics": gossip_peer_topics, + "gossip_topic_peers": gossip_topic_peers, + "relay_mesh": relay_mesh, + }); + + ctx.stream_channel_controller + .broadcast(Event::new(NETWORK_EVENT_TYPE.to_string(), event_data.to_string())) + .await; + + Timer::sleep(1.).await; // TODO: read this from configuration + } +} diff --git a/mm2src/mm2_net/src/p2p.rs b/mm2src/mm2_net/src/p2p.rs new file mode 100644 index 0000000000..74ee9dd9f1 --- /dev/null +++ b/mm2src/mm2_net/src/p2p.rs @@ -0,0 +1,40 @@ +use mm2_core::mm_ctx::MmArc; +use mm2_libp2p::atomicdex_behaviour::AdexCmdTx; +#[cfg(test)] use mocktopus::macros::*; +use parking_lot::Mutex; +use std::sync::Arc; + +pub struct P2PContext { + /// Using Mutex helps to prevent cloning which can actually result to channel being unbounded in case of using 1 tx clone per 1 message. + pub cmd_tx: Mutex, +} + +// `mockable` violates these +#[allow( + clippy::forget_ref, + clippy::forget_copy, + clippy::swap_ptr_to_ref, + clippy::forget_non_drop, + clippy::let_unit_value +)] +#[cfg_attr(test, mockable)] +impl P2PContext { + pub fn new(cmd_tx: AdexCmdTx) -> Self { + P2PContext { + cmd_tx: Mutex::new(cmd_tx), + } + } + + pub fn store_to_mm_arc(self, ctx: &MmArc) { *ctx.p2p_ctx.lock().unwrap() = Some(Arc::new(self)) } + + pub fn fetch_from_mm_arc(ctx: &MmArc) -> Arc { + ctx.p2p_ctx + .lock() + .unwrap() + .as_ref() + .unwrap() + .clone() + .downcast() + .unwrap() + } +} diff --git a/mm2src/mm2_main/src/sse.rs b/mm2src/mm2_net/src/sse_handler.rs similarity index 85% rename from mm2src/mm2_main/src/sse.rs rename to mm2src/mm2_net/src/sse_handler.rs index 68426b9dff..37b340654c 100644 --- a/mm2src/mm2_main/src/sse.rs +++ b/mm2src/mm2_net/src/sse_handler.rs @@ -1,13 +1,11 @@ -// TODO: handle this module inside the `mm2_event_stream` crate. - use hyper::{body::Bytes, Body, Request, Response}; use mm2_core::mm_ctx::MmArc; use std::convert::Infallible; -pub(crate) const SSE_ENDPOINT: &str = "/event-stream"; +pub const SSE_ENDPOINT: &str = "/event-stream"; /// Handles broadcasted messages from `mm2_event_stream` continuously. -pub async fn handle_sse_events(request: Request, ctx_h: u32) -> Result, Infallible> { +pub async fn handle_sse(request: Request, ctx_h: u32) -> Result, Infallible> { fn get_filtered_events(request: Request) -> Vec { let query = request.uri().query().unwrap_or(""); let events_param = query @@ -16,7 +14,11 @@ pub async fn handle_sse_events(request: Request, ctx_h: u32) -> Result, ctx_h: u32) -> Result Date: Mon, 28 Aug 2023 18:35:23 +0300 Subject: [PATCH 09/48] manage event streaming dynamically Signed-off-by: onur-ozkan --- mm2src/mm2_core/src/mm_ctx.rs | 17 +++++++++++++- mm2src/mm2_event_stream/src/lib.rs | 33 ++++++++++++++++++++++++++++ mm2src/mm2_main/src/lp_native_dex.rs | 21 ++++++++++++++---- mm2src/mm2_main/src/rpc.rs | 8 ++++--- mm2src/mm2_net/src/network_event.rs | 8 ++++--- mm2src/mm2_net/src/sse_handler.rs | 14 ++++++++++-- 6 files changed, 88 insertions(+), 13 deletions(-) diff --git a/mm2src/mm2_core/src/mm_ctx.rs b/mm2src/mm2_core/src/mm_ctx.rs index 49b570d21c..52799ce6d6 100644 --- a/mm2src/mm2_core/src/mm_ctx.rs +++ b/mm2src/mm2_core/src/mm_ctx.rs @@ -6,7 +6,7 @@ use common::log::{self, LogLevel, LogOnError, LogState}; use common::{cfg_native, cfg_wasm32, small_rng}; use gstuff::{try_s, Constructible, ERR, ERRL}; use lazy_static::lazy_static; -use mm2_event_stream::{controller::Controller, Event}; +use mm2_event_stream::{controller::Controller, Event, EventStreamConfiguration}; use mm2_metrics::{MetricsArc, MetricsOps}; use primitives::hash::H160; use rand::Rng; @@ -341,6 +341,20 @@ impl MmCtx { .lock() .unwrap() } + + /// Reads 'event_stream_configuration' from the mm2 configuration. If the config wasn't given, + /// returns `None`. + pub fn event_stream_configuration(&self) -> Option { + let value = &self.conf["event_stream_configuration"]; + if value.is_null() { + return None; + } + + let config: EventStreamConfiguration = + json::from_value(value.clone()).expect("Invalid json value in 'event_stream_configuration'."); + + Some(config) + } } impl Default for MmCtx { @@ -681,6 +695,7 @@ impl MmCtxBuilder { let mut ctx = MmCtx::with_log_state(log); ctx.mm_version = self.version; ctx.datetime = self.datetime; + if let Some(conf) = self.conf { ctx.conf = conf } diff --git a/mm2src/mm2_event_stream/src/lib.rs b/mm2src/mm2_event_stream/src/lib.rs index b2fbfdee6a..fdc725f03b 100644 --- a/mm2src/mm2_event_stream/src/lib.rs +++ b/mm2src/mm2_event_stream/src/lib.rs @@ -20,4 +20,37 @@ impl Event { pub fn message(&self) -> &str { &self.message } } +/// Configuration for event streaming +#[derive(Deserialize)] +pub struct EventStreamConfiguration { + #[serde(default)] + pub access_control_allow_origin: String, + #[serde(default)] + pub active_events: Vec, +} + +#[derive(Clone, Default, Deserialize)] +pub struct EventStatus { + name: String, + pub stream_interval_seconds: f64, +} + +impl Default for EventStreamConfiguration { + fn default() -> Self { + Self { + access_control_allow_origin: String::from("*"), + active_events: vec![], + } + } +} + +impl EventStreamConfiguration { + pub fn get_event(&self, event_name: &str) -> Option { + self.active_events + .iter() + .find(|event| event.name == event_name) + .cloned() + } +} + pub mod controller; diff --git a/mm2src/mm2_main/src/lp_native_dex.rs b/mm2src/mm2_main/src/lp_native_dex.rs index 30da1d6b82..5cc7131931 100644 --- a/mm2src/mm2_main/src/lp_native_dex.rs +++ b/mm2src/mm2_main/src/lp_native_dex.rs @@ -31,6 +31,7 @@ use mm2_err_handle::prelude::*; use mm2_libp2p::{spawn_gossipsub, AdexBehaviourError, NodeType, RelayAddress, RelayAddressError, SwarmRuntime, WssCerts}; use mm2_metrics::mm_gauge; +use mm2_net::network_event::NETWORK_EVENT_TYPE; use mm2_net::p2p::P2PContext; use rpc_task::RpcTaskError; use serde_json::{self as json}; @@ -382,6 +383,21 @@ fn migrate_db(ctx: &MmArc) -> MmInitResult<()> { #[cfg(not(target_arch = "wasm32"))] fn migration_1(_ctx: &MmArc) {} +#[cfg(not(target_arch = "wasm32"))] +fn init_event_streaming(ctx: &MmArc) { + if let Some(config) = ctx.event_stream_configuration() { + if let Some(event) = config.get_event(NETWORK_EVENT_TYPE) { + info!( + "Event {NETWORK_EVENT_TYPE} is activated with {} seconds interval.", + event.stream_interval_seconds + ); + + ctx.spawner() + .spawn(start_network_event_stream(ctx.clone(), event.stream_interval_seconds)); + } + } +} + pub async fn lp_init_continue(ctx: MmArc) -> MmInitResult<()> { init_ordermatch_context(&ctx)?; init_p2p(ctx.clone()).await?; @@ -413,10 +429,7 @@ pub async fn lp_init_continue(ctx: MmArc) -> MmInitResult<()> { kick_start(ctx.clone()).await?; #[cfg(not(target_arch = "wasm32"))] - { - // TODO: this should be configurable from MM2 the config - ctx.spawner().spawn(start_network_event_stream(ctx.clone())); - } + init_event_streaming(&ctx); ctx.spawner().spawn(lp_ordermatch_loop(ctx.clone())); diff --git a/mm2src/mm2_main/src/rpc.rs b/mm2src/mm2_main/src/rpc.rs index 1c06d76352..e59327e811 100644 --- a/mm2src/mm2_main/src/rpc.rs +++ b/mm2src/mm2_main/src/rpc.rs @@ -356,9 +356,13 @@ pub extern "C" fn spawn_rpc(ctx_h: u32) { // then we might want to refactor into starting it ideomatically in order to benefit from a more graceful shutdown, // cf. https://github.com/hyperium/hyper/pull/1640. + let ctx = MmArc::from_ffi_handle(ctx_h).expect("No context"); + + let is_event_stream_enabled = ctx.event_stream_configuration().is_some(); + let make_svc_fut = move |remote_addr: SocketAddr| async move { Ok::<_, Infallible>(service_fn(move |req: Request| async move { - if req.uri().path() == SSE_ENDPOINT { + if is_event_stream_enabled && req.uri().path() == SSE_ENDPOINT { let res = handle_sse(req, ctx_h).await?; return Ok::<_, Infallible>(res); } @@ -427,8 +431,6 @@ pub extern "C" fn spawn_rpc(ctx_h: u32) { }; } - let ctx = MmArc::from_ffi_handle(ctx_h).expect("No context"); - let rpc_ip_port = ctx .rpc_ip_port() .unwrap_or_else(|err| panic!("Invalid RPC port: {}", err)); diff --git a/mm2src/mm2_net/src/network_event.rs b/mm2src/mm2_net/src/network_event.rs index bc8fbb1ed5..44a0d6fa11 100644 --- a/mm2src/mm2_net/src/network_event.rs +++ b/mm2src/mm2_net/src/network_event.rs @@ -6,9 +6,11 @@ use serde_json::json; use crate::p2p::P2PContext; -const NETWORK_EVENT_TYPE: &str = "NETWORK"; +// TODO: Create Event trait to enforce same design for all events. -pub async fn start_network_event_stream(ctx: MmArc) { +pub const NETWORK_EVENT_TYPE: &str = "NETWORK"; + +pub async fn start_network_event_stream(ctx: MmArc, event_interval: f64) { let p2p_ctx = P2PContext::fetch_from_mm_arc(&ctx); loop { @@ -32,6 +34,6 @@ pub async fn start_network_event_stream(ctx: MmArc) { .broadcast(Event::new(NETWORK_EVENT_TYPE.to_string(), event_data.to_string())) .await; - Timer::sleep(1.).await; // TODO: read this from configuration + Timer::sleep(event_interval).await; } } diff --git a/mm2src/mm2_net/src/sse_handler.rs b/mm2src/mm2_net/src/sse_handler.rs index 37b340654c..9d550c012d 100644 --- a/mm2src/mm2_net/src/sse_handler.rs +++ b/mm2src/mm2_net/src/sse_handler.rs @@ -28,10 +28,20 @@ pub async fn handle_sse(request: Request, ctx_h: u32) -> Result return handle_internal_error(err).await, }; + let config = match ctx.event_stream_configuration() { + Some(config) => config, + None => { + return handle_internal_error( + "Event stream configuration couldn't be found. This should never happen.".to_string(), + ) + .await + }, + }; + let filtered_events = get_filtered_events(request); let mut channel_controller = ctx.stream_channel_controller.clone(); - let mut rx = channel_controller.create_channel(4); // TODO: read this from configuration + let mut rx = channel_controller.create_channel(config.active_events.len()); let body = Body::wrap_stream(async_stream::stream! { while let Some(msg) = rx.recv().await { // If there are no filtered events, that means we want to @@ -47,7 +57,7 @@ pub async fn handle_sse(request: Request, ctx_h: u32) -> Result Date: Mon, 28 Aug 2023 18:41:11 +0300 Subject: [PATCH 10/48] leave perf improvement TODO note Signed-off-by: onur-ozkan --- mm2src/mm2_core/src/mm_ctx.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mm2src/mm2_core/src/mm_ctx.rs b/mm2src/mm2_core/src/mm_ctx.rs index 52799ce6d6..8ed054dc0e 100644 --- a/mm2src/mm2_core/src/mm_ctx.rs +++ b/mm2src/mm2_core/src/mm_ctx.rs @@ -344,6 +344,8 @@ impl MmCtx { /// Reads 'event_stream_configuration' from the mm2 configuration. If the config wasn't given, /// returns `None`. + /// + /// TODO: Move this value to `MmCtx`, so deserialization will be executed only once pub fn event_stream_configuration(&self) -> Option { let value = &self.conf["event_stream_configuration"]; if value.is_null() { From c58a7d5736d889a703351ef1acb8a1a28a726cd6 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Tue, 29 Aug 2023 10:43:34 +0300 Subject: [PATCH 11/48] avoid serializing events on http side Signed-off-by: onur-ozkan --- mm2src/mm2_event_stream/src/lib.rs | 3 +-- mm2src/mm2_net/src/sse_handler.rs | 7 +++---- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/mm2src/mm2_event_stream/src/lib.rs b/mm2src/mm2_event_stream/src/lib.rs index fdc725f03b..9f0494235d 100644 --- a/mm2src/mm2_event_stream/src/lib.rs +++ b/mm2src/mm2_event_stream/src/lib.rs @@ -1,7 +1,6 @@ -use serde::{Deserialize, Serialize}; +use serde::Deserialize; /// multi-purpose/generic event type that can easily be used over the event streaming -#[derive(Debug, Deserialize, Serialize)] pub struct Event { _type: String, message: String, diff --git a/mm2src/mm2_net/src/sse_handler.rs b/mm2src/mm2_net/src/sse_handler.rs index 9d550c012d..b054916b60 100644 --- a/mm2src/mm2_net/src/sse_handler.rs +++ b/mm2src/mm2_net/src/sse_handler.rs @@ -43,12 +43,11 @@ pub async fn handle_sse(request: Request, ctx_h: u32) -> Result(Bytes::from(format!("data: {json} \n\n"))); + if filtered_events.is_empty() || filtered_events.contains(&event.event_type().to_owned()) { + yield Ok::<_, hyper::Error>(Bytes::from(format!("data: {} \n\n", event.message()))); } } }); From 79245d18ed37fd21a20f965763750e47c81afec4 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Tue, 29 Aug 2023 11:01:03 +0300 Subject: [PATCH 12/48] fix wasm error Signed-off-by: onur-ozkan --- mm2src/mm2_main/src/lp_native_dex.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mm2src/mm2_main/src/lp_native_dex.rs b/mm2src/mm2_main/src/lp_native_dex.rs index 5cc7131931..980d9abf64 100644 --- a/mm2src/mm2_main/src/lp_native_dex.rs +++ b/mm2src/mm2_main/src/lp_native_dex.rs @@ -31,7 +31,6 @@ use mm2_err_handle::prelude::*; use mm2_libp2p::{spawn_gossipsub, AdexBehaviourError, NodeType, RelayAddress, RelayAddressError, SwarmRuntime, WssCerts}; use mm2_metrics::mm_gauge; -use mm2_net::network_event::NETWORK_EVENT_TYPE; use mm2_net::p2p::P2PContext; use rpc_task::RpcTaskError; use serde_json::{self as json}; @@ -385,6 +384,8 @@ fn migration_1(_ctx: &MmArc) {} #[cfg(not(target_arch = "wasm32"))] fn init_event_streaming(ctx: &MmArc) { + use mm2_net::network_event::NETWORK_EVENT_TYPE; + if let Some(config) = ctx.event_stream_configuration() { if let Some(event) = config.get_event(NETWORK_EVENT_TYPE) { info!( From 99f87c820afc1ed8cb873e4f46ca6373d7173c12 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Tue, 29 Aug 2023 11:28:02 +0300 Subject: [PATCH 13/48] update SSE data type Signed-off-by: onur-ozkan --- mm2src/mm2_net/src/sse_handler.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/mm2src/mm2_net/src/sse_handler.rs b/mm2src/mm2_net/src/sse_handler.rs index b054916b60..2c7338cdc2 100644 --- a/mm2src/mm2_net/src/sse_handler.rs +++ b/mm2src/mm2_net/src/sse_handler.rs @@ -1,5 +1,6 @@ use hyper::{body::Bytes, Body, Request, Response}; use mm2_core::mm_ctx::MmArc; +use serde_json::json; use std::convert::Infallible; pub const SSE_ENDPOINT: &str = "/event-stream"; @@ -47,7 +48,12 @@ pub async fn handle_sse(request: Request, ctx_h: u32) -> Result(Bytes::from(format!("data: {} \n\n", event.message()))); + let data = json!({ + "_type": event.event_type(), + "message": event.message(), + }); + + yield Ok::<_, hyper::Error>(Bytes::from(format!("data: {data} \n\n"))); } } }); From 90996c5f46b858a6d6790fc549a4664b26508a53 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Tue, 29 Aug 2023 13:14:10 +0300 Subject: [PATCH 14/48] implement `EventBehaviour` Signed-off-by: onur-ozkan --- Cargo.lock | 2 + mm2src/mm2_event_stream/Cargo.toml | 1 + mm2src/mm2_event_stream/src/behaviour.rs | 15 +++++ mm2src/mm2_event_stream/src/lib.rs | 1 + mm2src/mm2_main/Cargo.toml | 1 + mm2src/mm2_main/src/lp_native_dex.rs | 19 ++---- mm2src/mm2_net/src/network_event.rs | 82 +++++++++++++++--------- 7 files changed, 78 insertions(+), 43 deletions(-) create mode 100644 mm2src/mm2_event_stream/src/behaviour.rs diff --git a/Cargo.lock b/Cargo.lock index ec2adc5a6c..600daa8785 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4187,6 +4187,7 @@ dependencies = [ name = "mm2_event_stream" version = "0.1.0" dependencies = [ + "async-trait", "parking_lot 0.12.0", "serde", "tokio", @@ -4287,6 +4288,7 @@ dependencies = [ "mm2_core", "mm2_db", "mm2_err_handle", + "mm2_event_stream", "mm2_gui_storage", "mm2_io", "mm2_metrics", diff --git a/mm2src/mm2_event_stream/Cargo.toml b/mm2src/mm2_event_stream/Cargo.toml index 8329355c96..ce18ef8143 100644 --- a/mm2src/mm2_event_stream/Cargo.toml +++ b/mm2src/mm2_event_stream/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" edition = "2021" [dependencies] +async-trait = "0.1" parking_lot = "0.12" serde = { version = "1", features = ["derive", "rc"] } tokio = { version = "1", features = ["sync"] } diff --git a/mm2src/mm2_event_stream/src/behaviour.rs b/mm2src/mm2_event_stream/src/behaviour.rs new file mode 100644 index 0000000000..bb905af3fc --- /dev/null +++ b/mm2src/mm2_event_stream/src/behaviour.rs @@ -0,0 +1,15 @@ +use crate::EventStreamConfiguration; +use async_trait::async_trait; + +#[async_trait] +pub trait EventBehaviour { + /// Unique name of the event. + const EVENT_NAME: &'static str; + + /// Event handler that is responsible for broadcasting event data to the streaming channels. + async fn handle(self, interval: f64); + + /// Spawns the `Self::handle` in a separate thread if the event is active according to the mm2 configuration. + /// Does nothing if the event is not active. + fn spawn_if_active(self, config: &EventStreamConfiguration); +} diff --git a/mm2src/mm2_event_stream/src/lib.rs b/mm2src/mm2_event_stream/src/lib.rs index 9f0494235d..de95ed5105 100644 --- a/mm2src/mm2_event_stream/src/lib.rs +++ b/mm2src/mm2_event_stream/src/lib.rs @@ -52,4 +52,5 @@ impl EventStreamConfiguration { } } +pub mod behaviour; pub mod controller; diff --git a/mm2src/mm2_main/Cargo.toml b/mm2src/mm2_main/Cargo.toml index f1258d1827..cd5a33fc25 100644 --- a/mm2src/mm2_main/Cargo.toml +++ b/mm2src/mm2_main/Cargo.toml @@ -57,6 +57,7 @@ lazy_static = "1.4" libc = "0.2" mm2_core = { path = "../mm2_core" } mm2_err_handle = { path = "../mm2_err_handle" } +mm2_event_stream = { path = "../mm2_event_stream" } mm2_gui_storage = { path = "../mm2_gui_storage" } mm2_io = { path = "../mm2_io" } mm2-libp2p = { path = "../mm2_libp2p" } diff --git a/mm2src/mm2_main/src/lp_native_dex.rs b/mm2src/mm2_main/src/lp_native_dex.rs index 980d9abf64..7ace35fe3a 100644 --- a/mm2src/mm2_main/src/lp_native_dex.rs +++ b/mm2src/mm2_main/src/lp_native_dex.rs @@ -51,10 +51,11 @@ use crate::mm2::lp_swap::{running_swaps_num, swap_kick_starts}; use crate::mm2::rpc::spawn_rpc; cfg_native! { + use db_common::sqlite::rusqlite::Error as SqlError; + use mm2_event_stream::behaviour::EventBehaviour; use mm2_io::fs::{ensure_dir_is_writable, ensure_file_is_writable}; use mm2_net::ip_addr::myipaddr; - use mm2_net::network_event::start_network_event_stream; - use db_common::sqlite::rusqlite::Error as SqlError; + use mm2_net::network_event::NetworkEvent; } #[path = "lp_init/init_context.rs"] mod init_context; @@ -384,18 +385,10 @@ fn migration_1(_ctx: &MmArc) {} #[cfg(not(target_arch = "wasm32"))] fn init_event_streaming(ctx: &MmArc) { - use mm2_net::network_event::NETWORK_EVENT_TYPE; - + // This condition only executed if events were enabled in mm2 configuration. if let Some(config) = ctx.event_stream_configuration() { - if let Some(event) = config.get_event(NETWORK_EVENT_TYPE) { - info!( - "Event {NETWORK_EVENT_TYPE} is activated with {} seconds interval.", - event.stream_interval_seconds - ); - - ctx.spawner() - .spawn(start_network_event_stream(ctx.clone(), event.stream_interval_seconds)); - } + // Network event handling + NetworkEvent::new(ctx.clone()).spawn_if_active(&config); } } diff --git a/mm2src/mm2_net/src/network_event.rs b/mm2src/mm2_net/src/network_event.rs index 44a0d6fa11..6dd5ee4396 100644 --- a/mm2src/mm2_net/src/network_event.rs +++ b/mm2src/mm2_net/src/network_event.rs @@ -1,39 +1,61 @@ -use common::executor::Timer; +use crate::p2p::P2PContext; +use async_trait::async_trait; +use common::{executor::{SpawnFuture, Timer}, + log::info}; use mm2_core::mm_ctx::MmArc; -use mm2_event_stream::Event; +pub use mm2_event_stream::behaviour::EventBehaviour; +use mm2_event_stream::{Event, EventStreamConfiguration}; use mm2_libp2p::atomicdex_behaviour; use serde_json::json; -use crate::p2p::P2PContext; - -// TODO: Create Event trait to enforce same design for all events. - -pub const NETWORK_EVENT_TYPE: &str = "NETWORK"; - -pub async fn start_network_event_stream(ctx: MmArc, event_interval: f64) { - let p2p_ctx = P2PContext::fetch_from_mm_arc(&ctx); - - loop { - let p2p_cmd_tx = p2p_ctx.cmd_tx.lock().clone(); - - let peers_info = atomicdex_behaviour::get_peers_info(p2p_cmd_tx.clone()).await; - let gossip_mesh = atomicdex_behaviour::get_gossip_mesh(p2p_cmd_tx.clone()).await; - let gossip_peer_topics = atomicdex_behaviour::get_gossip_peer_topics(p2p_cmd_tx.clone()).await; - let gossip_topic_peers = atomicdex_behaviour::get_gossip_topic_peers(p2p_cmd_tx.clone()).await; - let relay_mesh = atomicdex_behaviour::get_relay_mesh(p2p_cmd_tx).await; +pub struct NetworkEvent { + ctx: MmArc, +} - let event_data = json!({ - "peers_info": peers_info, - "gossip_mesh": gossip_mesh, - "gossip_peer_topics": gossip_peer_topics, - "gossip_topic_peers": gossip_topic_peers, - "relay_mesh": relay_mesh, - }); +impl NetworkEvent { + pub fn new(ctx: MmArc) -> Self { Self { ctx } } +} - ctx.stream_channel_controller - .broadcast(Event::new(NETWORK_EVENT_TYPE.to_string(), event_data.to_string())) - .await; +#[async_trait] +impl EventBehaviour for NetworkEvent { + const EVENT_NAME: &'static str = "NETWORK"; + + async fn handle(self, interval: f64) { + let p2p_ctx = P2PContext::fetch_from_mm_arc(&self.ctx); + + loop { + let p2p_cmd_tx = p2p_ctx.cmd_tx.lock().clone(); + + let peers_info = atomicdex_behaviour::get_peers_info(p2p_cmd_tx.clone()).await; + let gossip_mesh = atomicdex_behaviour::get_gossip_mesh(p2p_cmd_tx.clone()).await; + let gossip_peer_topics = atomicdex_behaviour::get_gossip_peer_topics(p2p_cmd_tx.clone()).await; + let gossip_topic_peers = atomicdex_behaviour::get_gossip_topic_peers(p2p_cmd_tx.clone()).await; + let relay_mesh = atomicdex_behaviour::get_relay_mesh(p2p_cmd_tx).await; + + let event_data = json!({ + "peers_info": peers_info, + "gossip_mesh": gossip_mesh, + "gossip_peer_topics": gossip_peer_topics, + "gossip_topic_peers": gossip_topic_peers, + "relay_mesh": relay_mesh, + }); + + self.ctx + .stream_channel_controller + .broadcast(Event::new(Self::EVENT_NAME.to_string(), event_data.to_string())) + .await; + + Timer::sleep(interval).await; + } + } - Timer::sleep(event_interval).await; + fn spawn_if_active(self, config: &EventStreamConfiguration) { + if let Some(event) = config.get_event(Self::EVENT_NAME) { + info!( + "NETWORK event is activated with {} seconds interval.", + event.stream_interval_seconds + ); + self.ctx.spawner().spawn(self.handle(event.stream_interval_seconds)); + } } } From 8445f35a8363a5c141106c25eab83888a949e883 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Tue, 29 Aug 2023 13:25:28 +0300 Subject: [PATCH 15/48] save configuration in mm2 context Signed-off-by: onur-ozkan --- mm2src/mm2_core/src/mm_ctx.rs | 29 ++++++++++++---------------- mm2src/mm2_main/src/lp_native_dex.rs | 4 ++-- mm2src/mm2_main/src/rpc.rs | 2 +- mm2src/mm2_net/src/sse_handler.rs | 4 ++-- 4 files changed, 17 insertions(+), 22 deletions(-) diff --git a/mm2src/mm2_core/src/mm_ctx.rs b/mm2src/mm2_core/src/mm_ctx.rs index 8ed054dc0e..7f16613f50 100644 --- a/mm2src/mm2_core/src/mm_ctx.rs +++ b/mm2src/mm2_core/src/mm_ctx.rs @@ -75,6 +75,8 @@ pub struct MmCtx { pub rpc_started: Constructible, /// Channels for continuously streaming data to clients via SSE. pub stream_channel_controller: Controller, + /// Configuration of event streaming used for SSE. + pub event_stream_configuration: Option, /// True if the MarketMaker instance needs to stop. pub stop: Constructible, /// Unique context identifier, allowing us to more easily pass the context through the FFI boundaries. @@ -137,6 +139,7 @@ impl MmCtx { initialized: Constructible::default(), rpc_started: Constructible::default(), stream_channel_controller: Controller::new(), + event_stream_configuration: None, stop: Constructible::default(), ffi_handle: Constructible::default(), ordermatch_ctx: Mutex::new(None), @@ -341,22 +344,6 @@ impl MmCtx { .lock() .unwrap() } - - /// Reads 'event_stream_configuration' from the mm2 configuration. If the config wasn't given, - /// returns `None`. - /// - /// TODO: Move this value to `MmCtx`, so deserialization will be executed only once - pub fn event_stream_configuration(&self) -> Option { - let value = &self.conf["event_stream_configuration"]; - if value.is_null() { - return None; - } - - let config: EventStreamConfiguration = - json::from_value(value.clone()).expect("Invalid json value in 'event_stream_configuration'."); - - Some(config) - } } impl Default for MmCtx { @@ -699,7 +686,15 @@ impl MmCtxBuilder { ctx.datetime = self.datetime; if let Some(conf) = self.conf { - ctx.conf = conf + ctx.conf = conf; + + let event_stream_configuration = &ctx.conf["event_stream_configuration"]; + if !event_stream_configuration.is_null() { + let event_stream_configuration: EventStreamConfiguration = + json::from_value(event_stream_configuration.clone()) + .expect("Invalid json value in 'event_stream_configuration'."); + ctx.event_stream_configuration = Some(event_stream_configuration); + } } #[cfg(target_arch = "wasm32")] diff --git a/mm2src/mm2_main/src/lp_native_dex.rs b/mm2src/mm2_main/src/lp_native_dex.rs index 7ace35fe3a..4dd2a00480 100644 --- a/mm2src/mm2_main/src/lp_native_dex.rs +++ b/mm2src/mm2_main/src/lp_native_dex.rs @@ -386,9 +386,9 @@ fn migration_1(_ctx: &MmArc) {} #[cfg(not(target_arch = "wasm32"))] fn init_event_streaming(ctx: &MmArc) { // This condition only executed if events were enabled in mm2 configuration. - if let Some(config) = ctx.event_stream_configuration() { + if let Some(config) = &ctx.event_stream_configuration { // Network event handling - NetworkEvent::new(ctx.clone()).spawn_if_active(&config); + NetworkEvent::new(ctx.clone()).spawn_if_active(config); } } diff --git a/mm2src/mm2_main/src/rpc.rs b/mm2src/mm2_main/src/rpc.rs index e59327e811..001f8bea28 100644 --- a/mm2src/mm2_main/src/rpc.rs +++ b/mm2src/mm2_main/src/rpc.rs @@ -358,7 +358,7 @@ pub extern "C" fn spawn_rpc(ctx_h: u32) { let ctx = MmArc::from_ffi_handle(ctx_h).expect("No context"); - let is_event_stream_enabled = ctx.event_stream_configuration().is_some(); + let is_event_stream_enabled = ctx.event_stream_configuration.is_some(); let make_svc_fut = move |remote_addr: SocketAddr| async move { Ok::<_, Infallible>(service_fn(move |req: Request| async move { diff --git a/mm2src/mm2_net/src/sse_handler.rs b/mm2src/mm2_net/src/sse_handler.rs index 2c7338cdc2..cb75785cd4 100644 --- a/mm2src/mm2_net/src/sse_handler.rs +++ b/mm2src/mm2_net/src/sse_handler.rs @@ -29,7 +29,7 @@ pub async fn handle_sse(request: Request, ctx_h: u32) -> Result return handle_internal_error(err).await, }; - let config = match ctx.event_stream_configuration() { + let config = match &ctx.event_stream_configuration { Some(config) => config, None => { return handle_internal_error( @@ -62,7 +62,7 @@ pub async fn handle_sse(request: Request, ctx_h: u32) -> Result Date: Tue, 29 Aug 2023 19:50:25 +0300 Subject: [PATCH 16/48] update doc-comment of `stream_channel_controller` in `MmCtx` Signed-off-by: onur-ozkan --- mm2src/mm2_core/src/mm_ctx.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm2src/mm2_core/src/mm_ctx.rs b/mm2src/mm2_core/src/mm_ctx.rs index 7f16613f50..ca66a979df 100644 --- a/mm2src/mm2_core/src/mm_ctx.rs +++ b/mm2src/mm2_core/src/mm_ctx.rs @@ -73,7 +73,7 @@ pub struct MmCtx { pub initialized: Constructible, /// True if the RPC HTTP server was started. pub rpc_started: Constructible, - /// Channels for continuously streaming data to clients via SSE. + /// Controller for continuously streaming data using streaming channels of `mm2_event_stream`. pub stream_channel_controller: Controller, /// Configuration of event streaming used for SSE. pub event_stream_configuration: Option, From 2e942af652723a8521928547879bcd390db5fe75 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Mon, 11 Sep 2023 07:54:44 +0300 Subject: [PATCH 17/48] optimize `mm2src/mm2_event_stream/src/lib.rs` Signed-off-by: onur-ozkan --- mm2src/mm2_event_stream/src/lib.rs | 32 ++++++++++++++++++++---------- mm2src/mm2_net/src/sse_handler.rs | 30 ++++++++++++---------------- 2 files changed, 34 insertions(+), 28 deletions(-) diff --git a/mm2src/mm2_event_stream/src/lib.rs b/mm2src/mm2_event_stream/src/lib.rs index de95ed5105..afa5c7e1be 100644 --- a/mm2src/mm2_event_stream/src/lib.rs +++ b/mm2src/mm2_event_stream/src/lib.rs @@ -1,12 +1,15 @@ use serde::Deserialize; +use std::collections::HashMap; -/// multi-purpose/generic event type that can easily be used over the event streaming +/// Multi-purpose/generic event type that can easily be used over the event streaming pub struct Event { _type: String, message: String, } impl Event { + /// Creates a new `Event` instance with the specified event type and message. + #[inline] pub fn new(event_type: String, message: String) -> Self { Self { _type: event_type, @@ -14,23 +17,29 @@ impl Event { } } + /// Gets the event type. + #[inline] pub fn event_type(&self) -> &str { &self._type } + /// Gets the event message. + #[inline] pub fn message(&self) -> &str { &self.message } } /// Configuration for event streaming #[derive(Deserialize)] pub struct EventStreamConfiguration { + /// The value to set for the `Access-Control-Allow-Origin` header. #[serde(default)] pub access_control_allow_origin: String, #[serde(default)] - pub active_events: Vec, + active_events: HashMap, } +/// Represents the configuration for a specific event within the event stream. #[derive(Clone, Default, Deserialize)] -pub struct EventStatus { - name: String, +pub struct EventConfig { + /// The interval in seconds at which the event should be streamed. pub stream_interval_seconds: f64, } @@ -38,18 +47,19 @@ impl Default for EventStreamConfiguration { fn default() -> Self { Self { access_control_allow_origin: String::from("*"), - active_events: vec![], + active_events: Default::default(), } } } impl EventStreamConfiguration { - pub fn get_event(&self, event_name: &str) -> Option { - self.active_events - .iter() - .find(|event| event.name == event_name) - .cloned() - } + /// Retrieves the configuration for a specific event by its name. + #[inline] + pub fn get_event(&self, event_name: &str) -> Option { self.active_events.get(event_name).cloned() } + + /// Gets the total number of active events in the configuration. + #[inline] + pub fn total_active_events(&self) -> usize { self.active_events.len() } } pub mod behaviour; diff --git a/mm2src/mm2_net/src/sse_handler.rs b/mm2src/mm2_net/src/sse_handler.rs index cb75785cd4..f57018ca04 100644 --- a/mm2src/mm2_net/src/sse_handler.rs +++ b/mm2src/mm2_net/src/sse_handler.rs @@ -7,21 +7,6 @@ pub const SSE_ENDPOINT: &str = "/event-stream"; /// Handles broadcasted messages from `mm2_event_stream` continuously. pub async fn handle_sse(request: Request, ctx_h: u32) -> Result, Infallible> { - fn get_filtered_events(request: Request) -> Vec { - let query = request.uri().query().unwrap_or(""); - let events_param = query - .split('&') - .find(|param| param.starts_with("filter=")) - .map(|param| param.trim_start_matches("filter=")) - .unwrap_or(""); - - if events_param.is_empty() { - Vec::new() - } else { - events_param.split(',').map(|event| event.to_string()).collect() - } - } - // This is only called once for per client on the initialization, // meaning this is not a resource intensive computation. let ctx = match MmArc::from_ffi_handle(ctx_h) { @@ -39,10 +24,21 @@ pub async fn handle_sse(request: Request, ctx_h: u32) -> Result { } /// guard to trace channels disconnection -pub struct ChannelGuard { +pub struct ChannelGuard { channel_id: ChannelId, controller: Controller, } /// Receiver to cleanup resources on `Drop` -pub struct GuardedReceiver { +pub struct GuardedReceiver { rx: Receiver>, #[allow(dead_code)] guard: ChannelGuard, } -impl Controller { +impl Controller { /// Creates a new channels controller pub fn new() -> Self { Default::default() } @@ -83,15 +83,19 @@ impl Default for Controller { } } -impl ChannelGuard { +impl ChannelGuard { fn new(channel_id: ChannelId, controller: Controller) -> Self { Self { channel_id, controller } } } -impl Drop for ChannelGuard { - fn drop(&mut self) { self.controller.remove_channel(&self.channel_id); } +impl Drop for ChannelGuard { + fn drop(&mut self) { + common::log::debug!("Dropping event channel with id: {}", self.channel_id); + + self.controller.remove_channel(&self.channel_id); + } } -impl GuardedReceiver { +impl GuardedReceiver { /// Receives the next event from the channel pub async fn recv(&mut self) -> Option> { self.rx.recv().await } } @@ -99,10 +103,25 @@ impl GuardedReceiver { #[cfg(test)] mod tests { use super::*; - use tokio::time::{sleep, Duration}; - #[tokio::test] - async fn test_create_channel_and_broadcast() { + common::cfg_wasm32! { + use wasm_bindgen_test::*; + wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); + } + + macro_rules! cross_test { + ($test_name:ident, $test_code:block) => { + #[cfg(not(target_arch = "wasm32"))] + #[tokio::test(flavor = "multi_thread")] + async fn $test_name() { $test_code } + + #[cfg(target_arch = "wasm32")] + #[wasm_bindgen_test] + async fn $test_name() { $test_code } + }; + } + + cross_test!(test_create_channel_and_broadcast, { let mut controller = Controller::new(); let mut guard_receiver = controller.create_channel(1); @@ -110,10 +129,9 @@ mod tests { let received_msg = guard_receiver.recv().await.unwrap(); assert_eq!(*received_msg, "Message".to_string()); - } + }); - #[tokio::test] - async fn test_multiple_channels_and_broadcast() { + cross_test!(test_multiple_channels_and_broadcast, { let mut controller = Controller::new(); let mut receivers = Vec::new(); @@ -127,10 +145,9 @@ mod tests { let received_msg = receiver.recv().await.unwrap(); assert_eq!(*received_msg, "Message".to_string()); } - } + }); - #[tokio::test] - async fn test_channel_cleanup_on_drop() { + cross_test!(test_channel_cleanup_on_drop, { let mut controller: Controller<()> = Controller::new(); let guard_receiver = controller.create_channel(1); @@ -138,13 +155,12 @@ mod tests { drop(guard_receiver); - sleep(Duration::from_millis(10)).await; // Give time for the drop to execute + common::executor::Timer::sleep(0.1).await; // Give time for the drop to execute assert_eq!(controller.num_connections(), 0); - } + }); - #[tokio::test] - async fn test_broadcast_across_channels() { + cross_test!(test_broadcast_across_channels, { let mut controller = Controller::new(); let mut receivers = Vec::new(); @@ -158,10 +174,9 @@ mod tests { let received_msg = receiver.recv().await.unwrap(); assert_eq!(*received_msg, "Message".to_string()); } - } + }); - #[tokio::test] - async fn test_multiple_messages_and_drop() { + cross_test!(test_multiple_messages_and_drop, { let mut controller = Controller::new(); let mut guard_receiver = controller.create_channel(6); @@ -188,9 +203,8 @@ mod tests { // Consume the GuardedReceiver to trigger drop and channel cleanup drop(guard_receiver); - // Sleep for a short time to allow cleanup to complete - sleep(Duration::from_millis(10)).await; + common::executor::Timer::sleep(0.1).await; // Give time for the drop to execute assert_eq!(controller.num_connections(), 0); - } + }); } diff --git a/mm2src/mm2_net/Cargo.toml b/mm2src/mm2_net/Cargo.toml index 44c22ce177..2eeb39071c 100644 --- a/mm2src/mm2_net/Cargo.toml +++ b/mm2src/mm2_net/Cargo.toml @@ -37,7 +37,7 @@ js-sys = "0.3.27" [target.'cfg(not(target_arch = "wasm32"))'.dependencies] futures-util = { version = "0.3" } -hyper = { version = "0.14.26", features = ["client", "http2", "server", "tcp"] } +hyper = { version = "0.14.26", features = ["client", "http2", "server", "tcp", "stream"] } gstuff = { version = "0.7", features = ["nightly"] } rustls = { version = "0.20", default-features = false } tokio = { version = "1.20" } From a7a2064986bc178dadb769f084963a6dfed386cc Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Fri, 15 Sep 2023 09:22:05 +0300 Subject: [PATCH 19/48] enable wasm tests to be executed with wasm-pack Signed-off-by: onur-ozkan --- mm2src/mm2_event_stream/Cargo.toml | 2 +- mm2src/mm2_event_stream/src/controller.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mm2src/mm2_event_stream/Cargo.toml b/mm2src/mm2_event_stream/Cargo.toml index 51654fbbf5..2865e0a01f 100644 --- a/mm2src/mm2_event_stream/Cargo.toml +++ b/mm2src/mm2_event_stream/Cargo.toml @@ -5,13 +5,13 @@ edition = "2021" [dependencies] async-trait = "0.1" +cfg-if = "1.0" common = { path = "../common" } parking_lot = "0.12" serde = { version = "1", features = ["derive", "rc"] } tokio = { version = "1", features = ["sync"] } [dev-dependencies] -cfg-if = "1.0" tokio = { version = "1", features = ["sync", "macros", "time", "rt"] } [target.'cfg(target_arch = "wasm32")'.dependencies] diff --git a/mm2src/mm2_event_stream/src/controller.rs b/mm2src/mm2_event_stream/src/controller.rs index 5b6effd7fa..098c6e4bb7 100644 --- a/mm2src/mm2_event_stream/src/controller.rs +++ b/mm2src/mm2_event_stream/src/controller.rs @@ -100,7 +100,7 @@ impl GuardedReceiver { pub async fn recv(&mut self) -> Option> { self.rx.recv().await } } -#[cfg(test)] +#[cfg(any(test, target_arch = "wasm32"))] mod tests { use super::*; From f6056ea5e000a43a8fe4604727cf2a8a1a56f8bf Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Mon, 18 Sep 2023 18:29:52 +0300 Subject: [PATCH 20/48] implement WASM support for event streaming Signed-off-by: onur-ozkan --- mm2src/mm2_main/src/lp_native_dex.rs | 27 ++++++++++++++++++------- mm2src/mm2_net/Cargo.toml | 2 +- mm2src/mm2_net/src/lib.rs | 4 +++- mm2src/mm2_net/src/wasm_event_stream.rs | 26 ++++++++++++++++++++++++ 4 files changed, 50 insertions(+), 9 deletions(-) create mode 100644 mm2src/mm2_net/src/wasm_event_stream.rs diff --git a/mm2src/mm2_main/src/lp_native_dex.rs b/mm2src/mm2_main/src/lp_native_dex.rs index 45f7a2f126..1f38b5852b 100644 --- a/mm2src/mm2_main/src/lp_native_dex.rs +++ b/mm2src/mm2_main/src/lp_native_dex.rs @@ -50,19 +50,24 @@ use crate::mm2::lp_ordermatch::{broadcast_maker_orders_keep_alive_loop, clean_me use crate::mm2::lp_swap::{running_swaps_num, swap_kick_starts}; use crate::mm2::rpc::spawn_rpc; +use mm2_event_stream::behaviour::EventBehaviour; +use mm2_net::network_event::NetworkEvent; + cfg_native! { use db_common::sqlite::rusqlite::Error as SqlError; - use mm2_event_stream::behaviour::EventBehaviour; use mm2_io::fs::{ensure_dir_is_writable, ensure_file_is_writable}; use mm2_net::ip_addr::myipaddr; - use mm2_net::network_event::NetworkEvent; } #[path = "lp_init/init_context.rs"] mod init_context; #[path = "lp_init/init_hw.rs"] pub mod init_hw; -#[cfg(target_arch = "wasm32")] -#[path = "lp_init/init_metamask.rs"] -pub mod init_metamask; + +cfg_wasm32! { + use mm2_net::wasm_event_stream::handle_worker_stream; + + #[path = "lp_init/init_metamask.rs"] + pub mod init_metamask; +} const NETID_7777_SEEDNODES: [&str; 3] = ["seed1.komodo.earth", "seed2.komodo.earth", "seed3.komodo.earth"]; @@ -379,7 +384,6 @@ fn migrate_db(ctx: &MmArc) -> MmInitResult<()> { #[cfg(not(target_arch = "wasm32"))] fn migration_1(_ctx: &MmArc) {} -#[cfg(not(target_arch = "wasm32"))] fn init_event_streaming(ctx: &MmArc) { // This condition only executed if events were enabled in mm2 configuration. if let Some(config) = &ctx.event_stream_configuration { @@ -388,6 +392,13 @@ fn init_event_streaming(ctx: &MmArc) { } } +#[cfg(target_arch = "wasm32")] +fn init_wasm_event_streaming(ctx: &MmArc) { + if ctx.event_stream_configuration.is_some() { + ctx.spawner().spawn(handle_worker_stream(ctx.clone())); + } +} + pub async fn lp_init_continue(ctx: MmArc) -> MmInitResult<()> { init_ordermatch_context(&ctx)?; init_p2p(ctx.clone()).await?; @@ -418,13 +429,15 @@ pub async fn lp_init_continue(ctx: MmArc) -> MmInitResult<()> { // an order and start new swap that might get started 2 times because of kick-start kick_start(ctx.clone()).await?; - #[cfg(not(target_arch = "wasm32"))] init_event_streaming(&ctx); ctx.spawner().spawn(lp_ordermatch_loop(ctx.clone())); ctx.spawner().spawn(broadcast_maker_orders_keep_alive_loop(ctx.clone())); + #[cfg(target_arch = "wasm32")] + init_wasm_event_streaming(&ctx); + ctx.spawner().spawn(clean_memory_loop(ctx.weak())); Ok(()) diff --git a/mm2src/mm2_net/Cargo.toml b/mm2src/mm2_net/Cargo.toml index 2eeb39071c..a58082ae0d 100644 --- a/mm2src/mm2_net/Cargo.toml +++ b/mm2src/mm2_net/Cargo.toml @@ -32,7 +32,7 @@ gstuff = { version = "0.7", features = ["nightly"] } wasm-bindgen = "0.2.86" wasm-bindgen-test = { version = "0.3.2" } wasm-bindgen-futures = "0.4.21" -web-sys = { version = "0.3.55", features = ["console", "CloseEvent", "DomException", "ErrorEvent", "IdbDatabase", "IdbCursor", "IdbCursorWithValue", "IdbFactory", "IdbIndex", "IdbIndexParameters", "IdbObjectStore", "IdbObjectStoreParameters", "IdbOpenDbRequest", "IdbKeyRange", "IdbTransaction", "IdbTransactionMode", "IdbVersionChangeEvent", "MessageEvent", "WebSocket"] } +web-sys = { version = "0.3.55", features = ["console", "CloseEvent", "DomException", "ErrorEvent", "IdbDatabase", "IdbCursor", "IdbCursorWithValue", "IdbFactory", "IdbIndex", "IdbIndexParameters", "IdbObjectStore", "IdbObjectStoreParameters", "IdbOpenDbRequest", "IdbKeyRange", "IdbTransaction", "IdbTransactionMode", "IdbVersionChangeEvent", "MessageEvent", "WebSocket", "Worker"] } js-sys = "0.3.27" [target.'cfg(not(target_arch = "wasm32"))'.dependencies] diff --git a/mm2src/mm2_net/src/lib.rs b/mm2src/mm2_net/src/lib.rs index ed70e093fa..c693abec17 100644 --- a/mm2src/mm2_net/src/lib.rs +++ b/mm2src/mm2_net/src/lib.rs @@ -1,11 +1,13 @@ pub mod grpc_web; +pub mod network_event; pub mod p2p; pub mod transport; #[cfg(not(target_arch = "wasm32"))] pub mod ip_addr; #[cfg(not(target_arch = "wasm32"))] pub mod native_http; #[cfg(not(target_arch = "wasm32"))] pub mod native_tls; -#[cfg(not(target_arch = "wasm32"))] pub mod network_event; #[cfg(not(target_arch = "wasm32"))] pub mod sse_handler; + +#[cfg(target_arch = "wasm32")] pub mod wasm_event_stream; #[cfg(target_arch = "wasm32")] pub mod wasm_http; #[cfg(target_arch = "wasm32")] pub mod wasm_ws; diff --git a/mm2src/mm2_net/src/wasm_event_stream.rs b/mm2src/mm2_net/src/wasm_event_stream.rs new file mode 100644 index 0000000000..1c6f8182fc --- /dev/null +++ b/mm2src/mm2_net/src/wasm_event_stream.rs @@ -0,0 +1,26 @@ +use mm2_core::mm_ctx::MmArc; +use serde_json::json; + +/// Handles broadcasted messages from `mm2_event_stream` continuously for WASM. +pub async fn handle_worker_stream(ctx: MmArc) { + let config = ctx + .event_stream_configuration + .as_ref() + .expect("Event stream configuration couldn't be found. This should never happen."); + + let mut channel_controller = ctx.stream_channel_controller.clone(); + let mut rx = channel_controller.create_channel(config.total_active_events()); + + while let Some(event) = rx.recv().await { + let data = json!({ + "_type": event.event_type(), + "message": event.message(), + }); + + let worker = web_sys::Worker::new("worker.js").expect("Missing worker.js"); + let message_js = wasm_bindgen::JsValue::from_str(&data.to_string()); + + worker.post_message(&message_js) + .expect("Incompatible browser!\nSee https://developer.mozilla.org/en-US/docs/Web/API/Worker/postMessage#browser_compatibility for details."); + } +} From 1e476d2de8b9faa2fb0d941ee5056803cc720856 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Thu, 21 Sep 2023 16:55:00 +0300 Subject: [PATCH 21/48] [WIP] concurrent balance loop controller Signed-off-by: onur-ozkan --- Cargo.lock | 1 + mm2src/coins/Cargo.toml | 1 + mm2src/coins/events.rs | 7 +++ mm2src/coins/lp_coins.rs | 65 ++++++++++++++++++++++++ mm2src/coins/tendermint/balance_event.rs | 9 ++++ mm2src/coins/tendermint/mod.rs | 1 + mm2src/mm2_main/src/lp_native_dex.rs | 4 ++ 7 files changed, 88 insertions(+) create mode 100644 mm2src/coins/events.rs create mode 100644 mm2src/coins/tendermint/balance_event.rs diff --git a/Cargo.lock b/Cargo.lock index d5cdf4fea0..df76de85cc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1026,6 +1026,7 @@ dependencies = [ "mm2_core", "mm2_db", "mm2_err_handle", + "mm2_event_stream", "mm2_git", "mm2_io", "mm2_metamask", diff --git a/mm2src/coins/Cargo.toml b/mm2src/coins/Cargo.toml index 72255359b3..2962e279d2 100644 --- a/mm2src/coins/Cargo.toml +++ b/mm2src/coins/Cargo.toml @@ -63,6 +63,7 @@ lazy_static = "1.4" libc = "0.2" mm2_core = { path = "../mm2_core" } mm2_err_handle = { path = "../mm2_err_handle" } +mm2_event_stream = { path = "../mm2_event_stream" } mm2_git = { path = "../mm2_git" } mm2_io = { path = "../mm2_io" } mm2_metrics = { path = "../mm2_metrics" } diff --git a/mm2src/coins/events.rs b/mm2src/coins/events.rs new file mode 100644 index 0000000000..1ed16d7188 --- /dev/null +++ b/mm2src/coins/events.rs @@ -0,0 +1,7 @@ +use crate::MmCoin; +use async_trait::async_trait; + +#[async_trait] +pub trait BalanceEvent: MmCoin { + async fn stream(&self); +} diff --git a/mm2src/coins/lp_coins.rs b/mm2src/coins/lp_coins.rs index 9213115d31..31aa378282 100644 --- a/mm2src/coins/lp_coins.rs +++ b/mm2src/coins/lp_coins.rs @@ -45,6 +45,7 @@ use async_trait::async_trait; use base58::FromBase58Error; use bip32::ExtendedPrivateKey; use common::custom_futures::timeout::TimeoutError; +use common::executor::Timer; use common::executor::{abortable_queue::{AbortableQueue, WeakSpawner}, AbortSettings, AbortedError, SpawnAbortable, SpawnFuture}; use common::log::{warn, LogOnError}; @@ -250,6 +251,8 @@ pub use test_coin::TestCoin; pub mod tx_history_storage; +pub mod events; + #[doc(hidden)] #[allow(unused_variables)] #[cfg(all( @@ -3411,6 +3414,68 @@ fn lp_spawn_tx_history(ctx: MmArc, coin: MmCoinEnum) -> Result<(), String> { Ok(()) } +/// Concurrent balance event controller loop for active coins +pub async fn balance_event_loop(ctx: MmArc) { + let cctx = CoinsContext::from_ctx(&ctx).unwrap(); + + // Events that are already fired + let mut event_pool: Vec = vec![]; + + loop { + let coins_mutex = cctx.coins.lock().await; + + let coins: Vec = coins_mutex + .values() + .filter_map(|coin| { + if coin.is_available.load(AtomicOrdering::Relaxed) && coin.inner.is_platform_coin() { + Some(coin.inner.clone()) + } else { + None + } + }) + .collect(); + + drop(coins_mutex); + + for coin in coins { + let ticker = coin.ticker().to_owned(); + + if event_pool.contains(&ticker) { + continue; + } + + match coin { + MmCoinEnum::Tendermint(_) => { + println!("COIN IS HERE {:?}", ticker); + }, + MmCoinEnum::TendermintToken(_) => { + unimplemented!(); + }, + MmCoinEnum::UtxoCoin(_) => todo!(), + MmCoinEnum::QtumCoin(_) => todo!(), + MmCoinEnum::Qrc20Coin(_) => todo!(), + MmCoinEnum::EthCoin(_) => todo!(), + MmCoinEnum::ZCoin(_) => todo!(), + MmCoinEnum::Bch(_) => todo!(), + MmCoinEnum::SlpToken(_) => todo!(), + MmCoinEnum::LightningCoin(_) => todo!(), + MmCoinEnum::Test(_) => todo!(), + #[cfg(all( + feature = "enable-solana", + not(target_os = "ios"), + not(target_os = "android"), + not(target_arch = "wasm32") + ))] + MmCoinEnum::SolanaCoin(_) | MmCoinEnum::SplToken(_) => todo!(), + } + + event_pool.push(ticker); + } + + Timer::sleep(5.).await; + } +} + /// NB: Returns only the enabled (aka active) coins. pub async fn lp_coinfind(ctx: &MmArc, ticker: &str) -> Result, String> { let cctx = try_s!(CoinsContext::from_ctx(ctx)); diff --git a/mm2src/coins/tendermint/balance_event.rs b/mm2src/coins/tendermint/balance_event.rs new file mode 100644 index 0000000000..60f74c2b07 --- /dev/null +++ b/mm2src/coins/tendermint/balance_event.rs @@ -0,0 +1,9 @@ +use async_trait::async_trait; + +use super::TendermintCoin; +use crate::events::BalanceEvent; + +#[async_trait] +impl BalanceEvent for TendermintCoin { + async fn stream(&self) {} +} diff --git a/mm2src/coins/tendermint/mod.rs b/mm2src/coins/tendermint/mod.rs index d480a4964e..9b8e76639e 100644 --- a/mm2src/coins/tendermint/mod.rs +++ b/mm2src/coins/tendermint/mod.rs @@ -2,6 +2,7 @@ // Useful resources // https://docs.cosmos.network/ +pub mod balance_event; mod ibc; mod iris; mod rpc; diff --git a/mm2src/mm2_main/src/lp_native_dex.rs b/mm2src/mm2_main/src/lp_native_dex.rs index 1f38b5852b..12aa19220b 100644 --- a/mm2src/mm2_main/src/lp_native_dex.rs +++ b/mm2src/mm2_main/src/lp_native_dex.rs @@ -19,6 +19,7 @@ // use bitcrypto::sha256; +use coins::balance_event_loop; use coins::register_balance_update_handler; use common::executor::{SpawnFuture, Timer}; use common::log::{info, warn}; @@ -386,10 +387,13 @@ fn migration_1(_ctx: &MmArc) {} fn init_event_streaming(ctx: &MmArc) { // This condition only executed if events were enabled in mm2 configuration. + if let Some(config) = &ctx.event_stream_configuration { // Network event handling NetworkEvent::new(ctx.clone()).spawn_if_active(config); } + + ctx.spawner().spawn(balance_event_loop(ctx.clone())); } #[cfg(target_arch = "wasm32")] From 945fece89aec7774dc4ef1ae1af9a87e40e33a21 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Thu, 21 Sep 2023 17:04:03 +0300 Subject: [PATCH 22/48] add explanation comment lines Signed-off-by: onur-ozkan --- mm2src/coins/lp_coins.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mm2src/coins/lp_coins.rs b/mm2src/coins/lp_coins.rs index 31aa378282..87c1b2dbdc 100644 --- a/mm2src/coins/lp_coins.rs +++ b/mm2src/coins/lp_coins.rs @@ -3427,6 +3427,8 @@ pub async fn balance_event_loop(ctx: MmArc) { let coins: Vec = coins_mutex .values() .filter_map(|coin| { + // We loop this over every 5 seconds, so it's not necessary to sequentially load the atomics all over + // the threads, since the cost of it is way too higher than the `AtomicOrdering::Relaxed` if coin.is_available.load(AtomicOrdering::Relaxed) && coin.inner.is_platform_coin() { Some(coin.inner.clone()) } else { @@ -3435,6 +3437,8 @@ pub async fn balance_event_loop(ctx: MmArc) { }) .collect(); + // Similar to above, we don't need to held the lock(which will block all other processes that depends + // on this lock(like coin activation)) since we loop this over continuously. drop(coins_mutex); for coin in coins { From 2d68ca94639369fa98955bdca7bdef1b326cd158 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Fri, 22 Sep 2023 11:05:09 +0300 Subject: [PATCH 23/48] create `CoinBalanceEvent` Signed-off-by: onur-ozkan --- mm2src/coins/coin_balance_event.rs | 93 ++++++++++++++++++++++++ mm2src/coins/events.rs | 7 -- mm2src/coins/lp_coins.rs | 69 +----------------- mm2src/coins/tendermint/balance_event.rs | 9 --- mm2src/coins/tendermint/mod.rs | 1 - mm2src/mm2_main/src/lp_native_dex.rs | 6 +- 6 files changed, 96 insertions(+), 89 deletions(-) create mode 100644 mm2src/coins/coin_balance_event.rs delete mode 100644 mm2src/coins/events.rs delete mode 100644 mm2src/coins/tendermint/balance_event.rs diff --git a/mm2src/coins/coin_balance_event.rs b/mm2src/coins/coin_balance_event.rs new file mode 100644 index 0000000000..1b3e0d53af --- /dev/null +++ b/mm2src/coins/coin_balance_event.rs @@ -0,0 +1,93 @@ +use crate::{CoinsContext, MmCoinEnum}; +use async_trait::async_trait; +use common::{executor::{SpawnFuture, Timer}, + log::info}; +use mm2_core::mm_ctx::MmArc; +use mm2_event_stream::{behaviour::EventBehaviour, EventStreamConfiguration}; +use std::sync::atomic::Ordering; + +pub struct CoinBalanceEvent { + ctx: MmArc, +} + +impl CoinBalanceEvent { + pub fn new(ctx: MmArc) -> Self { Self { ctx } } +} + +#[async_trait] +impl EventBehaviour for CoinBalanceEvent { + const EVENT_NAME: &'static str = "COIN_BALANCE"; + + async fn handle(self, interval: f64) { + let cctx = CoinsContext::from_ctx(&self.ctx).expect("Unexpected internal panic."); + + // Events that are already fired + let mut event_pool: Vec = vec![]; + + loop { + let coins_mutex = cctx.coins.lock().await; + + let coins: Vec = coins_mutex + .values() + .filter_map(|coin| { + // We loop this over and over, so it's not necessary to sequentially load the atomics all over + // the threads, since the cost of it is way too higher than the `AtomicOrdering::Relaxed` + if coin.is_available.load(Ordering::Relaxed) && coin.inner.is_platform_coin() { + Some(coin.inner.clone()) + } else { + None + } + }) + .collect(); + + // Similar to above, we don't need to held the lock(which will block all other processes that depends + // on this lock(like coin activation)) since we loop this over continuously. + drop(coins_mutex); + + for coin in coins { + let ticker = coin.ticker().to_owned(); + + if event_pool.contains(&ticker) { + continue; + } + + match coin { + MmCoinEnum::TendermintToken(_) => unreachable!(), + MmCoinEnum::Tendermint(_) => { + println!("TODO: here we will spawn a thread for tendermint balance handler which uses socket connection under the hood."); + }, + MmCoinEnum::UtxoCoin(_) => todo!(), + MmCoinEnum::QtumCoin(_) => todo!(), + MmCoinEnum::Qrc20Coin(_) => todo!(), + MmCoinEnum::EthCoin(_) => todo!(), + MmCoinEnum::ZCoin(_) => todo!(), + MmCoinEnum::Bch(_) => todo!(), + MmCoinEnum::SlpToken(_) => todo!(), + MmCoinEnum::LightningCoin(_) => todo!(), + MmCoinEnum::Test(_) => todo!(), + #[cfg(all( + feature = "enable-solana", + not(target_os = "ios"), + not(target_os = "android"), + not(target_arch = "wasm32") + ))] + MmCoinEnum::SolanaCoin(_) | MmCoinEnum::SplToken(_) => todo!(), + } + + event_pool.push(ticker); + } + + Timer::sleep(interval).await; + } + } + + fn spawn_if_active(self, config: &EventStreamConfiguration) { + if let Some(event) = config.get_event(Self::EVENT_NAME) { + info!( + "NETWORK event is activated with {} seconds interval.", + event.stream_interval_seconds + ); + self.ctx.spawner().spawn(self.handle(event.stream_interval_seconds)); + } + } +} diff --git a/mm2src/coins/events.rs b/mm2src/coins/events.rs deleted file mode 100644 index 1ed16d7188..0000000000 --- a/mm2src/coins/events.rs +++ /dev/null @@ -1,7 +0,0 @@ -use crate::MmCoin; -use async_trait::async_trait; - -#[async_trait] -pub trait BalanceEvent: MmCoin { - async fn stream(&self); -} diff --git a/mm2src/coins/lp_coins.rs b/mm2src/coins/lp_coins.rs index 87c1b2dbdc..2531386e5c 100644 --- a/mm2src/coins/lp_coins.rs +++ b/mm2src/coins/lp_coins.rs @@ -45,7 +45,6 @@ use async_trait::async_trait; use base58::FromBase58Error; use bip32::ExtendedPrivateKey; use common::custom_futures::timeout::TimeoutError; -use common::executor::Timer; use common::executor::{abortable_queue::{AbortableQueue, WeakSpawner}, AbortSettings, AbortedError, SpawnAbortable, SpawnFuture}; use common::log::{warn, LogOnError}; @@ -251,7 +250,7 @@ pub use test_coin::TestCoin; pub mod tx_history_storage; -pub mod events; +pub mod coin_balance_event; #[doc(hidden)] #[allow(unused_variables)] @@ -3414,72 +3413,6 @@ fn lp_spawn_tx_history(ctx: MmArc, coin: MmCoinEnum) -> Result<(), String> { Ok(()) } -/// Concurrent balance event controller loop for active coins -pub async fn balance_event_loop(ctx: MmArc) { - let cctx = CoinsContext::from_ctx(&ctx).unwrap(); - - // Events that are already fired - let mut event_pool: Vec = vec![]; - - loop { - let coins_mutex = cctx.coins.lock().await; - - let coins: Vec = coins_mutex - .values() - .filter_map(|coin| { - // We loop this over every 5 seconds, so it's not necessary to sequentially load the atomics all over - // the threads, since the cost of it is way too higher than the `AtomicOrdering::Relaxed` - if coin.is_available.load(AtomicOrdering::Relaxed) && coin.inner.is_platform_coin() { - Some(coin.inner.clone()) - } else { - None - } - }) - .collect(); - - // Similar to above, we don't need to held the lock(which will block all other processes that depends - // on this lock(like coin activation)) since we loop this over continuously. - drop(coins_mutex); - - for coin in coins { - let ticker = coin.ticker().to_owned(); - - if event_pool.contains(&ticker) { - continue; - } - - match coin { - MmCoinEnum::Tendermint(_) => { - println!("COIN IS HERE {:?}", ticker); - }, - MmCoinEnum::TendermintToken(_) => { - unimplemented!(); - }, - MmCoinEnum::UtxoCoin(_) => todo!(), - MmCoinEnum::QtumCoin(_) => todo!(), - MmCoinEnum::Qrc20Coin(_) => todo!(), - MmCoinEnum::EthCoin(_) => todo!(), - MmCoinEnum::ZCoin(_) => todo!(), - MmCoinEnum::Bch(_) => todo!(), - MmCoinEnum::SlpToken(_) => todo!(), - MmCoinEnum::LightningCoin(_) => todo!(), - MmCoinEnum::Test(_) => todo!(), - #[cfg(all( - feature = "enable-solana", - not(target_os = "ios"), - not(target_os = "android"), - not(target_arch = "wasm32") - ))] - MmCoinEnum::SolanaCoin(_) | MmCoinEnum::SplToken(_) => todo!(), - } - - event_pool.push(ticker); - } - - Timer::sleep(5.).await; - } -} - /// NB: Returns only the enabled (aka active) coins. pub async fn lp_coinfind(ctx: &MmArc, ticker: &str) -> Result, String> { let cctx = try_s!(CoinsContext::from_ctx(ctx)); diff --git a/mm2src/coins/tendermint/balance_event.rs b/mm2src/coins/tendermint/balance_event.rs deleted file mode 100644 index 60f74c2b07..0000000000 --- a/mm2src/coins/tendermint/balance_event.rs +++ /dev/null @@ -1,9 +0,0 @@ -use async_trait::async_trait; - -use super::TendermintCoin; -use crate::events::BalanceEvent; - -#[async_trait] -impl BalanceEvent for TendermintCoin { - async fn stream(&self) {} -} diff --git a/mm2src/coins/tendermint/mod.rs b/mm2src/coins/tendermint/mod.rs index 9b8e76639e..d480a4964e 100644 --- a/mm2src/coins/tendermint/mod.rs +++ b/mm2src/coins/tendermint/mod.rs @@ -2,7 +2,6 @@ // Useful resources // https://docs.cosmos.network/ -pub mod balance_event; mod ibc; mod iris; mod rpc; diff --git a/mm2src/mm2_main/src/lp_native_dex.rs b/mm2src/mm2_main/src/lp_native_dex.rs index 12aa19220b..6b0d80680f 100644 --- a/mm2src/mm2_main/src/lp_native_dex.rs +++ b/mm2src/mm2_main/src/lp_native_dex.rs @@ -19,7 +19,7 @@ // use bitcrypto::sha256; -use coins::balance_event_loop; +use coins::coin_balance_event::CoinBalanceEvent; use coins::register_balance_update_handler; use common::executor::{SpawnFuture, Timer}; use common::log::{info, warn}; @@ -389,11 +389,9 @@ fn init_event_streaming(ctx: &MmArc) { // This condition only executed if events were enabled in mm2 configuration. if let Some(config) = &ctx.event_stream_configuration { - // Network event handling NetworkEvent::new(ctx.clone()).spawn_if_active(config); + CoinBalanceEvent::new(ctx.clone()).spawn_if_active(config); } - - ctx.spawner().spawn(balance_event_loop(ctx.clone())); } #[cfg(target_arch = "wasm32")] From 61668acfbf5692126a50b8f2cad18cfa62e3dbbc Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Fri, 22 Sep 2023 12:20:27 +0300 Subject: [PATCH 24/48] impl `handle_balance_stream` for `MmCoin` trait Signed-off-by: onur-ozkan --- mm2src/coins/coin_balance_event.rs | 38 ++++++++++++--------- mm2src/coins/eth.rs | 2 ++ mm2src/coins/lightning.rs | 2 ++ mm2src/coins/lp_coins.rs | 3 ++ mm2src/coins/qrc20.rs | 2 ++ mm2src/coins/solana.rs | 2 ++ mm2src/coins/solana/spl.rs | 2 ++ mm2src/coins/tendermint/tendermint_coin.rs | 2 ++ mm2src/coins/tendermint/tendermint_token.rs | 2 ++ mm2src/coins/test_coin.rs | 2 ++ mm2src/coins/utxo/bch.rs | 2 ++ mm2src/coins/utxo/qtum.rs | 2 ++ mm2src/coins/utxo/slp.rs | 2 ++ mm2src/coins/utxo/utxo_standard.rs | 2 ++ mm2src/coins/z_coin.rs | 2 ++ 15 files changed, 51 insertions(+), 16 deletions(-) diff --git a/mm2src/coins/coin_balance_event.rs b/mm2src/coins/coin_balance_event.rs index 1b3e0d53af..2553c81fed 100644 --- a/mm2src/coins/coin_balance_event.rs +++ b/mm2src/coins/coin_balance_event.rs @@ -1,4 +1,4 @@ -use crate::{CoinsContext, MmCoinEnum}; +use crate::{CoinsContext, MmCoin, MmCoinEnum}; use async_trait::async_trait; use common::{executor::{SpawnFuture, Timer}, log::info}; @@ -32,7 +32,7 @@ impl EventBehaviour for CoinBalanceEvent { .filter_map(|coin| { // We loop this over and over, so it's not necessary to sequentially load the atomics all over // the threads, since the cost of it is way too higher than the `AtomicOrdering::Relaxed` - if coin.is_available.load(Ordering::Relaxed) && coin.inner.is_platform_coin() { + if coin.is_available.load(Ordering::Relaxed) { Some(coin.inner.clone()) } else { None @@ -44,6 +44,7 @@ impl EventBehaviour for CoinBalanceEvent { // on this lock(like coin activation)) since we loop this over continuously. drop(coins_mutex); + // Handle balance streaming concurrently for each coin for coin in coins { let ticker = coin.ticker().to_owned(); @@ -52,26 +53,31 @@ impl EventBehaviour for CoinBalanceEvent { } match coin { - MmCoinEnum::TendermintToken(_) => unreachable!(), - MmCoinEnum::Tendermint(_) => { - println!("TODO: here we will spawn a thread for tendermint balance handler which uses socket connection under the hood."); - }, - MmCoinEnum::UtxoCoin(_) => todo!(), - MmCoinEnum::QtumCoin(_) => todo!(), - MmCoinEnum::Qrc20Coin(_) => todo!(), - MmCoinEnum::EthCoin(_) => todo!(), - MmCoinEnum::ZCoin(_) => todo!(), - MmCoinEnum::Bch(_) => todo!(), - MmCoinEnum::SlpToken(_) => todo!(), - MmCoinEnum::LightningCoin(_) => todo!(), - MmCoinEnum::Test(_) => todo!(), + MmCoinEnum::UtxoCoin(inner) => self.ctx.spawner().spawn(inner.handle_balance_stream()), + MmCoinEnum::QtumCoin(inner) => self.ctx.spawner().spawn(inner.handle_balance_stream()), + MmCoinEnum::Qrc20Coin(inner) => self.ctx.spawner().spawn(inner.handle_balance_stream()), + MmCoinEnum::EthCoin(inner) => self.ctx.spawner().spawn(inner.handle_balance_stream()), + MmCoinEnum::ZCoin(inner) => self.ctx.spawner().spawn(inner.handle_balance_stream()), + MmCoinEnum::Bch(inner) => self.ctx.spawner().spawn(inner.handle_balance_stream()), + MmCoinEnum::SlpToken(inner) => self.ctx.spawner().spawn(inner.handle_balance_stream()), + MmCoinEnum::Tendermint(inner) => self.ctx.spawner().spawn(inner.handle_balance_stream()), + MmCoinEnum::TendermintToken(inner) => self.ctx.spawner().spawn(inner.handle_balance_stream()), + MmCoinEnum::LightningCoin(inner) => self.ctx.spawner().spawn(inner.handle_balance_stream()), + MmCoinEnum::Test(inner) => self.ctx.spawner().spawn(inner.handle_balance_stream()), #[cfg(all( feature = "enable-solana", not(target_os = "ios"), not(target_os = "android"), not(target_arch = "wasm32") ))] - MmCoinEnum::SolanaCoin(_) | MmCoinEnum::SplToken(_) => todo!(), + MmCoinEnum::SolanaCoin(inner) => self.ctx.spawner().spawn(inner.handle_balance_stream()), + #[cfg(all( + feature = "enable-solana", + not(target_os = "ios"), + not(target_os = "android"), + not(target_arch = "wasm32") + ))] + MmCoinEnum::SplToken(inner) => self.ctx.spawner().spawn(inner.handle_balance_stream()), } event_pool.push(ticker); diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index cba9ece714..13e8681828 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -4732,6 +4732,8 @@ impl MmCoin for EthCoin { tokens.remove(ticker); }; } + + async fn handle_balance_stream(self) { todo!() } } pub trait TryToAddress { diff --git a/mm2src/coins/lightning.rs b/mm2src/coins/lightning.rs index 979276d230..cb6e4f87d1 100644 --- a/mm2src/coins/lightning.rs +++ b/mm2src/coins/lightning.rs @@ -1452,4 +1452,6 @@ impl MmCoin for LightningCoin { fn on_disabled(&self) -> Result<(), AbortedError> { AbortableSystem::abort_all(&self.platform.abortable_system) } fn on_token_deactivated(&self, _ticker: &str) {} + + async fn handle_balance_stream(self) { todo!() } } diff --git a/mm2src/coins/lp_coins.rs b/mm2src/coins/lp_coins.rs index 2531386e5c..bbf24c4d1b 100644 --- a/mm2src/coins/lp_coins.rs +++ b/mm2src/coins/lp_coins.rs @@ -2463,6 +2463,9 @@ pub trait MmCoin: /// For Handling the removal/deactivation of token on platform coin deactivation. fn on_token_deactivated(&self, ticker: &str); + + // Handler for coin balance streaming continuously to the thread/stream channels + async fn handle_balance_stream(self); } /// The coin futures spawner. It's used to spawn futures that can be aborted immediately or after a timeout diff --git a/mm2src/coins/qrc20.rs b/mm2src/coins/qrc20.rs index c99f2d47b7..0eabe4d065 100644 --- a/mm2src/coins/qrc20.rs +++ b/mm2src/coins/qrc20.rs @@ -1465,6 +1465,8 @@ impl MmCoin for Qrc20Coin { fn on_disabled(&self) -> Result<(), AbortedError> { AbortableSystem::abort_all(&self.as_ref().abortable_system) } fn on_token_deactivated(&self, _ticker: &str) {} + + async fn handle_balance_stream(self) { todo!() } } pub fn qrc20_swap_id(time_lock: u32, secret_hash: &[u8]) -> Vec { diff --git a/mm2src/coins/solana.rs b/mm2src/coins/solana.rs index 1c4964f3a0..424e53eb6f 100644 --- a/mm2src/coins/solana.rs +++ b/mm2src/coins/solana.rs @@ -776,4 +776,6 @@ impl MmCoin for SolanaCoin { fn on_disabled(&self) -> Result<(), AbortedError> { AbortableSystem::abort_all(&self.abortable_system) } fn on_token_deactivated(&self, _ticker: &str) {} + + async fn handle_balance_stream(self) { todo!() } } diff --git a/mm2src/coins/solana/spl.rs b/mm2src/coins/solana/spl.rs index 06b43688d7..68faeb688e 100644 --- a/mm2src/coins/solana/spl.rs +++ b/mm2src/coins/solana/spl.rs @@ -570,4 +570,6 @@ impl MmCoin for SplToken { fn on_disabled(&self) -> Result<(), AbortedError> { self.conf.abortable_system.abort_all() } fn on_token_deactivated(&self, _ticker: &str) {} + + async fn handle_balance_stream(self) { todo!() } } diff --git a/mm2src/coins/tendermint/tendermint_coin.rs b/mm2src/coins/tendermint/tendermint_coin.rs index 33e48d1885..db0d745189 100644 --- a/mm2src/coins/tendermint/tendermint_coin.rs +++ b/mm2src/coins/tendermint/tendermint_coin.rs @@ -2195,6 +2195,8 @@ impl MmCoin for TendermintCoin { fn on_disabled(&self) -> Result<(), AbortedError> { AbortableSystem::abort_all(&self.abortable_system) } fn on_token_deactivated(&self, _ticker: &str) {} + + async fn handle_balance_stream(self) { todo!() } } impl MarketCoinOps for TendermintCoin { diff --git a/mm2src/coins/tendermint/tendermint_token.rs b/mm2src/coins/tendermint/tendermint_token.rs index f985ccec3c..cd473b9e76 100644 --- a/mm2src/coins/tendermint/tendermint_token.rs +++ b/mm2src/coins/tendermint/tendermint_token.rs @@ -874,4 +874,6 @@ impl MmCoin for TendermintToken { fn on_disabled(&self) -> Result<(), AbortedError> { self.abortable_system.abort_all() } fn on_token_deactivated(&self, _ticker: &str) {} + + async fn handle_balance_stream(self) { todo!() } } diff --git a/mm2src/coins/test_coin.rs b/mm2src/coins/test_coin.rs index c731b12b01..005ef46704 100644 --- a/mm2src/coins/test_coin.rs +++ b/mm2src/coins/test_coin.rs @@ -377,4 +377,6 @@ impl MmCoin for TestCoin { fn on_disabled(&self) -> Result<(), AbortedError> { Ok(()) } fn on_token_deactivated(&self, _ticker: &str) { () } + + async fn handle_balance_stream(self) { todo!() } } diff --git a/mm2src/coins/utxo/bch.rs b/mm2src/coins/utxo/bch.rs index e85f2a8d98..9025f61e85 100644 --- a/mm2src/coins/utxo/bch.rs +++ b/mm2src/coins/utxo/bch.rs @@ -1308,6 +1308,8 @@ impl MmCoin for BchCoin { tokens.remove(ticker); }; } + + async fn handle_balance_stream(self) { todo!() } } impl CoinWithDerivationMethod for BchCoin { diff --git a/mm2src/coins/utxo/qtum.rs b/mm2src/coins/utxo/qtum.rs index 8a4e8b4eae..62d43287c0 100644 --- a/mm2src/coins/utxo/qtum.rs +++ b/mm2src/coins/utxo/qtum.rs @@ -975,6 +975,8 @@ impl MmCoin for QtumCoin { fn on_disabled(&self) -> Result<(), AbortedError> { AbortableSystem::abort_all(&self.as_ref().abortable_system) } fn on_token_deactivated(&self, _ticker: &str) {} + + async fn handle_balance_stream(self) { todo!() } } #[async_trait] diff --git a/mm2src/coins/utxo/slp.rs b/mm2src/coins/utxo/slp.rs index 24ccf72448..8a84ce064c 100644 --- a/mm2src/coins/utxo/slp.rs +++ b/mm2src/coins/utxo/slp.rs @@ -1872,6 +1872,8 @@ impl MmCoin for SlpToken { fn on_disabled(&self) -> Result<(), AbortedError> { self.conf.abortable_system.abort_all() } fn on_token_deactivated(&self, _ticker: &str) {} + + async fn handle_balance_stream(self) { todo!() } } #[async_trait] diff --git a/mm2src/coins/utxo/utxo_standard.rs b/mm2src/coins/utxo/utxo_standard.rs index 431faaee86..5fd349f857 100644 --- a/mm2src/coins/utxo/utxo_standard.rs +++ b/mm2src/coins/utxo/utxo_standard.rs @@ -793,6 +793,8 @@ impl MmCoin for UtxoStandardCoin { fn on_disabled(&self) -> Result<(), AbortedError> { AbortableSystem::abort_all(&self.as_ref().abortable_system) } fn on_token_deactivated(&self, _ticker: &str) {} + + async fn handle_balance_stream(self) { todo!() } } #[async_trait] diff --git a/mm2src/coins/z_coin.rs b/mm2src/coins/z_coin.rs index d838db26f6..98989a57e8 100644 --- a/mm2src/coins/z_coin.rs +++ b/mm2src/coins/z_coin.rs @@ -1756,6 +1756,8 @@ impl MmCoin for ZCoin { fn on_disabled(&self) -> Result<(), AbortedError> { AbortableSystem::abort_all(&self.as_ref().abortable_system) } fn on_token_deactivated(&self, _ticker: &str) {} + + async fn handle_balance_stream(self) { todo!() } } #[async_trait] From 619bac8c9bfa7234cefd30253a4c29cd9e1ffbba Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Fri, 22 Sep 2023 19:13:01 +0300 Subject: [PATCH 25/48] update interval rule for coin balance event Signed-off-by: onur-ozkan --- mm2src/coins/coin_balance_event.rs | 33 +++++++++++---------- mm2src/coins/eth.rs | 2 +- mm2src/coins/lightning.rs | 2 +- mm2src/coins/lp_coins.rs | 2 +- mm2src/coins/qrc20.rs | 2 +- mm2src/coins/solana.rs | 2 +- mm2src/coins/solana/spl.rs | 2 +- mm2src/coins/tendermint/tendermint_coin.rs | 2 +- mm2src/coins/tendermint/tendermint_token.rs | 2 +- mm2src/coins/test_coin.rs | 2 +- mm2src/coins/utxo/bch.rs | 2 +- mm2src/coins/utxo/qtum.rs | 2 +- mm2src/coins/utxo/slp.rs | 2 +- mm2src/coins/utxo/utxo_standard.rs | 2 +- mm2src/coins/z_coin.rs | 2 +- 15 files changed, 32 insertions(+), 29 deletions(-) diff --git a/mm2src/coins/coin_balance_event.rs b/mm2src/coins/coin_balance_event.rs index 2553c81fed..520228c84a 100644 --- a/mm2src/coins/coin_balance_event.rs +++ b/mm2src/coins/coin_balance_event.rs @@ -53,44 +53,47 @@ impl EventBehaviour for CoinBalanceEvent { } match coin { - MmCoinEnum::UtxoCoin(inner) => self.ctx.spawner().spawn(inner.handle_balance_stream()), - MmCoinEnum::QtumCoin(inner) => self.ctx.spawner().spawn(inner.handle_balance_stream()), - MmCoinEnum::Qrc20Coin(inner) => self.ctx.spawner().spawn(inner.handle_balance_stream()), - MmCoinEnum::EthCoin(inner) => self.ctx.spawner().spawn(inner.handle_balance_stream()), - MmCoinEnum::ZCoin(inner) => self.ctx.spawner().spawn(inner.handle_balance_stream()), - MmCoinEnum::Bch(inner) => self.ctx.spawner().spawn(inner.handle_balance_stream()), - MmCoinEnum::SlpToken(inner) => self.ctx.spawner().spawn(inner.handle_balance_stream()), - MmCoinEnum::Tendermint(inner) => self.ctx.spawner().spawn(inner.handle_balance_stream()), - MmCoinEnum::TendermintToken(inner) => self.ctx.spawner().spawn(inner.handle_balance_stream()), - MmCoinEnum::LightningCoin(inner) => self.ctx.spawner().spawn(inner.handle_balance_stream()), - MmCoinEnum::Test(inner) => self.ctx.spawner().spawn(inner.handle_balance_stream()), + MmCoinEnum::UtxoCoin(inner) => self.ctx.spawner().spawn(inner.handle_balance_stream(interval)), + MmCoinEnum::QtumCoin(inner) => self.ctx.spawner().spawn(inner.handle_balance_stream(interval)), + MmCoinEnum::Qrc20Coin(inner) => self.ctx.spawner().spawn(inner.handle_balance_stream(interval)), + MmCoinEnum::EthCoin(inner) => self.ctx.spawner().spawn(inner.handle_balance_stream(interval)), + MmCoinEnum::ZCoin(inner) => self.ctx.spawner().spawn(inner.handle_balance_stream(interval)), + MmCoinEnum::Bch(inner) => self.ctx.spawner().spawn(inner.handle_balance_stream(interval)), + MmCoinEnum::SlpToken(inner) => self.ctx.spawner().spawn(inner.handle_balance_stream(interval)), + MmCoinEnum::Tendermint(inner) => self.ctx.spawner().spawn(inner.handle_balance_stream(interval)), + MmCoinEnum::TendermintToken(inner) => { + self.ctx.spawner().spawn(inner.handle_balance_stream(interval)) + }, + MmCoinEnum::LightningCoin(inner) => self.ctx.spawner().spawn(inner.handle_balance_stream(interval)), + MmCoinEnum::Test(inner) => self.ctx.spawner().spawn(inner.handle_balance_stream(interval)), #[cfg(all( feature = "enable-solana", not(target_os = "ios"), not(target_os = "android"), not(target_arch = "wasm32") ))] - MmCoinEnum::SolanaCoin(inner) => self.ctx.spawner().spawn(inner.handle_balance_stream()), + MmCoinEnum::SolanaCoin(inner) => self.ctx.spawner().spawn(inner.handle_balance_stream(interval)), #[cfg(all( feature = "enable-solana", not(target_os = "ios"), not(target_os = "android"), not(target_arch = "wasm32") ))] - MmCoinEnum::SplToken(inner) => self.ctx.spawner().spawn(inner.handle_balance_stream()), + MmCoinEnum::SplToken(inner) => self.ctx.spawner().spawn(inner.handle_balance_stream(interval)), } event_pool.push(ticker); } - Timer::sleep(interval).await; + Timer::sleep(5.).await; } } fn spawn_if_active(self, config: &EventStreamConfiguration) { if let Some(event) = config.get_event(Self::EVENT_NAME) { info!( - "NETWORK event is activated with {} seconds interval.", + "{} event is activated. `stream_interval_seconds`({}) has no effect for this event.", + Self::EVENT_NAME, event.stream_interval_seconds ); self.ctx.spawner().spawn(self.handle(event.stream_interval_seconds)); diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 13e8681828..459c43585c 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -4733,7 +4733,7 @@ impl MmCoin for EthCoin { }; } - async fn handle_balance_stream(self) { todo!() } + async fn handle_balance_stream(self, _interval: f64) { todo!() } } pub trait TryToAddress { diff --git a/mm2src/coins/lightning.rs b/mm2src/coins/lightning.rs index cb6e4f87d1..070d654e28 100644 --- a/mm2src/coins/lightning.rs +++ b/mm2src/coins/lightning.rs @@ -1453,5 +1453,5 @@ impl MmCoin for LightningCoin { fn on_token_deactivated(&self, _ticker: &str) {} - async fn handle_balance_stream(self) { todo!() } + async fn handle_balance_stream(self, _interval: f64) { todo!() } } diff --git a/mm2src/coins/lp_coins.rs b/mm2src/coins/lp_coins.rs index bbf24c4d1b..f7176e9c90 100644 --- a/mm2src/coins/lp_coins.rs +++ b/mm2src/coins/lp_coins.rs @@ -2465,7 +2465,7 @@ pub trait MmCoin: fn on_token_deactivated(&self, ticker: &str); // Handler for coin balance streaming continuously to the thread/stream channels - async fn handle_balance_stream(self); + async fn handle_balance_stream(self, interval: f64); } /// The coin futures spawner. It's used to spawn futures that can be aborted immediately or after a timeout diff --git a/mm2src/coins/qrc20.rs b/mm2src/coins/qrc20.rs index 0eabe4d065..1d0a93ee27 100644 --- a/mm2src/coins/qrc20.rs +++ b/mm2src/coins/qrc20.rs @@ -1466,7 +1466,7 @@ impl MmCoin for Qrc20Coin { fn on_token_deactivated(&self, _ticker: &str) {} - async fn handle_balance_stream(self) { todo!() } + async fn handle_balance_stream(self, _interval: f64) { todo!() } } pub fn qrc20_swap_id(time_lock: u32, secret_hash: &[u8]) -> Vec { diff --git a/mm2src/coins/solana.rs b/mm2src/coins/solana.rs index 424e53eb6f..c2b589d0a9 100644 --- a/mm2src/coins/solana.rs +++ b/mm2src/coins/solana.rs @@ -777,5 +777,5 @@ impl MmCoin for SolanaCoin { fn on_token_deactivated(&self, _ticker: &str) {} - async fn handle_balance_stream(self) { todo!() } + async fn handle_balance_stream(self, _interval: f64) { todo!() } } diff --git a/mm2src/coins/solana/spl.rs b/mm2src/coins/solana/spl.rs index 68faeb688e..a56b8447df 100644 --- a/mm2src/coins/solana/spl.rs +++ b/mm2src/coins/solana/spl.rs @@ -571,5 +571,5 @@ impl MmCoin for SplToken { fn on_token_deactivated(&self, _ticker: &str) {} - async fn handle_balance_stream(self) { todo!() } + async fn handle_balance_stream(self, _interval: f64) { todo!() } } diff --git a/mm2src/coins/tendermint/tendermint_coin.rs b/mm2src/coins/tendermint/tendermint_coin.rs index db0d745189..274ba64d26 100644 --- a/mm2src/coins/tendermint/tendermint_coin.rs +++ b/mm2src/coins/tendermint/tendermint_coin.rs @@ -2196,7 +2196,7 @@ impl MmCoin for TendermintCoin { fn on_token_deactivated(&self, _ticker: &str) {} - async fn handle_balance_stream(self) { todo!() } + async fn handle_balance_stream(self, _interval: f64) { todo!() } } impl MarketCoinOps for TendermintCoin { diff --git a/mm2src/coins/tendermint/tendermint_token.rs b/mm2src/coins/tendermint/tendermint_token.rs index cd473b9e76..cffc7f74cf 100644 --- a/mm2src/coins/tendermint/tendermint_token.rs +++ b/mm2src/coins/tendermint/tendermint_token.rs @@ -875,5 +875,5 @@ impl MmCoin for TendermintToken { fn on_token_deactivated(&self, _ticker: &str) {} - async fn handle_balance_stream(self) { todo!() } + async fn handle_balance_stream(self, _interval: f64) { todo!() } } diff --git a/mm2src/coins/test_coin.rs b/mm2src/coins/test_coin.rs index 005ef46704..13b6c30f12 100644 --- a/mm2src/coins/test_coin.rs +++ b/mm2src/coins/test_coin.rs @@ -378,5 +378,5 @@ impl MmCoin for TestCoin { fn on_token_deactivated(&self, _ticker: &str) { () } - async fn handle_balance_stream(self) { todo!() } + async fn handle_balance_stream(self, _interval: f64) { todo!() } } diff --git a/mm2src/coins/utxo/bch.rs b/mm2src/coins/utxo/bch.rs index 9025f61e85..0bb23c526d 100644 --- a/mm2src/coins/utxo/bch.rs +++ b/mm2src/coins/utxo/bch.rs @@ -1309,7 +1309,7 @@ impl MmCoin for BchCoin { }; } - async fn handle_balance_stream(self) { todo!() } + async fn handle_balance_stream(self, _interval: f64) { todo!() } } impl CoinWithDerivationMethod for BchCoin { diff --git a/mm2src/coins/utxo/qtum.rs b/mm2src/coins/utxo/qtum.rs index 62d43287c0..5da6be8757 100644 --- a/mm2src/coins/utxo/qtum.rs +++ b/mm2src/coins/utxo/qtum.rs @@ -976,7 +976,7 @@ impl MmCoin for QtumCoin { fn on_token_deactivated(&self, _ticker: &str) {} - async fn handle_balance_stream(self) { todo!() } + async fn handle_balance_stream(self, _interval: f64) { todo!() } } #[async_trait] diff --git a/mm2src/coins/utxo/slp.rs b/mm2src/coins/utxo/slp.rs index 8a84ce064c..4ae91e3269 100644 --- a/mm2src/coins/utxo/slp.rs +++ b/mm2src/coins/utxo/slp.rs @@ -1873,7 +1873,7 @@ impl MmCoin for SlpToken { fn on_token_deactivated(&self, _ticker: &str) {} - async fn handle_balance_stream(self) { todo!() } + async fn handle_balance_stream(self, _interval: f64) { todo!() } } #[async_trait] diff --git a/mm2src/coins/utxo/utxo_standard.rs b/mm2src/coins/utxo/utxo_standard.rs index 5fd349f857..11d1c9b890 100644 --- a/mm2src/coins/utxo/utxo_standard.rs +++ b/mm2src/coins/utxo/utxo_standard.rs @@ -794,7 +794,7 @@ impl MmCoin for UtxoStandardCoin { fn on_token_deactivated(&self, _ticker: &str) {} - async fn handle_balance_stream(self) { todo!() } + async fn handle_balance_stream(self, _interval: f64) { todo!() } } #[async_trait] diff --git a/mm2src/coins/z_coin.rs b/mm2src/coins/z_coin.rs index 98989a57e8..4d732a3f8e 100644 --- a/mm2src/coins/z_coin.rs +++ b/mm2src/coins/z_coin.rs @@ -1757,7 +1757,7 @@ impl MmCoin for ZCoin { fn on_token_deactivated(&self, _ticker: &str) {} - async fn handle_balance_stream(self) { todo!() } + async fn handle_balance_stream(self, _interval: f64) { todo!() } } #[async_trait] From eaac0c1aea2584872741f471c0d9518a5812c62f Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Mon, 25 Sep 2023 19:19:10 +0300 Subject: [PATCH 26/48] save dev state Signed-off-by: onur-ozkan --- Cargo.lock | 75 +++++++++++++++++----- mm2src/coins/Cargo.toml | 1 + mm2src/coins/tendermint/tendermint_coin.rs | 36 ++++++++++- 3 files changed, 93 insertions(+), 19 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index df76de85cc..bc685f79d7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1073,6 +1073,7 @@ dependencies = [ "tiny-bip39", "tokio", "tokio-rustls", + "tokio-tungstenite", "tonic", "tonic-build", "url", @@ -2386,9 +2387,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.21" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010" +checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" dependencies = [ "futures-core", "futures-sink", @@ -2396,9 +2397,9 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.21" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" +checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" [[package]] name = "futures-cpupool" @@ -2424,19 +2425,19 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.21" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b" +checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" [[package]] name = "futures-macro" -version = "0.3.21" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512" +checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2 1.0.58", "quote 1.0.27", - "syn 1.0.95", + "syn 2.0.16", ] [[package]] @@ -2463,15 +2464,15 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.21" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868" +checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" [[package]] name = "futures-task" -version = "0.3.21" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a" +checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" [[package]] name = "futures-timer" @@ -2485,9 +2486,9 @@ dependencies = [ [[package]] name = "futures-util" -version = "0.3.21" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a" +checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" dependencies = [ "futures 0.1.29", "futures-channel", @@ -6389,6 +6390,17 @@ dependencies = [ "opaque-debug 0.3.0", ] +[[package]] +name = "sha1" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "006769ba83e921b3085caa8334186b00cf92b4cb1a6cf4632fbccc8eff5c7549" +dependencies = [ + "cfg-if 1.0.0", + "cpufeatures 0.2.1", + "digest 0.10.3", +] + [[package]] name = "sha2" version = "0.8.2" @@ -6722,7 +6734,7 @@ dependencies = [ "solana-vote-program", "thiserror", "tokio", - "tungstenite", + "tungstenite 0.16.0", "url", ] @@ -7962,6 +7974,18 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-tungstenite" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec509ac96e9a0c43427c74f003127d953a265737636129424288d27cb5c4b12c" +dependencies = [ + "futures-util", + "log 0.4.17", + "tokio", + "tungstenite 0.19.0", +] + [[package]] name = "tokio-util" version = "0.7.2" @@ -8255,6 +8279,25 @@ dependencies = [ "webpki-roots", ] +[[package]] +name = "tungstenite" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15fba1a6d6bb030745759a9a2a588bfe8490fc8b4751a277db3a0be1c9ebbf67" +dependencies = [ + "byteorder 1.4.3", + "bytes 1.1.0", + "data-encoding", + "http 0.2.7", + "httparse", + "log 0.4.17", + "rand 0.8.4", + "sha1", + "thiserror", + "url", + "utf-8", +] + [[package]] name = "typenum" version = "1.15.0" diff --git a/mm2src/coins/Cargo.toml b/mm2src/coins/Cargo.toml index 2962e279d2..f7859bade7 100644 --- a/mm2src/coins/Cargo.toml +++ b/mm2src/coins/Cargo.toml @@ -98,6 +98,7 @@ utxo_signer = { path = "utxo_signer" } # using the same version as cosmrs tendermint-rpc = { version = "=0.23.7", default-features = false } tiny-bip39 = "0.8.0" +tokio-tungstenite = "0.19.0" url = { version = "2.2.2", features = ["serde"] } uuid = { version = "1.2.2", features = ["fast-rng", "serde", "v4"] } # One of web3 dependencies is the old `tokio-uds 0.1.7` which fails cross-compiling to ARM. diff --git a/mm2src/coins/tendermint/tendermint_coin.rs b/mm2src/coins/tendermint/tendermint_coin.rs index 274ba64d26..6dd4d300cd 100644 --- a/mm2src/coins/tendermint/tendermint_coin.rs +++ b/mm2src/coins/tendermint/tendermint_coin.rs @@ -55,7 +55,7 @@ use crypto::{Secp256k1Secret, StandardHDCoinAddress, StandardHDPathToCoin}; use derive_more::Display; use futures::future::try_join_all; use futures::lock::Mutex as AsyncMutex; -use futures::{FutureExt, TryFutureExt}; +use futures::{FutureExt, SinkExt, StreamExt, TryFutureExt}; use futures01::Future; use hex::FromHexError; use itertools::Itertools; @@ -71,7 +71,7 @@ use rpc::v1::types::Bytes as BytesJson; use serde_json::{self as json, Value as Json}; use std::collections::HashMap; use std::convert::TryFrom; -use std::ops::Deref; +use std::ops::{Deref, DerefMut}; use std::str::FromStr; use std::sync::{Arc, Mutex}; use std::time::Duration; @@ -2196,7 +2196,37 @@ impl MmCoin for TendermintCoin { fn on_token_deactivated(&self, _ticker: &str) {} - async fn handle_balance_stream(self, _interval: f64) { todo!() } + async fn handle_balance_stream(self, _interval: f64) { + let ws_conn = "ws://35.234.10.84:26657/websocket"; + let (mut socket, _) = tokio_tungstenite::connect_async(ws_conn).await.unwrap(); + + let q = json!({ + "jsonrpc": "2.0", + "method": "subscribe", + "id": 0, + "params": { + "query": "coin_received.receiver = 'iaa1e0rx87mdj79zejewuc4jg7ql9ud2286g2us8f2'" + } + }); + let msg = tokio_tungstenite::tungstenite::Message::text(q.to_string()).into(); + socket.send(msg).await.unwrap(); + + let q = json!({ + "jsonrpc": "2.0", + "method": "subscribe", + "id": 0, + "params": { + "query": "coin_spent.spender = 'iaa1e0rx87mdj79zejewuc4jg7ql9ud2286g2us8f2'" + } + }); + let msg = tokio_tungstenite::tungstenite::Message::text(q.to_string()).into(); + socket.send(msg).await.unwrap(); + + while let Some(message) = socket.next().await { + let message = message.unwrap(); + println!("AAAAAAAAAAAAAAAAA {:?}", message); + } + } } impl MarketCoinOps for TendermintCoin { From 212f4dd5f6b6d426afbd01861bcf234f68854bc3 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Mon, 25 Sep 2023 21:07:41 +0300 Subject: [PATCH 27/48] save dev state Signed-off-by: onur-ozkan --- mm2src/coins/tendermint/tendermint_coin.rs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/mm2src/coins/tendermint/tendermint_coin.rs b/mm2src/coins/tendermint/tendermint_coin.rs index 6dd4d300cd..0e9a907793 100644 --- a/mm2src/coins/tendermint/tendermint_coin.rs +++ b/mm2src/coins/tendermint/tendermint_coin.rs @@ -71,7 +71,7 @@ use rpc::v1::types::Bytes as BytesJson; use serde_json::{self as json, Value as Json}; use std::collections::HashMap; use std::convert::TryFrom; -use std::ops::{Deref, DerefMut}; +use std::ops::Deref; use std::str::FromStr; use std::sync::{Arc, Mutex}; use std::time::Duration; @@ -2223,8 +2223,16 @@ impl MmCoin for TendermintCoin { socket.send(msg).await.unwrap(); while let Some(message) = socket.next().await { - let message = message.unwrap(); - println!("AAAAAAAAAAAAAAAAA {:?}", message); + let msg = match message.unwrap() { + tokio_tungstenite::tungstenite::Message::Text(s) => s, + _ => String::new(), + }; + + if let Ok(parsed) = serde_json::from_str::(&msg) { + let transfers = &parsed["result"]["events"]["transfer.amount"]; + + println!("AAAAAAAAAAAAAAAAA {:?}", transfers); + } } } } From 188dadec4029b3d2185427abb989bbcd2e46b468 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Mon, 25 Sep 2023 21:39:04 +0300 Subject: [PATCH 28/48] WIP parse denoms from ws events Signed-off-by: onur-ozkan --- mm2src/coins/tendermint/tendermint_coin.rs | 23 +++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/mm2src/coins/tendermint/tendermint_coin.rs b/mm2src/coins/tendermint/tendermint_coin.rs index 0e9a907793..660bc7b2aa 100644 --- a/mm2src/coins/tendermint/tendermint_coin.rs +++ b/mm2src/coins/tendermint/tendermint_coin.rs @@ -2208,7 +2208,7 @@ impl MmCoin for TendermintCoin { "query": "coin_received.receiver = 'iaa1e0rx87mdj79zejewuc4jg7ql9ud2286g2us8f2'" } }); - let msg = tokio_tungstenite::tungstenite::Message::text(q.to_string()).into(); + let msg = tokio_tungstenite::tungstenite::Message::text(q.to_string()); socket.send(msg).await.unwrap(); let q = json!({ @@ -2219,7 +2219,7 @@ impl MmCoin for TendermintCoin { "query": "coin_spent.spender = 'iaa1e0rx87mdj79zejewuc4jg7ql9ud2286g2us8f2'" } }); - let msg = tokio_tungstenite::tungstenite::Message::text(q.to_string()).into(); + let msg = tokio_tungstenite::tungstenite::Message::text(q.to_string()); socket.send(msg).await.unwrap(); while let Some(message) = socket.next().await { @@ -2229,9 +2229,22 @@ impl MmCoin for TendermintCoin { }; if let Ok(parsed) = serde_json::from_str::(&msg) { - let transfers = &parsed["result"]["events"]["transfer.amount"]; - - println!("AAAAAAAAAAAAAAAAA {:?}", transfers); + let transfers: Vec = + json::from_value(parsed["result"]["events"]["transfer.amount"].clone()).unwrap_or_default(); + + let mut denoms: Vec = transfers + .iter() + .map(|t| { + let amount: String = t.chars().take_while(|c| c.is_numeric()).collect(); + let denom = &t[amount.len()..]; + denom.to_owned() + }) + .collect(); + + denoms.dedup(); + drop_mutability!(denoms); + + println!("DENOMS {:?}", denoms); } } } From f95568ca1d950418ac164f05e6ca0968520c28f4 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Tue, 26 Sep 2023 00:53:56 +0300 Subject: [PATCH 29/48] impl address handling and TLS support Signed-off-by: onur-ozkan --- Cargo.lock | 242 ++++++++++++++++-- mm2src/coins/Cargo.toml | 2 +- .../tendermint/rpc/tendermint_native_rpc.rs | 10 + mm2src/coins/tendermint/tendermint_coin.rs | 42 ++- mm2src/coins/tendermint/tendermint_token.rs | 6 +- 5 files changed, 268 insertions(+), 34 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bc685f79d7..e3189bb009 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -293,7 +293,7 @@ checksum = "acee9fd5073ab6b045a275b3e709c163dd36c90685219cb21804a147b58dba43" dependencies = [ "async-trait", "axum-core", - "bitflags", + "bitflags 1.3.2", "bytes 1.1.0", "futures-util", "http 0.2.7", @@ -502,6 +502,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" + [[package]] name = "bitvec" version = "0.18.5" @@ -930,7 +936,7 @@ checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" dependencies = [ "ansi_term", "atty", - "bitflags", + "bitflags 1.3.2", "strsim", "textwrap", "unicode-width", @@ -943,7 +949,7 @@ version = "0.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -952,7 +958,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4344512281c643ae7638bbabc3af17a11307803ec8f0fcad9fae512a8bf36467" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -1235,6 +1241,16 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" +[[package]] +name = "core-foundation" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "core-foundation-sys" version = "0.8.3" @@ -2316,6 +2332,21 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + [[package]] name = "form_urlencoded" version = "1.0.1" @@ -3297,7 +3328,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6607c62aa161d23d17a9072cc5da0be67cdfc89d3afb1e8d9c842bebc2525ffe" dependencies = [ "arrayvec 0.5.1", - "bitflags", + "bitflags 1.3.2", "cfg-if 1.0.0", "ryu", "static_assertions", @@ -4564,6 +4595,24 @@ dependencies = [ "unsigned-varint 0.7.1", ] +[[package]] +name = "native-tls" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" +dependencies = [ + "lazy_static", + "libc", + "log 0.4.17", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + [[package]] name = "nibble_vec" version = "0.1.0" @@ -4579,7 +4628,7 @@ version = "0.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f866317acbd3a240710c63f065ffb1e4fd466259045ccb504130b7f668f35c6" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cc", "cfg-if 1.0.0", "libc", @@ -4734,6 +4783,50 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +[[package]] +name = "openssl" +version = "0.10.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bac25ee399abb46215765b1cb35bc0212377e58a061560d8b29b024fd0430e7c" +dependencies = [ + "bitflags 2.4.0", + "cfg-if 1.0.0", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2 1.0.58", + "quote 1.0.27", + "syn 2.0.16", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-sys" +version = "0.9.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db4d56a4c0478783083cfafcc42493dd4a981d41669da64b4572a2a089b51b1d" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + [[package]] name = "ordered-float" version = "3.7.0" @@ -5643,7 +5736,7 @@ version = "10.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c49596760fce12ca21550ac21dc5a9617b2ea4b6e0aa7d8dab8ff2824fc2bba" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -5704,7 +5797,7 @@ version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -5940,7 +6033,7 @@ version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "01e213bc3ecb39ac32e81e51ebe31fd888a940515173e3a18a35f8c6e896422a" dependencies = [ - "bitflags", + "bitflags 1.3.2", "fallible-iterator", "fallible-streaming-iterator", "hashlink", @@ -6009,7 +6102,7 @@ version = "0.36.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd5c6ff11fecd55b40746d1995a02f2eb375bf8c00d192d521ee09f42bef37bc" dependencies = [ - "bitflags", + "bitflags 1.3.2", "errno", "io-lifetimes", "libc", @@ -6115,6 +6208,15 @@ dependencies = [ "syn 1.0.95", ] +[[package]] +name = "schannel" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" +dependencies = [ + "windows-sys 0.48.0", +] + [[package]] name = "scoped-tls" version = "1.0.0" @@ -6227,6 +6329,29 @@ dependencies = [ "zeroize", ] +[[package]] +name = "security-framework" +version = "2.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "semver" version = "0.9.0" @@ -6910,7 +7035,7 @@ checksum = "0a463f546a2f5842d35974bd4691ae5ceded6785ec24db440f773723f6ce4e11" dependencies = [ "base64 0.13.0", "bincode", - "bitflags", + "bitflags 1.3.2", "blake3", "borsh", "borsh-derive", @@ -7064,7 +7189,7 @@ dependencies = [ "assert_matches", "base64 0.13.0", "bincode", - "bitflags", + "bitflags 1.3.2", "borsh", "bs58", "bytemuck", @@ -7212,7 +7337,7 @@ version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77963e2aa8fadb589118c3aede2e78b6c4bcf1c01d588fbf33e915b390825fbd" dependencies = [ - "bitflags", + "bitflags 1.3.2", "byteorder 1.4.3", "hash-db", "hash256-std-hasher", @@ -7952,6 +8077,16 @@ dependencies = [ "syn 1.0.95", ] +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + [[package]] name = "tokio-rustls" version = "0.23.2" @@ -7982,7 +8117,9 @@ checksum = "ec509ac96e9a0c43427c74f003127d953a265737636129424288d27cb5c4b12c" dependencies = [ "futures-util", "log 0.4.17", + "native-tls", "tokio", + "tokio-native-tls", "tungstenite 0.19.0", ] @@ -8084,7 +8221,7 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d342c6d58709c0a6d48d48dabbb62d4ef955cf5f0f3bbfd845838e7ae88dbae" dependencies = [ - "bitflags", + "bitflags 1.3.2", "bytes 1.1.0", "futures-core", "futures-util", @@ -8291,6 +8428,7 @@ dependencies = [ "http 0.2.7", "httparse", "log 0.4.17", + "native-tls", "rand 0.8.4", "sha1", "thiserror", @@ -8792,12 +8930,12 @@ version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" dependencies = [ - "windows_aarch64_gnullvm", + "windows_aarch64_gnullvm 0.42.1", "windows_aarch64_msvc 0.42.1", "windows_i686_gnu 0.42.1", "windows_i686_msvc 0.42.1", "windows_x86_64_gnu 0.42.1", - "windows_x86_64_gnullvm", + "windows_x86_64_gnullvm 0.42.1", "windows_x86_64_msvc 0.42.1", ] @@ -8807,7 +8945,16 @@ version = "0.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" dependencies = [ - "windows-targets", + "windows-targets 0.42.1", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", ] [[package]] @@ -8816,21 +8963,42 @@ version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7" dependencies = [ - "windows_aarch64_gnullvm", + "windows_aarch64_gnullvm 0.42.1", "windows_aarch64_msvc 0.42.1", "windows_i686_gnu 0.42.1", "windows_i686_msvc 0.42.1", "windows_x86_64_gnu 0.42.1", - "windows_x86_64_gnullvm", + "windows_x86_64_gnullvm 0.42.1", "windows_x86_64_msvc 0.42.1", ] +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + [[package]] name = "windows_aarch64_gnullvm" version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + [[package]] name = "windows_aarch64_msvc" version = "0.32.0" @@ -8843,6 +9011,12 @@ version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + [[package]] name = "windows_i686_gnu" version = "0.32.0" @@ -8855,6 +9029,12 @@ version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + [[package]] name = "windows_i686_msvc" version = "0.32.0" @@ -8867,6 +9047,12 @@ version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + [[package]] name = "windows_x86_64_gnu" version = "0.32.0" @@ -8879,12 +9065,24 @@ version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + [[package]] name = "windows_x86_64_gnullvm" version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + [[package]] name = "windows_x86_64_msvc" version = "0.32.0" @@ -8897,6 +9095,12 @@ version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + [[package]] name = "winreg" version = "0.7.0" diff --git a/mm2src/coins/Cargo.toml b/mm2src/coins/Cargo.toml index f7859bade7..b892ef0bad 100644 --- a/mm2src/coins/Cargo.toml +++ b/mm2src/coins/Cargo.toml @@ -98,7 +98,7 @@ utxo_signer = { path = "utxo_signer" } # using the same version as cosmrs tendermint-rpc = { version = "=0.23.7", default-features = false } tiny-bip39 = "0.8.0" -tokio-tungstenite = "0.19.0" +tokio-tungstenite = { version = "0.19.0", features = ["native-tls"]} url = { version = "2.2.2", features = ["serde"] } uuid = { version = "1.2.2", features = ["fast-rng", "serde", "v4"] } # One of web3 dependencies is the old `tokio-uds 0.1.7` which fails cross-compiling to ARM. diff --git a/mm2src/coins/tendermint/rpc/tendermint_native_rpc.rs b/mm2src/coins/tendermint/rpc/tendermint_native_rpc.rs index dde181b3e3..4904a2ed30 100644 --- a/mm2src/coins/tendermint/rpc/tendermint_native_rpc.rs +++ b/mm2src/coins/tendermint/rpc/tendermint_native_rpc.rs @@ -309,6 +309,9 @@ impl HttpClient { }, }) } + + #[inline] + pub fn uri(&self) -> http::Uri { self.inner.uri() } } #[async_trait] @@ -481,6 +484,13 @@ mod sealed { HttpClient::Https(c) => c.perform(request).await, } } + + pub fn uri(&self) -> Uri { + match self { + HttpClient::Http(client) => client.uri.clone(), + HttpClient::Https(client) => client.uri.clone(), + } + } } async fn response_to_string(response: hyper::Response) -> Result { diff --git a/mm2src/coins/tendermint/tendermint_coin.rs b/mm2src/coins/tendermint/tendermint_coin.rs index 660bc7b2aa..4fe94f264d 100644 --- a/mm2src/coins/tendermint/tendermint_coin.rs +++ b/mm2src/coins/tendermint/tendermint_coin.rs @@ -75,6 +75,7 @@ use std::ops::Deref; use std::str::FromStr; use std::sync::{Arc, Mutex}; use std::time::Duration; +use tokio_tungstenite::tungstenite; use uuid::Uuid; // ABCI Request Paths @@ -2197,30 +2198,47 @@ impl MmCoin for TendermintCoin { fn on_token_deactivated(&self, _ticker: &str) {} async fn handle_balance_stream(self, _interval: f64) { - let ws_conn = "ws://35.234.10.84:26657/websocket"; - let (mut socket, _) = tokio_tungstenite::connect_async(ws_conn).await.unwrap(); + let node_uri = self.rpc_client().await.unwrap().uri(); - let q = json!({ + let address_prefix = match node_uri.scheme_str() { + Some("https") => "wss", + _ => "ws", + }; + let host_address = node_uri.host().expect("Host can't be empty."); + let port = node_uri.port_u16().map(|p| format!(":{}", p)).unwrap_or_default(); + + let socket_address = format!("{}://{}{}/websocket", address_prefix, host_address, port); + println!("SOCKET_ADDRESS! {:?}", socket_address); + + let (mut socket, _) = tokio_tungstenite::connect_async(socket_address).await.unwrap(); + + let account_id = self.account_id.to_string(); + + // Filter received TX events + let query_filter = format!("coin_received.receiver = '{}'", account_id); + let query_payload = json!({ "jsonrpc": "2.0", "method": "subscribe", "id": 0, "params": { - "query": "coin_received.receiver = 'iaa1e0rx87mdj79zejewuc4jg7ql9ud2286g2us8f2'" + "query": query_filter } }); - let msg = tokio_tungstenite::tungstenite::Message::text(q.to_string()); - socket.send(msg).await.unwrap(); + let query_payload = tungstenite::Message::text(query_payload.to_string()); + socket.send(query_payload).await.unwrap(); - let q = json!({ + // Filter spent TX events + let query_filter = format!("coin_spent.spender = '{}'", account_id); + let query_payload = json!({ "jsonrpc": "2.0", "method": "subscribe", "id": 0, "params": { - "query": "coin_spent.spender = 'iaa1e0rx87mdj79zejewuc4jg7ql9ud2286g2us8f2'" + "query": query_filter } }); - let msg = tokio_tungstenite::tungstenite::Message::text(q.to_string()); - socket.send(msg).await.unwrap(); + let query_payload = tungstenite::Message::text(query_payload.to_string()); + socket.send(query_payload).await.unwrap(); while let Some(message) = socket.next().await { let msg = match message.unwrap() { @@ -2228,9 +2246,9 @@ impl MmCoin for TendermintCoin { _ => String::new(), }; - if let Ok(parsed) = serde_json::from_str::(&msg) { + if let Ok(json_val) = json::from_str::(&msg) { let transfers: Vec = - json::from_value(parsed["result"]["events"]["transfer.amount"].clone()).unwrap_or_default(); + json::from_value(json_val["result"]["events"]["transfer.amount"].clone()).unwrap_or_default(); let mut denoms: Vec = transfers .iter() diff --git a/mm2src/coins/tendermint/tendermint_token.rs b/mm2src/coins/tendermint/tendermint_token.rs index cffc7f74cf..c723069a97 100644 --- a/mm2src/coins/tendermint/tendermint_token.rs +++ b/mm2src/coins/tendermint/tendermint_token.rs @@ -25,7 +25,7 @@ use async_trait::async_trait; use bitcrypto::sha256; use common::executor::abortable_queue::AbortableQueue; use common::executor::{AbortableSystem, AbortedError}; -use common::log::warn; +use common::log::{debug, warn}; use common::Future01CompatExt; use cosmrs::{bank::MsgSend, tx::{Fee, Msg}, @@ -875,5 +875,7 @@ impl MmCoin for TendermintToken { fn on_token_deactivated(&self, _ticker: &str) {} - async fn handle_balance_stream(self, _interval: f64) { todo!() } + async fn handle_balance_stream(self, _interval: f64) { + debug!("`fn handle_balance_stream` has no effect for Cosmos tokens.") + } } From 041aebb51c5094338d16879dff9c79e0c800df87 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Tue, 26 Sep 2023 10:40:27 +0300 Subject: [PATCH 30/48] denom to ticker conversion Signed-off-by: onur-ozkan --- mm2src/coins/tendermint/tendermint_coin.rs | 23 +++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/mm2src/coins/tendermint/tendermint_coin.rs b/mm2src/coins/tendermint/tendermint_coin.rs index 4fe94f264d..8e89801af7 100644 --- a/mm2src/coins/tendermint/tendermint_coin.rs +++ b/mm2src/coins/tendermint/tendermint_coin.rs @@ -1822,6 +1822,22 @@ impl TendermintCoin { _ => (self.gas_price(), fallback_gas_limit), } } + + async fn active_ticker_from_denom(&self, denom: &str) -> Option { + if self.denom.to_string() == denom { + return Some(self.ticker.clone()); + } + + let tokens = self.tokens_info.lock(); + + for (ticker, token) in &*tokens { + if token.denom.to_string() == denom { + return Some(ticker.to_owned()); + } + } + + None + } } fn clients_from_urls(rpc_urls: &[String]) -> MmResult, TendermintInitErrorKind> { @@ -2262,7 +2278,12 @@ impl MmCoin for TendermintCoin { denoms.dedup(); drop_mutability!(denoms); - println!("DENOMS {:?}", denoms); + println!("DENOMS {:?}", &denoms); + + for denom in denoms { + let ticker = self.active_ticker_from_denom(&denom).await; + println!("COIN IS ACTIVE: {:?}", ticker); + } } } } From 0f712e313eac088e9f92c004f53852d5a1f89623 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Tue, 26 Sep 2023 12:43:54 +0300 Subject: [PATCH 31/48] broadcast events when balance is changed Signed-off-by: onur-ozkan --- mm2src/coins/coin_balance_event.rs | 50 ++++++++++++++------- mm2src/coins/eth.rs | 2 +- mm2src/coins/lightning.rs | 2 +- mm2src/coins/lp_coins.rs | 2 +- mm2src/coins/qrc20.rs | 2 +- mm2src/coins/solana.rs | 2 +- mm2src/coins/solana/spl.rs | 2 +- mm2src/coins/tendermint/tendermint_coin.rs | 47 +++++++++++++++---- mm2src/coins/tendermint/tendermint_token.rs | 4 +- mm2src/coins/test_coin.rs | 2 +- mm2src/coins/utxo/bch.rs | 2 +- mm2src/coins/utxo/qtum.rs | 2 +- mm2src/coins/utxo/slp.rs | 2 +- mm2src/coins/utxo/utxo_standard.rs | 2 +- mm2src/coins/z_coin.rs | 2 +- 15 files changed, 87 insertions(+), 38 deletions(-) diff --git a/mm2src/coins/coin_balance_event.rs b/mm2src/coins/coin_balance_event.rs index 520228c84a..9a174591ba 100644 --- a/mm2src/coins/coin_balance_event.rs +++ b/mm2src/coins/coin_balance_event.rs @@ -6,6 +6,8 @@ use mm2_core::mm_ctx::MmArc; use mm2_event_stream::{behaviour::EventBehaviour, EventStreamConfiguration}; use std::sync::atomic::Ordering; +pub(crate) const COIN_BALANCE_EVENT_TAG: &str = "COIN_BALANCE"; + pub struct CoinBalanceEvent { ctx: MmArc, } @@ -16,9 +18,9 @@ impl CoinBalanceEvent { #[async_trait] impl EventBehaviour for CoinBalanceEvent { - const EVENT_NAME: &'static str = "COIN_BALANCE"; + const EVENT_NAME: &'static str = COIN_BALANCE_EVENT_TAG; - async fn handle(self, interval: f64) { + async fn handle(self, _interval: f64) { let cctx = CoinsContext::from_ctx(&self.ctx).expect("Unexpected internal panic."); // Events that are already fired @@ -53,33 +55,51 @@ impl EventBehaviour for CoinBalanceEvent { } match coin { - MmCoinEnum::UtxoCoin(inner) => self.ctx.spawner().spawn(inner.handle_balance_stream(interval)), - MmCoinEnum::QtumCoin(inner) => self.ctx.spawner().spawn(inner.handle_balance_stream(interval)), - MmCoinEnum::Qrc20Coin(inner) => self.ctx.spawner().spawn(inner.handle_balance_stream(interval)), - MmCoinEnum::EthCoin(inner) => self.ctx.spawner().spawn(inner.handle_balance_stream(interval)), - MmCoinEnum::ZCoin(inner) => self.ctx.spawner().spawn(inner.handle_balance_stream(interval)), - MmCoinEnum::Bch(inner) => self.ctx.spawner().spawn(inner.handle_balance_stream(interval)), - MmCoinEnum::SlpToken(inner) => self.ctx.spawner().spawn(inner.handle_balance_stream(interval)), - MmCoinEnum::Tendermint(inner) => self.ctx.spawner().spawn(inner.handle_balance_stream(interval)), + MmCoinEnum::UtxoCoin(inner) => { + self.ctx.spawner().spawn(inner.handle_balance_stream(self.ctx.clone())) + }, + MmCoinEnum::QtumCoin(inner) => { + self.ctx.spawner().spawn(inner.handle_balance_stream(self.ctx.clone())) + }, + MmCoinEnum::Qrc20Coin(inner) => { + self.ctx.spawner().spawn(inner.handle_balance_stream(self.ctx.clone())) + }, + MmCoinEnum::EthCoin(inner) => { + self.ctx.spawner().spawn(inner.handle_balance_stream(self.ctx.clone())) + }, + MmCoinEnum::ZCoin(inner) => self.ctx.spawner().spawn(inner.handle_balance_stream(self.ctx.clone())), + MmCoinEnum::Bch(inner) => self.ctx.spawner().spawn(inner.handle_balance_stream(self.ctx.clone())), + MmCoinEnum::SlpToken(inner) => { + self.ctx.spawner().spawn(inner.handle_balance_stream(self.ctx.clone())) + }, + MmCoinEnum::Tendermint(inner) => { + self.ctx.spawner().spawn(inner.handle_balance_stream(self.ctx.clone())) + }, MmCoinEnum::TendermintToken(inner) => { - self.ctx.spawner().spawn(inner.handle_balance_stream(interval)) + self.ctx.spawner().spawn(inner.handle_balance_stream(self.ctx.clone())) + }, + MmCoinEnum::LightningCoin(inner) => { + self.ctx.spawner().spawn(inner.handle_balance_stream(self.ctx.clone())) }, - MmCoinEnum::LightningCoin(inner) => self.ctx.spawner().spawn(inner.handle_balance_stream(interval)), - MmCoinEnum::Test(inner) => self.ctx.spawner().spawn(inner.handle_balance_stream(interval)), + MmCoinEnum::Test(inner) => self.ctx.spawner().spawn(inner.handle_balance_stream(self.ctx.clone())), #[cfg(all( feature = "enable-solana", not(target_os = "ios"), not(target_os = "android"), not(target_arch = "wasm32") ))] - MmCoinEnum::SolanaCoin(inner) => self.ctx.spawner().spawn(inner.handle_balance_stream(interval)), + MmCoinEnum::SolanaCoin(inner) => { + self.ctx.spawner().spawn(inner.handle_balance_stream(self.ctx.clone())) + }, #[cfg(all( feature = "enable-solana", not(target_os = "ios"), not(target_os = "android"), not(target_arch = "wasm32") ))] - MmCoinEnum::SplToken(inner) => self.ctx.spawner().spawn(inner.handle_balance_stream(interval)), + MmCoinEnum::SplToken(inner) => { + self.ctx.spawner().spawn(inner.handle_balance_stream(self.ctx.clone())) + }, } event_pool.push(ticker); diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 459c43585c..c831e13978 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -4733,7 +4733,7 @@ impl MmCoin for EthCoin { }; } - async fn handle_balance_stream(self, _interval: f64) { todo!() } + async fn handle_balance_stream(self, _ctx: MmArc) { todo!() } } pub trait TryToAddress { diff --git a/mm2src/coins/lightning.rs b/mm2src/coins/lightning.rs index 070d654e28..452b9a11fc 100644 --- a/mm2src/coins/lightning.rs +++ b/mm2src/coins/lightning.rs @@ -1453,5 +1453,5 @@ impl MmCoin for LightningCoin { fn on_token_deactivated(&self, _ticker: &str) {} - async fn handle_balance_stream(self, _interval: f64) { todo!() } + async fn handle_balance_stream(self, _ctx: MmArc) { todo!() } } diff --git a/mm2src/coins/lp_coins.rs b/mm2src/coins/lp_coins.rs index f7176e9c90..b3fd383d5a 100644 --- a/mm2src/coins/lp_coins.rs +++ b/mm2src/coins/lp_coins.rs @@ -2465,7 +2465,7 @@ pub trait MmCoin: fn on_token_deactivated(&self, ticker: &str); // Handler for coin balance streaming continuously to the thread/stream channels - async fn handle_balance_stream(self, interval: f64); + async fn handle_balance_stream(self, ctx: MmArc); } /// The coin futures spawner. It's used to spawn futures that can be aborted immediately or after a timeout diff --git a/mm2src/coins/qrc20.rs b/mm2src/coins/qrc20.rs index 1d0a93ee27..1abc24a27e 100644 --- a/mm2src/coins/qrc20.rs +++ b/mm2src/coins/qrc20.rs @@ -1466,7 +1466,7 @@ impl MmCoin for Qrc20Coin { fn on_token_deactivated(&self, _ticker: &str) {} - async fn handle_balance_stream(self, _interval: f64) { todo!() } + async fn handle_balance_stream(self, _ctx: MmArc) { todo!() } } pub fn qrc20_swap_id(time_lock: u32, secret_hash: &[u8]) -> Vec { diff --git a/mm2src/coins/solana.rs b/mm2src/coins/solana.rs index c2b589d0a9..60762113b9 100644 --- a/mm2src/coins/solana.rs +++ b/mm2src/coins/solana.rs @@ -777,5 +777,5 @@ impl MmCoin for SolanaCoin { fn on_token_deactivated(&self, _ticker: &str) {} - async fn handle_balance_stream(self, _interval: f64) { todo!() } + async fn handle_balance_stream(self, _ctx: MmArc) { todo!() } } diff --git a/mm2src/coins/solana/spl.rs b/mm2src/coins/solana/spl.rs index a56b8447df..95d630e55a 100644 --- a/mm2src/coins/solana/spl.rs +++ b/mm2src/coins/solana/spl.rs @@ -571,5 +571,5 @@ impl MmCoin for SplToken { fn on_token_deactivated(&self, _ticker: &str) {} - async fn handle_balance_stream(self, _interval: f64) { todo!() } + async fn handle_balance_stream(self, _ctx: MmArc) { todo!() } } diff --git a/mm2src/coins/tendermint/tendermint_coin.rs b/mm2src/coins/tendermint/tendermint_coin.rs index 8e89801af7..022eaeff95 100644 --- a/mm2src/coins/tendermint/tendermint_coin.rs +++ b/mm2src/coins/tendermint/tendermint_coin.rs @@ -5,6 +5,7 @@ use super::iris::htlc::{IrisHtlc, MsgClaimHtlc, MsgCreateHtlc, HTLC_STATE_COMPLE HTLC_STATE_REFUNDED}; use super::iris::htlc_proto::{CreateHtlcProtoRep, QueryHtlcRequestProto, QueryHtlcResponseProto}; use super::rpc::*; +use crate::coin_balance_event::COIN_BALANCE_EVENT_TAG; use crate::coin_errors::{MyAddressError, ValidatePaymentError}; use crate::rpc_command::tendermint::{IBCChainRegistriesResponse, IBCChainRegistriesResult, IBCChainsRequestError, IBCTransferChannel, IBCTransferChannelTag, IBCTransferChannelsRequest, @@ -62,6 +63,7 @@ use itertools::Itertools; use keys::KeyPair; use mm2_core::mm_ctx::MmArc; use mm2_err_handle::prelude::*; +use mm2_event_stream::Event; use mm2_git::{FileMetadata, GitController, GithubClient, RepositoryOperations, GITHUB_API_URI}; use mm2_number::MmNumber; use parking_lot::Mutex as PaMutex; @@ -1823,16 +1825,16 @@ impl TendermintCoin { } } - async fn active_ticker_from_denom(&self, denom: &str) -> Option { + async fn active_ticker_and_decimals_from_denom(&self, denom: &str) -> Option<(String, u8)> { if self.denom.to_string() == denom { - return Some(self.ticker.clone()); + return Some((self.ticker.clone(), self.decimals)); } let tokens = self.tokens_info.lock(); for (ticker, token) in &*tokens { if token.denom.to_string() == denom { - return Some(ticker.to_owned()); + return Some((ticker.to_owned(), token.decimals)); } } @@ -2213,7 +2215,7 @@ impl MmCoin for TendermintCoin { fn on_token_deactivated(&self, _ticker: &str) {} - async fn handle_balance_stream(self, _interval: f64) { + async fn handle_balance_stream(self, ctx: MmArc) { let node_uri = self.rpc_client().await.unwrap().uri(); let address_prefix = match node_uri.scheme_str() { @@ -2224,7 +2226,6 @@ impl MmCoin for TendermintCoin { let port = node_uri.port_u16().map(|p| format!(":{}", p)).unwrap_or_default(); let socket_address = format!("{}://{}{}/websocket", address_prefix, host_address, port); - println!("SOCKET_ADDRESS! {:?}", socket_address); let (mut socket, _) = tokio_tungstenite::connect_async(socket_address).await.unwrap(); @@ -2256,6 +2257,7 @@ impl MmCoin for TendermintCoin { let query_payload = tungstenite::Message::text(query_payload.to_string()); socket.send(query_payload).await.unwrap(); + let mut current_balances: HashMap = HashMap::new(); while let Some(message) = socket.next().await { let msg = match message.unwrap() { tokio_tungstenite::tungstenite::Message::Text(s) => s, @@ -2278,11 +2280,38 @@ impl MmCoin for TendermintCoin { denoms.dedup(); drop_mutability!(denoms); - println!("DENOMS {:?}", &denoms); - for denom in denoms { - let ticker = self.active_ticker_from_denom(&denom).await; - println!("COIN IS ACTIVE: {:?}", ticker); + if let Some((ticker, decimals)) = self.active_ticker_and_decimals_from_denom(&denom).await { + let balance_denom = self + .account_balance_for_denom(&self.account_id, denom) + .await + .map_err(|e| e.into_inner()) + .unwrap(); + + let balance_decimal = big_decimal_from_sat_unsigned(balance_denom, decimals); + + let mut broadcast = false; + if let Some(balance) = current_balances.get_mut(&ticker) { + if *balance != balance_decimal { + *balance = balance_decimal.clone(); + broadcast = true; + } + } else { + current_balances.insert(ticker.clone(), balance_decimal.clone()); + broadcast = true; + } + + if broadcast { + let payload = json!({ + "ticker": ticker, + "balance": { "spendable": balance_decimal, "unspendable": BigDecimal::default() } + }); + + ctx.stream_channel_controller + .broadcast(Event::new(COIN_BALANCE_EVENT_TAG.to_string(), payload.to_string())) + .await; + } + } } } } diff --git a/mm2src/coins/tendermint/tendermint_token.rs b/mm2src/coins/tendermint/tendermint_token.rs index c723069a97..d711a6b8ef 100644 --- a/mm2src/coins/tendermint/tendermint_token.rs +++ b/mm2src/coins/tendermint/tendermint_token.rs @@ -875,7 +875,7 @@ impl MmCoin for TendermintToken { fn on_token_deactivated(&self, _ticker: &str) {} - async fn handle_balance_stream(self, _interval: f64) { - debug!("`fn handle_balance_stream` has no effect for Cosmos tokens.") + async fn handle_balance_stream(self, _ctx: MmArc) { + debug!("`fn handle_balance_stream` has no effect on Cosmos tokens.") } } diff --git a/mm2src/coins/test_coin.rs b/mm2src/coins/test_coin.rs index 13b6c30f12..f76ce77040 100644 --- a/mm2src/coins/test_coin.rs +++ b/mm2src/coins/test_coin.rs @@ -378,5 +378,5 @@ impl MmCoin for TestCoin { fn on_token_deactivated(&self, _ticker: &str) { () } - async fn handle_balance_stream(self, _interval: f64) { todo!() } + async fn handle_balance_stream(self, _ctx: MmArc) { todo!() } } diff --git a/mm2src/coins/utxo/bch.rs b/mm2src/coins/utxo/bch.rs index 0bb23c526d..23e7d9972f 100644 --- a/mm2src/coins/utxo/bch.rs +++ b/mm2src/coins/utxo/bch.rs @@ -1309,7 +1309,7 @@ impl MmCoin for BchCoin { }; } - async fn handle_balance_stream(self, _interval: f64) { todo!() } + async fn handle_balance_stream(self, _ctx: MmArc) { todo!() } } impl CoinWithDerivationMethod for BchCoin { diff --git a/mm2src/coins/utxo/qtum.rs b/mm2src/coins/utxo/qtum.rs index 5da6be8757..a31e837704 100644 --- a/mm2src/coins/utxo/qtum.rs +++ b/mm2src/coins/utxo/qtum.rs @@ -976,7 +976,7 @@ impl MmCoin for QtumCoin { fn on_token_deactivated(&self, _ticker: &str) {} - async fn handle_balance_stream(self, _interval: f64) { todo!() } + async fn handle_balance_stream(self, _ctx: MmArc) { todo!() } } #[async_trait] diff --git a/mm2src/coins/utxo/slp.rs b/mm2src/coins/utxo/slp.rs index 4ae91e3269..fb93bce288 100644 --- a/mm2src/coins/utxo/slp.rs +++ b/mm2src/coins/utxo/slp.rs @@ -1873,7 +1873,7 @@ impl MmCoin for SlpToken { fn on_token_deactivated(&self, _ticker: &str) {} - async fn handle_balance_stream(self, _interval: f64) { todo!() } + async fn handle_balance_stream(self, _ctx: MmArc) { todo!() } } #[async_trait] diff --git a/mm2src/coins/utxo/utxo_standard.rs b/mm2src/coins/utxo/utxo_standard.rs index 11d1c9b890..027107777a 100644 --- a/mm2src/coins/utxo/utxo_standard.rs +++ b/mm2src/coins/utxo/utxo_standard.rs @@ -794,7 +794,7 @@ impl MmCoin for UtxoStandardCoin { fn on_token_deactivated(&self, _ticker: &str) {} - async fn handle_balance_stream(self, _interval: f64) { todo!() } + async fn handle_balance_stream(self, _ctx: MmArc) { todo!() } } #[async_trait] diff --git a/mm2src/coins/z_coin.rs b/mm2src/coins/z_coin.rs index 4d732a3f8e..d74c914ee9 100644 --- a/mm2src/coins/z_coin.rs +++ b/mm2src/coins/z_coin.rs @@ -1757,7 +1757,7 @@ impl MmCoin for ZCoin { fn on_token_deactivated(&self, _ticker: &str) {} - async fn handle_balance_stream(self, _interval: f64) { todo!() } + async fn handle_balance_stream(self, _ctx: MmArc) { todo!() } } #[async_trait] From 633987aab827d27557289fd2df3bc18f87694b76 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Tue, 26 Sep 2023 14:04:56 +0300 Subject: [PATCH 32/48] create `http_uri_to_ws_address` Signed-off-by: onur-ozkan --- mm2src/coins/tendermint/tendermint_coin.rs | 56 +++++++++------------- mm2src/common/common.rs | 37 ++++++++++++++ 2 files changed, 60 insertions(+), 33 deletions(-) diff --git a/mm2src/coins/tendermint/tendermint_coin.rs b/mm2src/coins/tendermint/tendermint_coin.rs index 022eaeff95..7cd97c97e2 100644 --- a/mm2src/coins/tendermint/tendermint_coin.rs +++ b/mm2src/coins/tendermint/tendermint_coin.rs @@ -36,7 +36,7 @@ use bitcrypto::{dhash160, sha256}; use common::executor::{abortable_queue::AbortableQueue, AbortableSystem}; use common::executor::{AbortedError, Timer}; use common::log::{debug, warn}; -use common::{get_utc_timestamp, now_sec, Future01CompatExt, DEX_FEE_ADDR_PUBKEY}; +use common::{get_utc_timestamp, http_uri_to_ws_address, now_sec, Future01CompatExt, DEX_FEE_ADDR_PUBKEY}; use cosmrs::bank::MsgSend; use cosmrs::crypto::secp256k1::SigningKey; use cosmrs::proto::cosmos::auth::v1beta1::{BaseAccount, QueryAccountRequest, QueryAccountResponse}; @@ -2215,53 +2215,42 @@ impl MmCoin for TendermintCoin { fn on_token_deactivated(&self, _ticker: &str) {} + // TODO: handle/rotate socket connection when server goes down async fn handle_balance_stream(self, ctx: MmArc) { - let node_uri = self.rpc_client().await.unwrap().uri(); - - let address_prefix = match node_uri.scheme_str() { - Some("https") => "wss", - _ => "ws", - }; - let host_address = node_uri.host().expect("Host can't be empty."); - let port = node_uri.port_u16().map(|p| format!(":{}", p)).unwrap_or_default(); + fn generate_subscription_query(query_filter: String) -> String { + let q = json!({ + "jsonrpc": "2.0", + "method": "subscribe", + "id": 0, + "params": { + "query": query_filter + } + }); - let socket_address = format!("{}://{}{}/websocket", address_prefix, host_address, port); + q.to_string() + } + let node_uri = self.rpc_client().await.unwrap().uri(); + let socket_address = format!("{}/{}", http_uri_to_ws_address(node_uri), "websocket"); let (mut socket, _) = tokio_tungstenite::connect_async(socket_address).await.unwrap(); let account_id = self.account_id.to_string(); // Filter received TX events - let query_filter = format!("coin_received.receiver = '{}'", account_id); - let query_payload = json!({ - "jsonrpc": "2.0", - "method": "subscribe", - "id": 0, - "params": { - "query": query_filter - } - }); - let query_payload = tungstenite::Message::text(query_payload.to_string()); - socket.send(query_payload).await.unwrap(); + let query = generate_subscription_query(format!("coin_received.receiver = '{}'", account_id)); + let query = tungstenite::Message::text(query); + socket.send(query).await.unwrap(); // Filter spent TX events - let query_filter = format!("coin_spent.spender = '{}'", account_id); - let query_payload = json!({ - "jsonrpc": "2.0", - "method": "subscribe", - "id": 0, - "params": { - "query": query_filter - } - }); - let query_payload = tungstenite::Message::text(query_payload.to_string()); - socket.send(query_payload).await.unwrap(); + let query = generate_subscription_query(format!("coin_spent.spender = '{}'", account_id)); + let query = tungstenite::Message::text(query); + socket.send(query).await.unwrap(); let mut current_balances: HashMap = HashMap::new(); while let Some(message) = socket.next().await { let msg = match message.unwrap() { tokio_tungstenite::tungstenite::Message::Text(s) => s, - _ => String::new(), + _ => continue, }; if let Ok(json_val) = json::from_str::(&msg) { @@ -2290,6 +2279,7 @@ impl MmCoin for TendermintCoin { let balance_decimal = big_decimal_from_sat_unsigned(balance_denom, decimals); + // Only broadcast when balance is changed let mut broadcast = false; if let Some(balance) = current_balances.get_mut(&ticker) { if *balance != balance_decimal { diff --git a/mm2src/common/common.rs b/mm2src/common/common.rs index 653ad11353..c9464002d1 100644 --- a/mm2src/common/common.rs +++ b/mm2src/common/common.rs @@ -1045,3 +1045,40 @@ pub fn parse_rfc3339_to_timestamp(date_str: &str) -> Result bool { old_version == 0 && new_version == 1 } + +/// Takes `http:Uri` and converts it into `String` of websocket address +/// +/// Panics if the given URI doesn't contain a host value. +pub fn http_uri_to_ws_address(uri: http::Uri) -> String { + let address_prefix = match uri.scheme_str() { + Some("https") => "wss://", + _ => "ws://", + }; + + let host_address = uri.host().expect("Host can't be empty."); + let port = uri.port_u16().map(|p| format!(":{}", p)).unwrap_or_default(); + + format!("{}{}{}", address_prefix, host_address, port) +} + +#[test] +fn test_http_uri_to_ws_address() { + let uri = "https://cosmos-rpc.polkachu.com".parse::().unwrap(); + let ws_connection = http_uri_to_ws_address(uri); + assert_eq!(ws_connection, "wss://cosmos-rpc.polkachu.com"); + + let uri = "http://cosmos-rpc.polkachu.com".parse::().unwrap(); + let ws_connection = http_uri_to_ws_address(uri); + assert_eq!(ws_connection, "ws://cosmos-rpc.polkachu.com"); + + let uri = "http://34.82.96.8:26657".parse::().unwrap(); + let ws_connection = http_uri_to_ws_address(uri); + assert_eq!(ws_connection, "ws://34.82.96.8:26657"); +} + +#[test] +#[should_panic(expected = "Host can't be empty.")] +fn test_http_uri_to_ws_address_panic() { + let uri = "/demo/value".parse::().unwrap(); + http_uri_to_ws_address(uri); +} From eff5c9a42148c008cad88023b1d7100240da2bf6 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Tue, 26 Sep 2023 14:48:24 +0300 Subject: [PATCH 33/48] handle socket related panics/connection failures Signed-off-by: onur-ozkan --- mm2src/coins/coin_balance_event.rs | 1 + mm2src/coins/tendermint/tendermint_coin.rs | 151 ++++++++++++--------- 2 files changed, 90 insertions(+), 62 deletions(-) diff --git a/mm2src/coins/coin_balance_event.rs b/mm2src/coins/coin_balance_event.rs index 9a174591ba..c0e0ee068c 100644 --- a/mm2src/coins/coin_balance_event.rs +++ b/mm2src/coins/coin_balance_event.rs @@ -6,6 +6,7 @@ use mm2_core::mm_ctx::MmArc; use mm2_event_stream::{behaviour::EventBehaviour, EventStreamConfiguration}; use std::sync::atomic::Ordering; +/// Event tag for broadcasting balance events pub(crate) const COIN_BALANCE_EVENT_TAG: &str = "COIN_BALANCE"; pub struct CoinBalanceEvent { diff --git a/mm2src/coins/tendermint/tendermint_coin.rs b/mm2src/coins/tendermint/tendermint_coin.rs index 7cd97c97e2..4fa6224b4b 100644 --- a/mm2src/coins/tendermint/tendermint_coin.rs +++ b/mm2src/coins/tendermint/tendermint_coin.rs @@ -35,7 +35,7 @@ use async_trait::async_trait; use bitcrypto::{dhash160, sha256}; use common::executor::{abortable_queue::AbortableQueue, AbortableSystem}; use common::executor::{AbortedError, Timer}; -use common::log::{debug, warn}; +use common::log::{debug, error, warn}; use common::{get_utc_timestamp, http_uri_to_ws_address, now_sec, Future01CompatExt, DEX_FEE_ADDR_PUBKEY}; use cosmrs::bank::MsgSend; use cosmrs::crypto::secp256k1::SigningKey; @@ -2215,7 +2215,6 @@ impl MmCoin for TendermintCoin { fn on_token_deactivated(&self, _ticker: &str) {} - // TODO: handle/rotate socket connection when server goes down async fn handle_balance_stream(self, ctx: MmArc) { fn generate_subscription_query(query_filter: String) -> String { let q = json!({ @@ -2230,80 +2229,108 @@ impl MmCoin for TendermintCoin { q.to_string() } - let node_uri = self.rpc_client().await.unwrap().uri(); - let socket_address = format!("{}/{}", http_uri_to_ws_address(node_uri), "websocket"); - let (mut socket, _) = tokio_tungstenite::connect_async(socket_address).await.unwrap(); - let account_id = self.account_id.to_string(); + let mut current_balances: HashMap = HashMap::new(); - // Filter received TX events - let query = generate_subscription_query(format!("coin_received.receiver = '{}'", account_id)); - let query = tungstenite::Message::text(query); - socket.send(query).await.unwrap(); + let receiver_q = generate_subscription_query(format!("coin_received.receiver = '{}'", account_id)); + let receiver_q = tungstenite::Message::text(receiver_q); - // Filter spent TX events - let query = generate_subscription_query(format!("coin_spent.spender = '{}'", account_id)); - let query = tungstenite::Message::text(query); - socket.send(query).await.unwrap(); + let spender_q = generate_subscription_query(format!("coin_spent.spender = '{}'", account_id)); + let spender_q = tungstenite::Message::text(spender_q); - let mut current_balances: HashMap = HashMap::new(); - while let Some(message) = socket.next().await { - let msg = match message.unwrap() { - tokio_tungstenite::tungstenite::Message::Text(s) => s, - _ => continue, + loop { + let node_uri = match self.rpc_client().await { + Ok(client) => client.uri(), + Err(e) => { + error!("{e}"); + continue; + }, }; - if let Ok(json_val) = json::from_str::(&msg) { - let transfers: Vec = - json::from_value(json_val["result"]["events"]["transfer.amount"].clone()).unwrap_or_default(); - - let mut denoms: Vec = transfers - .iter() - .map(|t| { - let amount: String = t.chars().take_while(|c| c.is_numeric()).collect(); - let denom = &t[amount.len()..]; - denom.to_owned() - }) - .collect(); - - denoms.dedup(); - drop_mutability!(denoms); - - for denom in denoms { - if let Some((ticker, decimals)) = self.active_ticker_and_decimals_from_denom(&denom).await { - let balance_denom = self - .account_balance_for_denom(&self.account_id, denom) - .await - .map_err(|e| e.into_inner()) - .unwrap(); - - let balance_decimal = big_decimal_from_sat_unsigned(balance_denom, decimals); - - // Only broadcast when balance is changed - let mut broadcast = false; - if let Some(balance) = current_balances.get_mut(&ticker) { - if *balance != balance_decimal { - *balance = balance_decimal.clone(); + let socket_address = format!("{}/{}", http_uri_to_ws_address(node_uri), "websocket"); + + let mut socket = match tokio_tungstenite::connect_async(socket_address).await { + Ok((socket, _)) => socket, + Err(e) => { + error!("{e}"); + continue; + }, + }; + + // Filter received TX events + if let Err(e) = socket.send(receiver_q.clone()).await { + error!("{e}"); + continue; + } + + // Filter spent TX events + if let Err(e) = socket.send(spender_q.clone()).await { + error!("{e}"); + continue; + } + + while let Some(message) = socket.next().await { + let msg = match message { + Ok(tungstenite::Message::Text(s)) => s, + _ => continue, + }; + + if let Ok(json_val) = json::from_str::(&msg) { + let transfers: Vec = + json::from_value(json_val["result"]["events"]["transfer.amount"].clone()).unwrap_or_default(); + + let mut denoms: Vec = transfers + .iter() + .map(|t| { + let amount: String = t.chars().take_while(|c| c.is_numeric()).collect(); + let denom = &t[amount.len()..]; + denom.to_owned() + }) + .collect(); + + denoms.dedup(); + drop_mutability!(denoms); + + for denom in denoms { + if let Some((ticker, decimals)) = self.active_ticker_and_decimals_from_denom(&denom).await { + let balance_denom = match self.account_balance_for_denom(&self.account_id, denom).await { + Ok(balance_denom) => balance_denom, + Err(e) => { + error!("{e}"); + continue; + }, + }; + + let balance_decimal = big_decimal_from_sat_unsigned(balance_denom, decimals); + + // Only broadcast when balance is changed + let mut broadcast = false; + if let Some(balance) = current_balances.get_mut(&ticker) { + if *balance != balance_decimal { + *balance = balance_decimal.clone(); + broadcast = true; + } + } else { + current_balances.insert(ticker.clone(), balance_decimal.clone()); broadcast = true; } - } else { - current_balances.insert(ticker.clone(), balance_decimal.clone()); - broadcast = true; - } - if broadcast { - let payload = json!({ - "ticker": ticker, - "balance": { "spendable": balance_decimal, "unspendable": BigDecimal::default() } - }); + if broadcast { + let payload = json!({ + "ticker": ticker, + "balance": { "spendable": balance_decimal, "unspendable": BigDecimal::default() } + }); - ctx.stream_channel_controller - .broadcast(Event::new(COIN_BALANCE_EVENT_TAG.to_string(), payload.to_string())) - .await; + ctx.stream_channel_controller + .broadcast(Event::new(COIN_BALANCE_EVENT_TAG.to_string(), payload.to_string())) + .await; + } } } } } + + Timer::sleep(2.0).await; } } } From 8a0577c9fa98a32a216b21cb9313f13101ef1703 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Tue, 26 Sep 2023 19:47:15 +0300 Subject: [PATCH 34/48] use komodo fork of websocket lib for WASM support Signed-off-by: onur-ozkan --- Cargo.lock | 294 ++++----------------- mm2src/coins/Cargo.toml | 2 +- mm2src/coins/tendermint/tendermint_coin.rs | 36 ++- 3 files changed, 74 insertions(+), 258 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e3189bb009..1fc7723a5d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -293,7 +293,7 @@ checksum = "acee9fd5073ab6b045a275b3e709c163dd36c90685219cb21804a147b58dba43" dependencies = [ "async-trait", "axum-core", - "bitflags 1.3.2", + "bitflags", "bytes 1.1.0", "futures-util", "http 0.2.7", @@ -490,7 +490,7 @@ dependencies = [ "primitives", "ripemd160", "serialization", - "sha-1", + "sha-1 0.9.8", "sha2 0.9.9", "sha3 0.9.1", "siphasher", @@ -502,12 +502,6 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" -[[package]] -name = "bitflags" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" - [[package]] name = "bitvec" version = "0.18.5" @@ -936,7 +930,7 @@ checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" dependencies = [ "ansi_term", "atty", - "bitflags 1.3.2", + "bitflags", "strsim", "textwrap", "unicode-width", @@ -949,7 +943,7 @@ version = "0.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" dependencies = [ - "bitflags 1.3.2", + "bitflags", ] [[package]] @@ -958,7 +952,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4344512281c643ae7638bbabc3af17a11307803ec8f0fcad9fae512a8bf36467" dependencies = [ - "bitflags 1.3.2", + "bitflags", ] [[package]] @@ -1011,6 +1005,7 @@ dependencies = [ "ethcore-transaction", "ethereum-types", "ethkey", + "ewebsock", "futures 0.1.29", "futures 0.3.15", "group 0.8.0", @@ -1079,7 +1074,6 @@ dependencies = [ "tiny-bip39", "tokio", "tokio-rustls", - "tokio-tungstenite", "tonic", "tonic-build", "url", @@ -1241,16 +1235,6 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" -[[package]] -name = "core-foundation" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" -dependencies = [ - "core-foundation-sys", - "libc", -] - [[package]] name = "core-foundation-sys" version = "0.8.3" @@ -2177,6 +2161,24 @@ dependencies = [ "tiny-keccak 1.4.4", ] +[[package]] +name = "ewebsock" +version = "0.2.0" +source = "git+https://github.com/KomodoPlatform/ewebsock.git?branch=async#c402aa2a29e9aacda42651a7e42482297c11bffb" +dependencies = [ + "async-stream", + "futures 0.3.15", + "futures-util", + "js-sys", + "tokio", + "tokio-tungstenite", + "tracing", + "tungstenite 0.17.3", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + [[package]] name = "eyre" version = "0.6.8" @@ -2332,21 +2334,6 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - [[package]] name = "form_urlencoded" version = "1.0.1" @@ -3328,7 +3315,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6607c62aa161d23d17a9072cc5da0be67cdfc89d3afb1e8d9c842bebc2525ffe" dependencies = [ "arrayvec 0.5.1", - "bitflags 1.3.2", + "bitflags", "cfg-if 1.0.0", "ryu", "static_assertions", @@ -4595,24 +4582,6 @@ dependencies = [ "unsigned-varint 0.7.1", ] -[[package]] -name = "native-tls" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" -dependencies = [ - "lazy_static", - "libc", - "log 0.4.17", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", -] - [[package]] name = "nibble_vec" version = "0.1.0" @@ -4628,7 +4597,7 @@ version = "0.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f866317acbd3a240710c63f065ffb1e4fd466259045ccb504130b7f668f35c6" dependencies = [ - "bitflags 1.3.2", + "bitflags", "cc", "cfg-if 1.0.0", "libc", @@ -4783,50 +4752,6 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" -[[package]] -name = "openssl" -version = "0.10.57" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bac25ee399abb46215765b1cb35bc0212377e58a061560d8b29b024fd0430e7c" -dependencies = [ - "bitflags 2.4.0", - "cfg-if 1.0.0", - "foreign-types", - "libc", - "once_cell", - "openssl-macros", - "openssl-sys", -] - -[[package]] -name = "openssl-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" -dependencies = [ - "proc-macro2 1.0.58", - "quote 1.0.27", - "syn 2.0.16", -] - -[[package]] -name = "openssl-probe" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" - -[[package]] -name = "openssl-sys" -version = "0.9.93" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db4d56a4c0478783083cfafcc42493dd4a981d41669da64b4572a2a089b51b1d" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - [[package]] name = "ordered-float" version = "3.7.0" @@ -5736,7 +5661,7 @@ version = "10.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c49596760fce12ca21550ac21dc5a9617b2ea4b6e0aa7d8dab8ff2824fc2bba" dependencies = [ - "bitflags 1.3.2", + "bitflags", ] [[package]] @@ -5797,7 +5722,7 @@ version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" dependencies = [ - "bitflags 1.3.2", + "bitflags", ] [[package]] @@ -6033,7 +5958,7 @@ version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "01e213bc3ecb39ac32e81e51ebe31fd888a940515173e3a18a35f8c6e896422a" dependencies = [ - "bitflags 1.3.2", + "bitflags", "fallible-iterator", "fallible-streaming-iterator", "hashlink", @@ -6102,7 +6027,7 @@ version = "0.36.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd5c6ff11fecd55b40746d1995a02f2eb375bf8c00d192d521ee09f42bef37bc" dependencies = [ - "bitflags 1.3.2", + "bitflags", "errno", "io-lifetimes", "libc", @@ -6208,15 +6133,6 @@ dependencies = [ "syn 1.0.95", ] -[[package]] -name = "schannel" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" -dependencies = [ - "windows-sys 0.48.0", -] - [[package]] name = "scoped-tls" version = "1.0.0" @@ -6329,29 +6245,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "security-framework" -version = "2.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" -dependencies = [ - "bitflags 1.3.2", - "core-foundation", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" -dependencies = [ - "core-foundation-sys", - "libc", -] - [[package]] name = "semver" version = "0.9.0" @@ -6516,10 +6409,10 @@ dependencies = [ ] [[package]] -name = "sha1" -version = "0.10.4" +name = "sha-1" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "006769ba83e921b3085caa8334186b00cf92b4cb1a6cf4632fbccc8eff5c7549" +checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f" dependencies = [ "cfg-if 1.0.0", "cpufeatures 0.2.1", @@ -6715,7 +6608,7 @@ dependencies = [ "httparse", "log 0.4.17", "rand 0.8.4", - "sha-1", + "sha-1 0.9.8", ] [[package]] @@ -7035,7 +6928,7 @@ checksum = "0a463f546a2f5842d35974bd4691ae5ceded6785ec24db440f773723f6ce4e11" dependencies = [ "base64 0.13.0", "bincode", - "bitflags 1.3.2", + "bitflags", "blake3", "borsh", "borsh-derive", @@ -7189,7 +7082,7 @@ dependencies = [ "assert_matches", "base64 0.13.0", "bincode", - "bitflags 1.3.2", + "bitflags", "borsh", "bs58", "bytemuck", @@ -7337,7 +7230,7 @@ version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77963e2aa8fadb589118c3aede2e78b6c4bcf1c01d588fbf33e915b390825fbd" dependencies = [ - "bitflags 1.3.2", + "bitflags", "byteorder 1.4.3", "hash-db", "hash256-std-hasher", @@ -8077,16 +7970,6 @@ dependencies = [ "syn 1.0.95", ] -[[package]] -name = "tokio-native-tls" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" -dependencies = [ - "native-tls", - "tokio", -] - [[package]] name = "tokio-rustls" version = "0.23.2" @@ -8111,16 +7994,18 @@ dependencies = [ [[package]] name = "tokio-tungstenite" -version = "0.19.0" +version = "0.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec509ac96e9a0c43427c74f003127d953a265737636129424288d27cb5c4b12c" +checksum = "f714dd15bead90401d77e04243611caec13726c2408afd5b31901dfcdcb3b181" dependencies = [ "futures-util", "log 0.4.17", - "native-tls", + "rustls 0.20.4", "tokio", - "tokio-native-tls", - "tungstenite 0.19.0", + "tokio-rustls", + "tungstenite 0.17.3", + "webpki 0.22.0", + "webpki-roots", ] [[package]] @@ -8221,7 +8106,7 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d342c6d58709c0a6d48d48dabbb62d4ef955cf5f0f3bbfd845838e7ae88dbae" dependencies = [ - "bitflags 1.3.2", + "bitflags", "bytes 1.1.0", "futures-core", "futures-util", @@ -8408,7 +8293,7 @@ dependencies = [ "log 0.4.17", "rand 0.8.4", "rustls 0.20.4", - "sha-1", + "sha-1 0.9.8", "thiserror", "url", "utf-8", @@ -8418,22 +8303,23 @@ dependencies = [ [[package]] name = "tungstenite" -version = "0.19.0" +version = "0.17.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15fba1a6d6bb030745759a9a2a588bfe8490fc8b4751a277db3a0be1c9ebbf67" +checksum = "e27992fd6a8c29ee7eef28fc78349aa244134e10ad447ce3b9f0ac0ed0fa4ce0" dependencies = [ + "base64 0.13.0", "byteorder 1.4.3", "bytes 1.1.0", - "data-encoding", "http 0.2.7", "httparse", "log 0.4.17", - "native-tls", "rand 0.8.4", - "sha1", + "rustls 0.20.4", + "sha-1 0.10.0", "thiserror", "url", "utf-8", + "webpki 0.22.0", ] [[package]] @@ -8930,12 +8816,12 @@ version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" dependencies = [ - "windows_aarch64_gnullvm 0.42.1", + "windows_aarch64_gnullvm", "windows_aarch64_msvc 0.42.1", "windows_i686_gnu 0.42.1", "windows_i686_msvc 0.42.1", "windows_x86_64_gnu 0.42.1", - "windows_x86_64_gnullvm 0.42.1", + "windows_x86_64_gnullvm", "windows_x86_64_msvc 0.42.1", ] @@ -8945,16 +8831,7 @@ version = "0.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" dependencies = [ - "windows-targets 0.42.1", -] - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", + "windows-targets", ] [[package]] @@ -8963,42 +8840,21 @@ version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7" dependencies = [ - "windows_aarch64_gnullvm 0.42.1", + "windows_aarch64_gnullvm", "windows_aarch64_msvc 0.42.1", "windows_i686_gnu 0.42.1", "windows_i686_msvc 0.42.1", "windows_x86_64_gnu 0.42.1", - "windows_x86_64_gnullvm 0.42.1", + "windows_x86_64_gnullvm", "windows_x86_64_msvc 0.42.1", ] -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", -] - [[package]] name = "windows_aarch64_gnullvm" version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - [[package]] name = "windows_aarch64_msvc" version = "0.32.0" @@ -9011,12 +8867,6 @@ version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - [[package]] name = "windows_i686_gnu" version = "0.32.0" @@ -9029,12 +8879,6 @@ version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - [[package]] name = "windows_i686_msvc" version = "0.32.0" @@ -9047,12 +8891,6 @@ version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - [[package]] name = "windows_x86_64_gnu" version = "0.32.0" @@ -9065,24 +8903,12 @@ version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - [[package]] name = "windows_x86_64_gnullvm" version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - [[package]] name = "windows_x86_64_msvc" version = "0.32.0" @@ -9095,12 +8921,6 @@ version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - [[package]] name = "winreg" version = "0.7.0" diff --git a/mm2src/coins/Cargo.toml b/mm2src/coins/Cargo.toml index b892ef0bad..dcb6fbb8c1 100644 --- a/mm2src/coins/Cargo.toml +++ b/mm2src/coins/Cargo.toml @@ -49,6 +49,7 @@ ethereum-types = { version = "0.13", default-features = false, features = ["std" ethkey = { git = "https://github.com/KomodoPlatform/mm2-parity-ethereum.git" } # Waiting for https://github.com/rust-lang/rust/issues/54725 to use on Stable. #enum_dispatch = "0.1" +ewebsock = { git = "https://github.com/KomodoPlatform/ewebsock.git", branch = "async", features = ["tls"] } futures01 = { version = "0.1", package = "futures" } # using select macro requires the crate to be named futures, compilation failed with futures03 name futures = { version = "0.3", package = "futures", features = ["compat", "async-await"] } @@ -98,7 +99,6 @@ utxo_signer = { path = "utxo_signer" } # using the same version as cosmrs tendermint-rpc = { version = "=0.23.7", default-features = false } tiny-bip39 = "0.8.0" -tokio-tungstenite = { version = "0.19.0", features = ["native-tls"]} url = { version = "2.2.2", features = ["serde"] } uuid = { version = "1.2.2", features = ["fast-rng", "serde", "v4"] } # One of web3 dependencies is the old `tokio-uds 0.1.7` which fails cross-compiling to ARM. diff --git a/mm2src/coins/tendermint/tendermint_coin.rs b/mm2src/coins/tendermint/tendermint_coin.rs index 4fa6224b4b..e3700d3d64 100644 --- a/mm2src/coins/tendermint/tendermint_coin.rs +++ b/mm2src/coins/tendermint/tendermint_coin.rs @@ -54,9 +54,10 @@ use cosmrs::{AccountId, Any, Coin, Denom, ErrorReport}; use crypto::privkey::key_pair_from_secret; use crypto::{Secp256k1Secret, StandardHDCoinAddress, StandardHDPathToCoin}; use derive_more::Display; +use ewebsock::{WsEvent, WsMessage}; use futures::future::try_join_all; use futures::lock::Mutex as AsyncMutex; -use futures::{FutureExt, SinkExt, StreamExt, TryFutureExt}; +use futures::{FutureExt, TryFutureExt}; use futures01::Future; use hex::FromHexError; use itertools::Itertools; @@ -77,7 +78,6 @@ use std::ops::Deref; use std::str::FromStr; use std::sync::{Arc, Mutex}; use std::time::Duration; -use tokio_tungstenite::tungstenite; use uuid::Uuid; // ABCI Request Paths @@ -2233,10 +2233,10 @@ impl MmCoin for TendermintCoin { let mut current_balances: HashMap = HashMap::new(); let receiver_q = generate_subscription_query(format!("coin_received.receiver = '{}'", account_id)); - let receiver_q = tungstenite::Message::text(receiver_q); + let receiver_q = ewebsock::WsMessage::Text(receiver_q); let spender_q = generate_subscription_query(format!("coin_spent.spender = '{}'", account_id)); - let spender_q = tungstenite::Message::text(spender_q); + let spender_q = ewebsock::WsMessage::Text(spender_q); loop { let node_uri = match self.rpc_client().await { @@ -2249,8 +2249,8 @@ impl MmCoin for TendermintCoin { let socket_address = format!("{}/{}", http_uri_to_ws_address(node_uri), "websocket"); - let mut socket = match tokio_tungstenite::connect_async(socket_address).await { - Ok((socket, _)) => socket, + let (mut sender, mut receiver) = match ewebsock::connect(socket_address, 100) { + Ok(ws) => ws, Err(e) => { error!("{e}"); continue; @@ -2258,20 +2258,18 @@ impl MmCoin for TendermintCoin { }; // Filter received TX events - if let Err(e) = socket.send(receiver_q.clone()).await { - error!("{e}"); - continue; - } + sender.send(receiver_q.clone()); // Filter spent TX events - if let Err(e) = socket.send(spender_q.clone()).await { - error!("{e}"); - continue; - } - - while let Some(message) = socket.next().await { - let msg = match message { - Ok(tungstenite::Message::Text(s)) => s, + sender.send(spender_q.clone()); + + while let Some(message) = receiver.try_recv().await { + let msg = match &*message { + WsEvent::Message(WsMessage::Text(data)) => data.clone(), + WsEvent::Error(err) => { + error!("{err}"); + break; + }, _ => continue, }; @@ -2329,8 +2327,6 @@ impl MmCoin for TendermintCoin { } } } - - Timer::sleep(2.0).await; } } } From 8f478a40c702d1638b503e6eeb4aa0bcf6a41f55 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Wed, 27 Sep 2023 11:05:11 +0300 Subject: [PATCH 35/48] get full compatibility on native + WASM sockets Signed-off-by: onur-ozkan --- Cargo.lock | 360 +++++++++++++----- mm2src/coins/Cargo.toml | 3 +- mm2src/coins/coin_balance_event.rs | 1 + .../tendermint/rpc/tendermint_wasm_rpc.rs | 3 + mm2src/coins/tendermint/tendermint_coin.rs | 31 +- mm2src/mm2_main/src/lp_native_dex.rs | 2 +- 6 files changed, 290 insertions(+), 110 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1fc7723a5d..8632ed0b3a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -293,7 +293,7 @@ checksum = "acee9fd5073ab6b045a275b3e709c163dd36c90685219cb21804a147b58dba43" dependencies = [ "async-trait", "axum-core", - "bitflags", + "bitflags 1.3.2", "bytes 1.1.0", "futures-util", "http 0.2.7", @@ -490,7 +490,7 @@ dependencies = [ "primitives", "ripemd160", "serialization", - "sha-1 0.9.8", + "sha-1", "sha2 0.9.9", "sha3 0.9.1", "siphasher", @@ -502,6 +502,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" + [[package]] name = "bitvec" version = "0.18.5" @@ -930,7 +936,7 @@ checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" dependencies = [ "ansi_term", "atty", - "bitflags", + "bitflags 1.3.2", "strsim", "textwrap", "unicode-width", @@ -943,7 +949,7 @@ version = "0.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -952,7 +958,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4344512281c643ae7638bbabc3af17a11307803ec8f0fcad9fae512a8bf36467" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -1005,9 +1011,9 @@ dependencies = [ "ethcore-transaction", "ethereum-types", "ethkey", - "ewebsock", "futures 0.1.29", "futures 0.3.15", + "futures-util", "group 0.8.0", "gstuff", "hex 0.4.3", @@ -1074,6 +1080,7 @@ dependencies = [ "tiny-bip39", "tokio", "tokio-rustls", + "tokio-tungstenite-wasm", "tonic", "tonic-build", "url", @@ -1235,6 +1242,16 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" +[[package]] +name = "core-foundation" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "core-foundation-sys" version = "0.8.3" @@ -2161,24 +2178,6 @@ dependencies = [ "tiny-keccak 1.4.4", ] -[[package]] -name = "ewebsock" -version = "0.2.0" -source = "git+https://github.com/KomodoPlatform/ewebsock.git?branch=async#c402aa2a29e9aacda42651a7e42482297c11bffb" -dependencies = [ - "async-stream", - "futures 0.3.15", - "futures-util", - "js-sys", - "tokio", - "tokio-tungstenite", - "tracing", - "tungstenite 0.17.3", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - [[package]] name = "eyre" version = "0.6.8" @@ -2334,6 +2333,21 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + [[package]] name = "form_urlencoded" version = "1.0.1" @@ -2405,9 +2419,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.28" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" +checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010" dependencies = [ "futures-core", "futures-sink", @@ -2415,9 +2429,9 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.28" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" +checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" [[package]] name = "futures-cpupool" @@ -2443,19 +2457,19 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.28" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" +checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b" [[package]] name = "futures-macro" -version = "0.3.28" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" +checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512" dependencies = [ "proc-macro2 1.0.58", "quote 1.0.27", - "syn 2.0.16", + "syn 1.0.95", ] [[package]] @@ -2482,15 +2496,15 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.28" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" +checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868" [[package]] name = "futures-task" -version = "0.3.28" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" +checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a" [[package]] name = "futures-timer" @@ -2504,9 +2518,9 @@ dependencies = [ [[package]] name = "futures-util" -version = "0.3.28" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" +checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a" dependencies = [ "futures 0.1.29", "futures-channel", @@ -3315,7 +3329,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6607c62aa161d23d17a9072cc5da0be67cdfc89d3afb1e8d9c842bebc2525ffe" dependencies = [ "arrayvec 0.5.1", - "bitflags", + "bitflags 1.3.2", "cfg-if 1.0.0", "ryu", "static_assertions", @@ -4582,6 +4596,24 @@ dependencies = [ "unsigned-varint 0.7.1", ] +[[package]] +name = "native-tls" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" +dependencies = [ + "lazy_static", + "libc", + "log 0.4.17", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + [[package]] name = "nibble_vec" version = "0.1.0" @@ -4597,7 +4629,7 @@ version = "0.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f866317acbd3a240710c63f065ffb1e4fd466259045ccb504130b7f668f35c6" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cc", "cfg-if 1.0.0", "libc", @@ -4752,6 +4784,50 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +[[package]] +name = "openssl" +version = "0.10.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bac25ee399abb46215765b1cb35bc0212377e58a061560d8b29b024fd0430e7c" +dependencies = [ + "bitflags 2.4.0", + "cfg-if 1.0.0", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2 1.0.58", + "quote 1.0.27", + "syn 2.0.16", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-sys" +version = "0.9.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db4d56a4c0478783083cfafcc42493dd4a981d41669da64b4572a2a089b51b1d" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + [[package]] name = "ordered-float" version = "3.7.0" @@ -5661,7 +5737,7 @@ version = "10.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c49596760fce12ca21550ac21dc5a9617b2ea4b6e0aa7d8dab8ff2824fc2bba" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -5722,7 +5798,7 @@ version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -5958,7 +6034,7 @@ version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "01e213bc3ecb39ac32e81e51ebe31fd888a940515173e3a18a35f8c6e896422a" dependencies = [ - "bitflags", + "bitflags 1.3.2", "fallible-iterator", "fallible-streaming-iterator", "hashlink", @@ -6027,7 +6103,7 @@ version = "0.36.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd5c6ff11fecd55b40746d1995a02f2eb375bf8c00d192d521ee09f42bef37bc" dependencies = [ - "bitflags", + "bitflags 1.3.2", "errno", "io-lifetimes", "libc", @@ -6133,6 +6209,15 @@ dependencies = [ "syn 1.0.95", ] +[[package]] +name = "schannel" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" +dependencies = [ + "windows-sys 0.48.0", +] + [[package]] name = "scoped-tls" version = "1.0.0" @@ -6245,6 +6330,29 @@ dependencies = [ "zeroize", ] +[[package]] +name = "security-framework" +version = "2.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "semver" version = "0.9.0" @@ -6408,17 +6516,6 @@ dependencies = [ "opaque-debug 0.3.0", ] -[[package]] -name = "sha-1" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f" -dependencies = [ - "cfg-if 1.0.0", - "cpufeatures 0.2.1", - "digest 0.10.3", -] - [[package]] name = "sha2" version = "0.8.2" @@ -6608,7 +6705,7 @@ dependencies = [ "httparse", "log 0.4.17", "rand 0.8.4", - "sha-1 0.9.8", + "sha-1", ] [[package]] @@ -6752,7 +6849,7 @@ dependencies = [ "solana-vote-program", "thiserror", "tokio", - "tungstenite 0.16.0", + "tungstenite", "url", ] @@ -6928,7 +7025,7 @@ checksum = "0a463f546a2f5842d35974bd4691ae5ceded6785ec24db440f773723f6ce4e11" dependencies = [ "base64 0.13.0", "bincode", - "bitflags", + "bitflags 1.3.2", "blake3", "borsh", "borsh-derive", @@ -7082,7 +7179,7 @@ dependencies = [ "assert_matches", "base64 0.13.0", "bincode", - "bitflags", + "bitflags 1.3.2", "borsh", "bs58", "bytemuck", @@ -7230,7 +7327,7 @@ version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77963e2aa8fadb589118c3aede2e78b6c4bcf1c01d588fbf33e915b390825fbd" dependencies = [ - "bitflags", + "bitflags 1.3.2", "byteorder 1.4.3", "hash-db", "hash256-std-hasher", @@ -7970,6 +8067,16 @@ dependencies = [ "syn 1.0.95", ] +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + [[package]] name = "tokio-rustls" version = "0.23.2" @@ -7994,18 +8101,33 @@ dependencies = [ [[package]] name = "tokio-tungstenite" -version = "0.17.2" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f714dd15bead90401d77e04243611caec13726c2408afd5b31901dfcdcb3b181" +checksum = "e80b39df6afcc12cdf752398ade96a6b9e99c903dfdc36e53ad10b9c366bca72" dependencies = [ "futures-util", "log 0.4.17", - "rustls 0.20.4", + "native-tls", "tokio", - "tokio-rustls", - "tungstenite 0.17.3", - "webpki 0.22.0", - "webpki-roots", + "tokio-native-tls", + "tungstenite", +] + +[[package]] +name = "tokio-tungstenite-wasm" +version = "0.1.1-alpha.0" +source = "git+https://github.com/KomodoPlatform/tokio-tungstenite-wasm?rev=d20abdb#d20abdbbb2f03e302e3a8d11a1736ec8b50d0f58" +dependencies = [ + "futures-channel", + "futures-util", + "http 0.2.7", + "httparse", + "js-sys", + "thiserror", + "tokio", + "tokio-tungstenite", + "wasm-bindgen", + "web-sys", ] [[package]] @@ -8106,7 +8228,7 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d342c6d58709c0a6d48d48dabbb62d4ef955cf5f0f3bbfd845838e7ae88dbae" dependencies = [ - "bitflags", + "bitflags 1.3.2", "bytes 1.1.0", "futures-core", "futures-util", @@ -8291,9 +8413,10 @@ dependencies = [ "http 0.2.7", "httparse", "log 0.4.17", + "native-tls", "rand 0.8.4", "rustls 0.20.4", - "sha-1 0.9.8", + "sha-1", "thiserror", "url", "utf-8", @@ -8301,27 +8424,6 @@ dependencies = [ "webpki-roots", ] -[[package]] -name = "tungstenite" -version = "0.17.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e27992fd6a8c29ee7eef28fc78349aa244134e10ad447ce3b9f0ac0ed0fa4ce0" -dependencies = [ - "base64 0.13.0", - "byteorder 1.4.3", - "bytes 1.1.0", - "http 0.2.7", - "httparse", - "log 0.4.17", - "rand 0.8.4", - "rustls 0.20.4", - "sha-1 0.10.0", - "thiserror", - "url", - "utf-8", - "webpki 0.22.0", -] - [[package]] name = "typenum" version = "1.15.0" @@ -8816,12 +8918,12 @@ version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" dependencies = [ - "windows_aarch64_gnullvm", + "windows_aarch64_gnullvm 0.42.1", "windows_aarch64_msvc 0.42.1", "windows_i686_gnu 0.42.1", "windows_i686_msvc 0.42.1", "windows_x86_64_gnu 0.42.1", - "windows_x86_64_gnullvm", + "windows_x86_64_gnullvm 0.42.1", "windows_x86_64_msvc 0.42.1", ] @@ -8831,7 +8933,16 @@ version = "0.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" dependencies = [ - "windows-targets", + "windows-targets 0.42.1", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", ] [[package]] @@ -8840,21 +8951,42 @@ version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7" dependencies = [ - "windows_aarch64_gnullvm", + "windows_aarch64_gnullvm 0.42.1", "windows_aarch64_msvc 0.42.1", "windows_i686_gnu 0.42.1", "windows_i686_msvc 0.42.1", "windows_x86_64_gnu 0.42.1", - "windows_x86_64_gnullvm", + "windows_x86_64_gnullvm 0.42.1", "windows_x86_64_msvc 0.42.1", ] +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + [[package]] name = "windows_aarch64_gnullvm" version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + [[package]] name = "windows_aarch64_msvc" version = "0.32.0" @@ -8867,6 +8999,12 @@ version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + [[package]] name = "windows_i686_gnu" version = "0.32.0" @@ -8879,6 +9017,12 @@ version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + [[package]] name = "windows_i686_msvc" version = "0.32.0" @@ -8891,6 +9035,12 @@ version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + [[package]] name = "windows_x86_64_gnu" version = "0.32.0" @@ -8903,12 +9053,24 @@ version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + [[package]] name = "windows_x86_64_gnullvm" version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + [[package]] name = "windows_x86_64_msvc" version = "0.32.0" @@ -8921,6 +9083,12 @@ version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + [[package]] name = "winreg" version = "0.7.0" diff --git a/mm2src/coins/Cargo.toml b/mm2src/coins/Cargo.toml index dcb6fbb8c1..ccc9b6e270 100644 --- a/mm2src/coins/Cargo.toml +++ b/mm2src/coins/Cargo.toml @@ -49,8 +49,9 @@ ethereum-types = { version = "0.13", default-features = false, features = ["std" ethkey = { git = "https://github.com/KomodoPlatform/mm2-parity-ethereum.git" } # Waiting for https://github.com/rust-lang/rust/issues/54725 to use on Stable. #enum_dispatch = "0.1" -ewebsock = { git = "https://github.com/KomodoPlatform/ewebsock.git", branch = "async", features = ["tls"] } +tokio-tungstenite-wasm = { git = "https://github.com/KomodoPlatform/tokio-tungstenite-wasm", rev = "d20abdb", features = ["native-tls"]} futures01 = { version = "0.1", package = "futures" } +futures-util = { version = "0.3", default-features = false, features = ["sink", "std"] } # using select macro requires the crate to be named futures, compilation failed with futures03 name futures = { version = "0.3", package = "futures", features = ["compat", "async-await"] } group = "0.8.0" diff --git a/mm2src/coins/coin_balance_event.rs b/mm2src/coins/coin_balance_event.rs index c0e0ee068c..124900b3fe 100644 --- a/mm2src/coins/coin_balance_event.rs +++ b/mm2src/coins/coin_balance_event.rs @@ -79,6 +79,7 @@ impl EventBehaviour for CoinBalanceEvent { MmCoinEnum::TendermintToken(inner) => { self.ctx.spawner().spawn(inner.handle_balance_stream(self.ctx.clone())) }, + #[cfg(not(target_arch = "wasm32"))] MmCoinEnum::LightningCoin(inner) => { self.ctx.spawner().spawn(inner.handle_balance_stream(self.ctx.clone())) }, diff --git a/mm2src/coins/tendermint/rpc/tendermint_wasm_rpc.rs b/mm2src/coins/tendermint/rpc/tendermint_wasm_rpc.rs index 036815a25f..bcbc07c874 100644 --- a/mm2src/coins/tendermint/rpc/tendermint_wasm_rpc.rs +++ b/mm2src/coins/tendermint/rpc/tendermint_wasm_rpc.rs @@ -58,6 +58,9 @@ impl HttpClient { Ok(HttpClient { uri: url.to_owned() }) } + #[inline] + pub fn uri(&self) -> http::Uri { Uri::from_str(&self.uri).expect("This should never happen.") } + pub(crate) async fn perform(&self, request: R) -> Result where R: SimpleRequest, diff --git a/mm2src/coins/tendermint/tendermint_coin.rs b/mm2src/coins/tendermint/tendermint_coin.rs index e3700d3d64..a463e7a0f9 100644 --- a/mm2src/coins/tendermint/tendermint_coin.rs +++ b/mm2src/coins/tendermint/tendermint_coin.rs @@ -54,11 +54,11 @@ use cosmrs::{AccountId, Any, Coin, Denom, ErrorReport}; use crypto::privkey::key_pair_from_secret; use crypto::{Secp256k1Secret, StandardHDCoinAddress, StandardHDPathToCoin}; use derive_more::Display; -use ewebsock::{WsEvent, WsMessage}; use futures::future::try_join_all; use futures::lock::Mutex as AsyncMutex; use futures::{FutureExt, TryFutureExt}; use futures01::Future; +use futures_util::{SinkExt, StreamExt}; use hex::FromHexError; use itertools::Itertools; use keys::KeyPair; @@ -1825,7 +1825,7 @@ impl TendermintCoin { } } - async fn active_ticker_and_decimals_from_denom(&self, denom: &str) -> Option<(String, u8)> { + fn active_ticker_and_decimals_from_denom(&self, denom: &str) -> Option<(String, u8)> { if self.denom.to_string() == denom { return Some((self.ticker.clone(), self.decimals)); } @@ -2233,10 +2233,10 @@ impl MmCoin for TendermintCoin { let mut current_balances: HashMap = HashMap::new(); let receiver_q = generate_subscription_query(format!("coin_received.receiver = '{}'", account_id)); - let receiver_q = ewebsock::WsMessage::Text(receiver_q); + let receiver_q = tokio_tungstenite_wasm::Message::Text(receiver_q); let spender_q = generate_subscription_query(format!("coin_spent.spender = '{}'", account_id)); - let spender_q = ewebsock::WsMessage::Text(spender_q); + let spender_q = tokio_tungstenite_wasm::Message::Text(spender_q); loop { let node_uri = match self.rpc_client().await { @@ -2249,7 +2249,7 @@ impl MmCoin for TendermintCoin { let socket_address = format!("{}/{}", http_uri_to_ws_address(node_uri), "websocket"); - let (mut sender, mut receiver) = match ewebsock::connect(socket_address, 100) { + let mut wsocket = match tokio_tungstenite_wasm::connect(socket_address).await { Ok(ws) => ws, Err(e) => { error!("{e}"); @@ -2258,15 +2258,22 @@ impl MmCoin for TendermintCoin { }; // Filter received TX events - sender.send(receiver_q.clone()); + if let Err(e) = wsocket.send(receiver_q.clone()).await { + error!("{e}"); + continue; + } // Filter spent TX events - sender.send(spender_q.clone()); + if let Err(e) = wsocket.send(spender_q.clone()).await { + error!("{e}"); + continue; + } - while let Some(message) = receiver.try_recv().await { - let msg = match &*message { - WsEvent::Message(WsMessage::Text(data)) => data.clone(), - WsEvent::Error(err) => { + while let Some(message) = wsocket.next().await { + let msg = match message { + Ok(tokio_tungstenite_wasm::Message::Text(data)) => data.clone(), + Ok(tokio_tungstenite_wasm::Message::Close(_)) => break, + Err(err) => { error!("{err}"); break; }, @@ -2290,7 +2297,7 @@ impl MmCoin for TendermintCoin { drop_mutability!(denoms); for denom in denoms { - if let Some((ticker, decimals)) = self.active_ticker_and_decimals_from_denom(&denom).await { + if let Some((ticker, decimals)) = self.active_ticker_and_decimals_from_denom(&denom) { let balance_denom = match self.account_balance_for_denom(&self.account_id, denom).await { Ok(balance_denom) => balance_denom, Err(e) => { diff --git a/mm2src/mm2_main/src/lp_native_dex.rs b/mm2src/mm2_main/src/lp_native_dex.rs index 6b0d80680f..624e27d876 100644 --- a/mm2src/mm2_main/src/lp_native_dex.rs +++ b/mm2src/mm2_main/src/lp_native_dex.rs @@ -19,7 +19,6 @@ // use bitcrypto::sha256; -use coins::coin_balance_event::CoinBalanceEvent; use coins::register_balance_update_handler; use common::executor::{SpawnFuture, Timer}; use common::log::{info, warn}; @@ -53,6 +52,7 @@ use crate::mm2::rpc::spawn_rpc; use mm2_event_stream::behaviour::EventBehaviour; use mm2_net::network_event::NetworkEvent; +use coins::coin_balance_event::CoinBalanceEvent; cfg_native! { use db_common::sqlite::rusqlite::Error as SqlError; From a2d6295e1928cd56a9b5b5c3ad07337be40ee27c Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Wed, 27 Sep 2023 11:29:07 +0300 Subject: [PATCH 36/48] enable rustls feature Signed-off-by: onur-ozkan --- Cargo.lock | 136 ++++++--------------------- mm2src/coins/Cargo.toml | 2 +- mm2src/mm2_main/src/lp_native_dex.rs | 2 +- 3 files changed, 33 insertions(+), 107 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8632ed0b3a..7beb59843e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -293,7 +293,7 @@ checksum = "acee9fd5073ab6b045a275b3e709c163dd36c90685219cb21804a147b58dba43" dependencies = [ "async-trait", "axum-core", - "bitflags 1.3.2", + "bitflags", "bytes 1.1.0", "futures-util", "http 0.2.7", @@ -502,12 +502,6 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" -[[package]] -name = "bitflags" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" - [[package]] name = "bitvec" version = "0.18.5" @@ -936,7 +930,7 @@ checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" dependencies = [ "ansi_term", "atty", - "bitflags 1.3.2", + "bitflags", "strsim", "textwrap", "unicode-width", @@ -949,7 +943,7 @@ version = "0.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" dependencies = [ - "bitflags 1.3.2", + "bitflags", ] [[package]] @@ -958,7 +952,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4344512281c643ae7638bbabc3af17a11307803ec8f0fcad9fae512a8bf36467" dependencies = [ - "bitflags 1.3.2", + "bitflags", ] [[package]] @@ -2333,21 +2327,6 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - [[package]] name = "form_urlencoded" version = "1.0.1" @@ -3329,7 +3308,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6607c62aa161d23d17a9072cc5da0be67cdfc89d3afb1e8d9c842bebc2525ffe" dependencies = [ "arrayvec 0.5.1", - "bitflags 1.3.2", + "bitflags", "cfg-if 1.0.0", "ryu", "static_assertions", @@ -4596,24 +4575,6 @@ dependencies = [ "unsigned-varint 0.7.1", ] -[[package]] -name = "native-tls" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" -dependencies = [ - "lazy_static", - "libc", - "log 0.4.17", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", -] - [[package]] name = "nibble_vec" version = "0.1.0" @@ -4629,7 +4590,7 @@ version = "0.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f866317acbd3a240710c63f065ffb1e4fd466259045ccb504130b7f668f35c6" dependencies = [ - "bitflags 1.3.2", + "bitflags", "cc", "cfg-if 1.0.0", "libc", @@ -4784,50 +4745,12 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" -[[package]] -name = "openssl" -version = "0.10.57" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bac25ee399abb46215765b1cb35bc0212377e58a061560d8b29b024fd0430e7c" -dependencies = [ - "bitflags 2.4.0", - "cfg-if 1.0.0", - "foreign-types", - "libc", - "once_cell", - "openssl-macros", - "openssl-sys", -] - -[[package]] -name = "openssl-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" -dependencies = [ - "proc-macro2 1.0.58", - "quote 1.0.27", - "syn 2.0.16", -] - [[package]] name = "openssl-probe" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" -[[package]] -name = "openssl-sys" -version = "0.9.93" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db4d56a4c0478783083cfafcc42493dd4a981d41669da64b4572a2a089b51b1d" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - [[package]] name = "ordered-float" version = "3.7.0" @@ -5737,7 +5660,7 @@ version = "10.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c49596760fce12ca21550ac21dc5a9617b2ea4b6e0aa7d8dab8ff2824fc2bba" dependencies = [ - "bitflags 1.3.2", + "bitflags", ] [[package]] @@ -5798,7 +5721,7 @@ version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" dependencies = [ - "bitflags 1.3.2", + "bitflags", ] [[package]] @@ -6034,7 +5957,7 @@ version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "01e213bc3ecb39ac32e81e51ebe31fd888a940515173e3a18a35f8c6e896422a" dependencies = [ - "bitflags 1.3.2", + "bitflags", "fallible-iterator", "fallible-streaming-iterator", "hashlink", @@ -6103,7 +6026,7 @@ version = "0.36.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd5c6ff11fecd55b40746d1995a02f2eb375bf8c00d192d521ee09f42bef37bc" dependencies = [ - "bitflags 1.3.2", + "bitflags", "errno", "io-lifetimes", "libc", @@ -6136,6 +6059,18 @@ dependencies = [ "webpki 0.22.0", ] +[[package]] +name = "rustls-native-certs" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" +dependencies = [ + "openssl-probe", + "rustls-pemfile 1.0.2", + "schannel", + "security-framework", +] + [[package]] name = "rustls-pemfile" version = "0.2.1" @@ -6336,7 +6271,7 @@ version = "2.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" dependencies = [ - "bitflags 1.3.2", + "bitflags", "core-foundation", "core-foundation-sys", "libc", @@ -7025,7 +6960,7 @@ checksum = "0a463f546a2f5842d35974bd4691ae5ceded6785ec24db440f773723f6ce4e11" dependencies = [ "base64 0.13.0", "bincode", - "bitflags 1.3.2", + "bitflags", "blake3", "borsh", "borsh-derive", @@ -7179,7 +7114,7 @@ dependencies = [ "assert_matches", "base64 0.13.0", "bincode", - "bitflags 1.3.2", + "bitflags", "borsh", "bs58", "bytemuck", @@ -7327,7 +7262,7 @@ version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77963e2aa8fadb589118c3aede2e78b6c4bcf1c01d588fbf33e915b390825fbd" dependencies = [ - "bitflags 1.3.2", + "bitflags", "byteorder 1.4.3", "hash-db", "hash256-std-hasher", @@ -8067,16 +8002,6 @@ dependencies = [ "syn 1.0.95", ] -[[package]] -name = "tokio-native-tls" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" -dependencies = [ - "native-tls", - "tokio", -] - [[package]] name = "tokio-rustls" version = "0.23.2" @@ -8107,10 +8032,12 @@ checksum = "e80b39df6afcc12cdf752398ade96a6b9e99c903dfdc36e53ad10b9c366bca72" dependencies = [ "futures-util", "log 0.4.17", - "native-tls", + "rustls 0.20.4", + "rustls-native-certs", "tokio", - "tokio-native-tls", + "tokio-rustls", "tungstenite", + "webpki 0.22.0", ] [[package]] @@ -8228,7 +8155,7 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d342c6d58709c0a6d48d48dabbb62d4ef955cf5f0f3bbfd845838e7ae88dbae" dependencies = [ - "bitflags 1.3.2", + "bitflags", "bytes 1.1.0", "futures-core", "futures-util", @@ -8413,7 +8340,6 @@ dependencies = [ "http 0.2.7", "httparse", "log 0.4.17", - "native-tls", "rand 0.8.4", "rustls 0.20.4", "sha-1", diff --git a/mm2src/coins/Cargo.toml b/mm2src/coins/Cargo.toml index ccc9b6e270..ec8c7e5efc 100644 --- a/mm2src/coins/Cargo.toml +++ b/mm2src/coins/Cargo.toml @@ -49,7 +49,7 @@ ethereum-types = { version = "0.13", default-features = false, features = ["std" ethkey = { git = "https://github.com/KomodoPlatform/mm2-parity-ethereum.git" } # Waiting for https://github.com/rust-lang/rust/issues/54725 to use on Stable. #enum_dispatch = "0.1" -tokio-tungstenite-wasm = { git = "https://github.com/KomodoPlatform/tokio-tungstenite-wasm", rev = "d20abdb", features = ["native-tls"]} +tokio-tungstenite-wasm = { git = "https://github.com/KomodoPlatform/tokio-tungstenite-wasm", rev = "d20abdb", features = ["rustls-tls-native-roots"]} futures01 = { version = "0.1", package = "futures" } futures-util = { version = "0.3", default-features = false, features = ["sink", "std"] } # using select macro requires the crate to be named futures, compilation failed with futures03 name diff --git a/mm2src/mm2_main/src/lp_native_dex.rs b/mm2src/mm2_main/src/lp_native_dex.rs index 624e27d876..a6e2c66948 100644 --- a/mm2src/mm2_main/src/lp_native_dex.rs +++ b/mm2src/mm2_main/src/lp_native_dex.rs @@ -50,9 +50,9 @@ use crate::mm2::lp_ordermatch::{broadcast_maker_orders_keep_alive_loop, clean_me use crate::mm2::lp_swap::{running_swaps_num, swap_kick_starts}; use crate::mm2::rpc::spawn_rpc; +use coins::coin_balance_event::CoinBalanceEvent; use mm2_event_stream::behaviour::EventBehaviour; use mm2_net::network_event::NetworkEvent; -use coins::coin_balance_event::CoinBalanceEvent; cfg_native! { use db_common::sqlite::rusqlite::Error as SqlError; From e62695005bc387015de43899c8b73fcf41bbaf82 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Thu, 28 Sep 2023 11:57:19 +0300 Subject: [PATCH 37/48] broadcast network events only when data changes Signed-off-by: onur-ozkan --- mm2src/mm2_event_stream/src/lib.rs | 3 +++ mm2src/mm2_libp2p/src/atomicdex_behaviour.rs | 18 +++++++++--------- mm2src/mm2_net/src/network_event.rs | 14 ++++++++++---- 3 files changed, 22 insertions(+), 13 deletions(-) diff --git a/mm2src/mm2_event_stream/src/lib.rs b/mm2src/mm2_event_stream/src/lib.rs index afa5c7e1be..cc3b86f7d5 100644 --- a/mm2src/mm2_event_stream/src/lib.rs +++ b/mm2src/mm2_event_stream/src/lib.rs @@ -40,9 +40,12 @@ pub struct EventStreamConfiguration { #[derive(Clone, Default, Deserialize)] pub struct EventConfig { /// The interval in seconds at which the event should be streamed. + #[serde(default = "default_stream_interval")] pub stream_interval_seconds: f64, } +const fn default_stream_interval() -> f64 { 5. } + impl Default for EventStreamConfiguration { fn default() -> Self { Self { diff --git a/mm2src/mm2_libp2p/src/atomicdex_behaviour.rs b/mm2src/mm2_libp2p/src/atomicdex_behaviour.rs index 56dc93cbb5..a1dc3ccccc 100644 --- a/mm2src/mm2_libp2p/src/atomicdex_behaviour.rs +++ b/mm2src/mm2_libp2p/src/atomicdex_behaviour.rs @@ -26,7 +26,7 @@ use libp2p_floodsub::{Floodsub, FloodsubEvent, Topic as FloodsubTopic}; use log::{debug, error, info}; use rand::seq::SliceRandom; use rand::Rng; -use std::{collections::hash_map::{DefaultHasher, HashMap}, +use std::{collections::{hash_map::DefaultHasher, BTreeMap}, hash::{Hash, Hasher}, iter, net::IpAddr, @@ -47,7 +47,7 @@ const ANNOUNCE_INITIAL_DELAY: Duration = Duration::from_secs(60); const CHANNEL_BUF_SIZE: usize = 1024 * 8; /// Returns info about connected peers -pub async fn get_peers_info(mut cmd_tx: AdexCmdTx) -> HashMap> { +pub async fn get_peers_info(mut cmd_tx: AdexCmdTx) -> BTreeMap> { let (result_tx, rx) = oneshot::channel(); let cmd = AdexBehaviourCmd::GetPeersInfo { result_tx }; cmd_tx.send(cmd).await.expect("Rx should be present"); @@ -55,21 +55,21 @@ pub async fn get_peers_info(mut cmd_tx: AdexCmdTx) -> HashMap HashMap> { +pub async fn get_gossip_mesh(mut cmd_tx: AdexCmdTx) -> BTreeMap> { let (result_tx, rx) = oneshot::channel(); let cmd = AdexBehaviourCmd::GetGossipMesh { result_tx }; cmd_tx.send(cmd).await.expect("Rx should be present"); rx.await.expect("Tx should be present") } -pub async fn get_gossip_peer_topics(mut cmd_tx: AdexCmdTx) -> HashMap> { +pub async fn get_gossip_peer_topics(mut cmd_tx: AdexCmdTx) -> BTreeMap> { let (result_tx, rx) = oneshot::channel(); let cmd = AdexBehaviourCmd::GetGossipPeerTopics { result_tx }; cmd_tx.send(cmd).await.expect("Rx should be present"); rx.await.expect("Tx should be present") } -pub async fn get_gossip_topic_peers(mut cmd_tx: AdexCmdTx) -> HashMap> { +pub async fn get_gossip_topic_peers(mut cmd_tx: AdexCmdTx) -> BTreeMap> { let (result_tx, rx) = oneshot::channel(); let cmd = AdexBehaviourCmd::GetGossipTopicPeers { result_tx }; cmd_tx.send(cmd).await.expect("Rx should be present"); @@ -133,16 +133,16 @@ pub enum AdexBehaviourCmd { response_channel: AdexResponseChannel, }, GetPeersInfo { - result_tx: oneshot::Sender>>, + result_tx: oneshot::Sender>>, }, GetGossipMesh { - result_tx: oneshot::Sender>>, + result_tx: oneshot::Sender>>, }, GetGossipPeerTopics { - result_tx: oneshot::Sender>>, + result_tx: oneshot::Sender>>, }, GetGossipTopicPeers { - result_tx: oneshot::Sender>>, + result_tx: oneshot::Sender>>, }, GetRelayMesh { result_tx: oneshot::Sender>, diff --git a/mm2src/mm2_net/src/network_event.rs b/mm2src/mm2_net/src/network_event.rs index 6dd5ee4396..14d3971529 100644 --- a/mm2src/mm2_net/src/network_event.rs +++ b/mm2src/mm2_net/src/network_event.rs @@ -23,6 +23,8 @@ impl EventBehaviour for NetworkEvent { async fn handle(self, interval: f64) { let p2p_ctx = P2PContext::fetch_from_mm_arc(&self.ctx); + let mut previously_sent = json!({}); + loop { let p2p_cmd_tx = p2p_ctx.cmd_tx.lock().clone(); @@ -40,10 +42,14 @@ impl EventBehaviour for NetworkEvent { "relay_mesh": relay_mesh, }); - self.ctx - .stream_channel_controller - .broadcast(Event::new(Self::EVENT_NAME.to_string(), event_data.to_string())) - .await; + if previously_sent != event_data { + self.ctx + .stream_channel_controller + .broadcast(Event::new(Self::EVENT_NAME.to_string(), event_data.to_string())) + .await; + + previously_sent = event_data; + } Timer::sleep(interval).await; } From c3afd298b7c5b5fc845ed1f2834eb9edb52136dc Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Wed, 4 Oct 2023 11:37:51 +0300 Subject: [PATCH 38/48] refactor balance stream impl design Signed-off-by: onur-ozkan --- Cargo.lock | 1 + mm2src/coins/coin_balance_event.rs | 124 -------------- mm2src/coins/eth.rs | 2 - mm2src/coins/lightning.rs | 2 - mm2src/coins/lp_coins.rs | 5 - mm2src/coins/qrc20.rs | 2 - mm2src/coins/solana.rs | 2 - mm2src/coins/solana/spl.rs | 2 - mm2src/coins/tendermint/mod.rs | 1 + .../tendermint/tendermint_balance_events.rs | 154 ++++++++++++++++++ mm2src/coins/tendermint/tendermint_coin.rs | 133 +-------------- mm2src/coins/tendermint/tendermint_token.rs | 6 +- mm2src/coins/test_coin.rs | 2 - mm2src/coins/utxo/bch.rs | 2 - mm2src/coins/utxo/qtum.rs | 2 - mm2src/coins/utxo/slp.rs | 2 - mm2src/coins/utxo/utxo_standard.rs | 2 - mm2src/coins/z_coin.rs | 2 - mm2src/coins_activation/Cargo.toml | 1 + .../src/bch_with_tokens_activation.rs | 3 + .../src/eth_with_token_activation.rs | 3 + .../src/platform_coin_with_tokens.rs | 7 + .../src/solana_with_tokens_activation.rs | 3 + .../src/tendermint_with_assets_activation.rs | 6 + mm2src/mm2_main/src/lp_native_dex.rs | 3 - 25 files changed, 185 insertions(+), 287 deletions(-) delete mode 100644 mm2src/coins/coin_balance_event.rs create mode 100644 mm2src/coins/tendermint/tendermint_balance_events.rs diff --git a/Cargo.lock b/Cargo.lock index aaedcd6274..94b003f869 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1125,6 +1125,7 @@ dependencies = [ "lightning-invoice", "mm2_core", "mm2_err_handle", + "mm2_event_stream", "mm2_metamask", "mm2_metrics", "mm2_number", diff --git a/mm2src/coins/coin_balance_event.rs b/mm2src/coins/coin_balance_event.rs deleted file mode 100644 index 124900b3fe..0000000000 --- a/mm2src/coins/coin_balance_event.rs +++ /dev/null @@ -1,124 +0,0 @@ -use crate::{CoinsContext, MmCoin, MmCoinEnum}; -use async_trait::async_trait; -use common::{executor::{SpawnFuture, Timer}, - log::info}; -use mm2_core::mm_ctx::MmArc; -use mm2_event_stream::{behaviour::EventBehaviour, EventStreamConfiguration}; -use std::sync::atomic::Ordering; - -/// Event tag for broadcasting balance events -pub(crate) const COIN_BALANCE_EVENT_TAG: &str = "COIN_BALANCE"; - -pub struct CoinBalanceEvent { - ctx: MmArc, -} - -impl CoinBalanceEvent { - pub fn new(ctx: MmArc) -> Self { Self { ctx } } -} - -#[async_trait] -impl EventBehaviour for CoinBalanceEvent { - const EVENT_NAME: &'static str = COIN_BALANCE_EVENT_TAG; - - async fn handle(self, _interval: f64) { - let cctx = CoinsContext::from_ctx(&self.ctx).expect("Unexpected internal panic."); - - // Events that are already fired - let mut event_pool: Vec = vec![]; - - loop { - let coins_mutex = cctx.coins.lock().await; - - let coins: Vec = coins_mutex - .values() - .filter_map(|coin| { - // We loop this over and over, so it's not necessary to sequentially load the atomics all over - // the threads, since the cost of it is way too higher than the `AtomicOrdering::Relaxed` - if coin.is_available.load(Ordering::Relaxed) { - Some(coin.inner.clone()) - } else { - None - } - }) - .collect(); - - // Similar to above, we don't need to held the lock(which will block all other processes that depends - // on this lock(like coin activation)) since we loop this over continuously. - drop(coins_mutex); - - // Handle balance streaming concurrently for each coin - for coin in coins { - let ticker = coin.ticker().to_owned(); - - if event_pool.contains(&ticker) { - continue; - } - - match coin { - MmCoinEnum::UtxoCoin(inner) => { - self.ctx.spawner().spawn(inner.handle_balance_stream(self.ctx.clone())) - }, - MmCoinEnum::QtumCoin(inner) => { - self.ctx.spawner().spawn(inner.handle_balance_stream(self.ctx.clone())) - }, - MmCoinEnum::Qrc20Coin(inner) => { - self.ctx.spawner().spawn(inner.handle_balance_stream(self.ctx.clone())) - }, - MmCoinEnum::EthCoin(inner) => { - self.ctx.spawner().spawn(inner.handle_balance_stream(self.ctx.clone())) - }, - MmCoinEnum::ZCoin(inner) => self.ctx.spawner().spawn(inner.handle_balance_stream(self.ctx.clone())), - MmCoinEnum::Bch(inner) => self.ctx.spawner().spawn(inner.handle_balance_stream(self.ctx.clone())), - MmCoinEnum::SlpToken(inner) => { - self.ctx.spawner().spawn(inner.handle_balance_stream(self.ctx.clone())) - }, - MmCoinEnum::Tendermint(inner) => { - self.ctx.spawner().spawn(inner.handle_balance_stream(self.ctx.clone())) - }, - MmCoinEnum::TendermintToken(inner) => { - self.ctx.spawner().spawn(inner.handle_balance_stream(self.ctx.clone())) - }, - #[cfg(not(target_arch = "wasm32"))] - MmCoinEnum::LightningCoin(inner) => { - self.ctx.spawner().spawn(inner.handle_balance_stream(self.ctx.clone())) - }, - MmCoinEnum::Test(inner) => self.ctx.spawner().spawn(inner.handle_balance_stream(self.ctx.clone())), - #[cfg(all( - feature = "enable-solana", - not(target_os = "ios"), - not(target_os = "android"), - not(target_arch = "wasm32") - ))] - MmCoinEnum::SolanaCoin(inner) => { - self.ctx.spawner().spawn(inner.handle_balance_stream(self.ctx.clone())) - }, - #[cfg(all( - feature = "enable-solana", - not(target_os = "ios"), - not(target_os = "android"), - not(target_arch = "wasm32") - ))] - MmCoinEnum::SplToken(inner) => { - self.ctx.spawner().spawn(inner.handle_balance_stream(self.ctx.clone())) - }, - } - - event_pool.push(ticker); - } - - Timer::sleep(5.).await; - } - } - - fn spawn_if_active(self, config: &EventStreamConfiguration) { - if let Some(event) = config.get_event(Self::EVENT_NAME) { - info!( - "{} event is activated. `stream_interval_seconds`({}) has no effect for this event.", - Self::EVENT_NAME, - event.stream_interval_seconds - ); - self.ctx.spawner().spawn(self.handle(event.stream_interval_seconds)); - } - } -} diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 49b4056e13..ef20bcd52e 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -4743,8 +4743,6 @@ impl MmCoin for EthCoin { tokens.remove(ticker); }; } - - async fn handle_balance_stream(self, _ctx: MmArc) { todo!() } } pub trait TryToAddress { diff --git a/mm2src/coins/lightning.rs b/mm2src/coins/lightning.rs index 44b2c2f9dc..59b026121b 100644 --- a/mm2src/coins/lightning.rs +++ b/mm2src/coins/lightning.rs @@ -1452,6 +1452,4 @@ impl MmCoin for LightningCoin { fn on_disabled(&self) -> Result<(), AbortedError> { AbortableSystem::abort_all(&self.platform.abortable_system) } fn on_token_deactivated(&self, _ticker: &str) {} - - async fn handle_balance_stream(self, _ctx: MmArc) { todo!() } } diff --git a/mm2src/coins/lp_coins.rs b/mm2src/coins/lp_coins.rs index 92b65b81b2..564863ad98 100644 --- a/mm2src/coins/lp_coins.rs +++ b/mm2src/coins/lp_coins.rs @@ -250,8 +250,6 @@ pub use test_coin::TestCoin; pub mod tx_history_storage; -pub mod coin_balance_event; - #[doc(hidden)] #[allow(unused_variables)] #[cfg(all( @@ -2578,9 +2576,6 @@ pub trait MmCoin: /// For Handling the removal/deactivation of token on platform coin deactivation. fn on_token_deactivated(&self, ticker: &str); - - // Handler for coin balance streaming continuously to the thread/stream channels - async fn handle_balance_stream(self, ctx: MmArc); } /// The coin futures spawner. It's used to spawn futures that can be aborted immediately or after a timeout diff --git a/mm2src/coins/qrc20.rs b/mm2src/coins/qrc20.rs index 6ad1fa91e9..68cdf5a35a 100644 --- a/mm2src/coins/qrc20.rs +++ b/mm2src/coins/qrc20.rs @@ -1486,8 +1486,6 @@ impl MmCoin for Qrc20Coin { fn on_disabled(&self) -> Result<(), AbortedError> { AbortableSystem::abort_all(&self.as_ref().abortable_system) } fn on_token_deactivated(&self, _ticker: &str) {} - - async fn handle_balance_stream(self, _ctx: MmArc) { todo!() } } pub fn qrc20_swap_id(time_lock: u32, secret_hash: &[u8]) -> Vec { diff --git a/mm2src/coins/solana.rs b/mm2src/coins/solana.rs index 2a485e0ab9..5f7bb9e44d 100644 --- a/mm2src/coins/solana.rs +++ b/mm2src/coins/solana.rs @@ -776,6 +776,4 @@ impl MmCoin for SolanaCoin { fn on_disabled(&self) -> Result<(), AbortedError> { AbortableSystem::abort_all(&self.abortable_system) } fn on_token_deactivated(&self, _ticker: &str) {} - - async fn handle_balance_stream(self, _ctx: MmArc) { todo!() } } diff --git a/mm2src/coins/solana/spl.rs b/mm2src/coins/solana/spl.rs index 8d39787de1..134d8204ba 100644 --- a/mm2src/coins/solana/spl.rs +++ b/mm2src/coins/solana/spl.rs @@ -570,6 +570,4 @@ impl MmCoin for SplToken { fn on_disabled(&self) -> Result<(), AbortedError> { self.conf.abortable_system.abort_all() } fn on_token_deactivated(&self, _ticker: &str) {} - - async fn handle_balance_stream(self, _ctx: MmArc) { todo!() } } diff --git a/mm2src/coins/tendermint/mod.rs b/mm2src/coins/tendermint/mod.rs index d480a4964e..400d95071c 100644 --- a/mm2src/coins/tendermint/mod.rs +++ b/mm2src/coins/tendermint/mod.rs @@ -5,6 +5,7 @@ mod ibc; mod iris; mod rpc; +pub mod tendermint_balance_events; mod tendermint_coin; mod tendermint_token; pub mod tendermint_tx_history_v2; diff --git a/mm2src/coins/tendermint/tendermint_balance_events.rs b/mm2src/coins/tendermint/tendermint_balance_events.rs new file mode 100644 index 0000000000..df6e3489ab --- /dev/null +++ b/mm2src/coins/tendermint/tendermint_balance_events.rs @@ -0,0 +1,154 @@ +use async_trait::async_trait; +use common::{executor::{AbortSettings, SpawnAbortable}, + http_uri_to_ws_address, log}; +use futures_util::{SinkExt, StreamExt}; +use mm2_event_stream::{behaviour::EventBehaviour, Event, EventStreamConfiguration}; +use mm2_number::BigDecimal; +use std::collections::HashMap; + +use super::TendermintCoin; +use crate::{tendermint::TendermintCommons, utxo::utxo_common::big_decimal_from_sat_unsigned, MarketCoinOps, MmCoin}; + +#[async_trait] +impl EventBehaviour for TendermintCoin { + const EVENT_NAME: &'static str = "COIN_BALANCE"; + + async fn handle(self, _interval: f64) { + fn generate_subscription_query(query_filter: String) -> String { + let q = json!({ + "jsonrpc": "2.0", + "method": "subscribe", + "id": 0, + "params": { + "query": query_filter + } + }); + + q.to_string() + } + + let account_id = self.account_id.to_string(); + let mut current_balances: HashMap = HashMap::new(); + + let receiver_q = generate_subscription_query(format!("coin_received.receiver = '{}'", account_id)); + let receiver_q = tokio_tungstenite_wasm::Message::Text(receiver_q); + + let spender_q = generate_subscription_query(format!("coin_spent.spender = '{}'", account_id)); + let spender_q = tokio_tungstenite_wasm::Message::Text(spender_q); + + loop { + let node_uri = match self.rpc_client().await { + Ok(client) => client.uri(), + Err(e) => { + log::error!("{e}"); + continue; + }, + }; + + let socket_address = format!("{}/{}", http_uri_to_ws_address(node_uri), "websocket"); + + let mut wsocket = match tokio_tungstenite_wasm::connect(socket_address).await { + Ok(ws) => ws, + Err(e) => { + log::error!("{e}"); + continue; + }, + }; + + // Filter received TX events + if let Err(e) = wsocket.send(receiver_q.clone()).await { + log::error!("{e}"); + continue; + } + + // Filter spent TX events + if let Err(e) = wsocket.send(spender_q.clone()).await { + log::error!("{e}"); + continue; + } + + while let Some(message) = wsocket.next().await { + let msg = match message { + Ok(tokio_tungstenite_wasm::Message::Text(data)) => data.clone(), + Ok(tokio_tungstenite_wasm::Message::Close(_)) => break, + Err(err) => { + log::error!("{err}"); + break; + }, + _ => continue, + }; + + if let Ok(json_val) = serde_json::from_str::(&msg) { + let transfers: Vec = + serde_json::from_value(json_val["result"]["events"]["transfer.amount"].clone()) + .unwrap_or_default(); + + let mut denoms: Vec = transfers + .iter() + .map(|t| { + let amount: String = t.chars().take_while(|c| c.is_numeric()).collect(); + let denom = &t[amount.len()..]; + denom.to_owned() + }) + .collect(); + + denoms.dedup(); + drop_mutability!(denoms); + + for denom in denoms { + if let Some((ticker, decimals)) = self.active_ticker_and_decimals_from_denom(&denom) { + let balance_denom = match self.account_balance_for_denom(&self.account_id, denom).await { + Ok(balance_denom) => balance_denom, + Err(e) => { + log::error!("{e}"); + continue; + }, + }; + + let balance_decimal = big_decimal_from_sat_unsigned(balance_denom, decimals); + + // Only broadcast when balance is changed + let mut broadcast = false; + if let Some(balance) = current_balances.get_mut(&ticker) { + if *balance != balance_decimal { + *balance = balance_decimal.clone(); + broadcast = true; + } + } else { + current_balances.insert(ticker.clone(), balance_decimal.clone()); + broadcast = true; + } + + if broadcast { + let payload = json!({ + "ticker": ticker, + "balance": { "spendable": balance_decimal, "unspendable": BigDecimal::default() } + }); + + self.ctx + .stream_channel_controller + .broadcast(Event::new(Self::EVENT_NAME.to_string(), payload.to_string())) + .await; + } + } + } + } + } + } + } + + fn spawn_if_active(self, config: &EventStreamConfiguration) { + if let Some(event) = config.get_event(Self::EVENT_NAME) { + log::info!( + "{} event is activated. `stream_interval_seconds`({}) has no effect for this event.", + Self::EVENT_NAME, + event.stream_interval_seconds + ); + + let fut = self.clone().handle(event.stream_interval_seconds); + let settings = + AbortSettings::info_on_abort(format!("Balance streaming stopped for {}", self.ticker().to_owned())); + self.spawner().spawn_with_settings(fut, settings); + } + } +} diff --git a/mm2src/coins/tendermint/tendermint_coin.rs b/mm2src/coins/tendermint/tendermint_coin.rs index 97a2947277..9885fd482c 100644 --- a/mm2src/coins/tendermint/tendermint_coin.rs +++ b/mm2src/coins/tendermint/tendermint_coin.rs @@ -5,7 +5,6 @@ use super::iris::htlc::{IrisHtlc, MsgClaimHtlc, MsgCreateHtlc, HTLC_STATE_COMPLE HTLC_STATE_REFUNDED}; use super::iris::htlc_proto::{CreateHtlcProtoRep, QueryHtlcRequestProto, QueryHtlcResponseProto}; use super::rpc::*; -use crate::coin_balance_event::COIN_BALANCE_EVENT_TAG; use crate::coin_errors::{MyAddressError, ValidatePaymentError}; use crate::rpc_command::tendermint::{IBCChainRegistriesResponse, IBCChainRegistriesResult, IBCChainsRequestError, IBCTransferChannel, IBCTransferChannelTag, IBCTransferChannelsRequest, @@ -35,8 +34,8 @@ use async_trait::async_trait; use bitcrypto::{dhash160, sha256}; use common::executor::{abortable_queue::AbortableQueue, AbortableSystem}; use common::executor::{AbortedError, Timer}; -use common::log::{debug, error, warn}; -use common::{get_utc_timestamp, http_uri_to_ws_address, now_sec, Future01CompatExt, DEX_FEE_ADDR_PUBKEY}; +use common::log::{debug, warn}; +use common::{get_utc_timestamp, now_sec, Future01CompatExt, DEX_FEE_ADDR_PUBKEY}; use cosmrs::bank::MsgSend; use cosmrs::crypto::secp256k1::SigningKey; use cosmrs::proto::cosmos::auth::v1beta1::{BaseAccount, QueryAccountRequest, QueryAccountResponse}; @@ -58,13 +57,11 @@ use futures::future::try_join_all; use futures::lock::Mutex as AsyncMutex; use futures::{FutureExt, TryFutureExt}; use futures01::Future; -use futures_util::{SinkExt, StreamExt}; use hex::FromHexError; use itertools::Itertools; use keys::KeyPair; use mm2_core::mm_ctx::MmArc; use mm2_err_handle::prelude::*; -use mm2_event_stream::Event; use mm2_git::{FileMetadata, GitController, GithubClient, RepositoryOperations, GITHUB_API_URI}; use mm2_number::MmNumber; use parking_lot::Mutex as PaMutex; @@ -240,6 +237,7 @@ pub struct TendermintCoinImpl { pub(crate) history_sync_state: Mutex, client: TendermintRpcClient, chain_registry_name: Option, + pub(crate) ctx: MmArc, } #[derive(Clone)] @@ -547,6 +545,7 @@ impl TendermintCoin { history_sync_state: Mutex::new(history_sync_state), client: TendermintRpcClient(AsyncMutex::new(client_impl)), chain_registry_name: protocol_info.chain_registry_name, + ctx: ctx.clone(), }))) } @@ -1825,7 +1824,7 @@ impl TendermintCoin { } } - fn active_ticker_and_decimals_from_denom(&self, denom: &str) -> Option<(String, u8)> { + pub(crate) fn active_ticker_and_decimals_from_denom(&self, denom: &str) -> Option<(String, u8)> { if self.denom.to_string() == denom { return Some((self.ticker.clone(), self.decimals)); } @@ -2214,128 +2213,6 @@ impl MmCoin for TendermintCoin { fn on_disabled(&self) -> Result<(), AbortedError> { AbortableSystem::abort_all(&self.abortable_system) } fn on_token_deactivated(&self, _ticker: &str) {} - - async fn handle_balance_stream(self, ctx: MmArc) { - fn generate_subscription_query(query_filter: String) -> String { - let q = json!({ - "jsonrpc": "2.0", - "method": "subscribe", - "id": 0, - "params": { - "query": query_filter - } - }); - - q.to_string() - } - - let account_id = self.account_id.to_string(); - let mut current_balances: HashMap = HashMap::new(); - - let receiver_q = generate_subscription_query(format!("coin_received.receiver = '{}'", account_id)); - let receiver_q = tokio_tungstenite_wasm::Message::Text(receiver_q); - - let spender_q = generate_subscription_query(format!("coin_spent.spender = '{}'", account_id)); - let spender_q = tokio_tungstenite_wasm::Message::Text(spender_q); - - loop { - let node_uri = match self.rpc_client().await { - Ok(client) => client.uri(), - Err(e) => { - error!("{e}"); - continue; - }, - }; - - let socket_address = format!("{}/{}", http_uri_to_ws_address(node_uri), "websocket"); - - let mut wsocket = match tokio_tungstenite_wasm::connect(socket_address).await { - Ok(ws) => ws, - Err(e) => { - error!("{e}"); - continue; - }, - }; - - // Filter received TX events - if let Err(e) = wsocket.send(receiver_q.clone()).await { - error!("{e}"); - continue; - } - - // Filter spent TX events - if let Err(e) = wsocket.send(spender_q.clone()).await { - error!("{e}"); - continue; - } - - while let Some(message) = wsocket.next().await { - let msg = match message { - Ok(tokio_tungstenite_wasm::Message::Text(data)) => data.clone(), - Ok(tokio_tungstenite_wasm::Message::Close(_)) => break, - Err(err) => { - error!("{err}"); - break; - }, - _ => continue, - }; - - if let Ok(json_val) = json::from_str::(&msg) { - let transfers: Vec = - json::from_value(json_val["result"]["events"]["transfer.amount"].clone()).unwrap_or_default(); - - let mut denoms: Vec = transfers - .iter() - .map(|t| { - let amount: String = t.chars().take_while(|c| c.is_numeric()).collect(); - let denom = &t[amount.len()..]; - denom.to_owned() - }) - .collect(); - - denoms.dedup(); - drop_mutability!(denoms); - - for denom in denoms { - if let Some((ticker, decimals)) = self.active_ticker_and_decimals_from_denom(&denom) { - let balance_denom = match self.account_balance_for_denom(&self.account_id, denom).await { - Ok(balance_denom) => balance_denom, - Err(e) => { - error!("{e}"); - continue; - }, - }; - - let balance_decimal = big_decimal_from_sat_unsigned(balance_denom, decimals); - - // Only broadcast when balance is changed - let mut broadcast = false; - if let Some(balance) = current_balances.get_mut(&ticker) { - if *balance != balance_decimal { - *balance = balance_decimal.clone(); - broadcast = true; - } - } else { - current_balances.insert(ticker.clone(), balance_decimal.clone()); - broadcast = true; - } - - if broadcast { - let payload = json!({ - "ticker": ticker, - "balance": { "spendable": balance_decimal, "unspendable": BigDecimal::default() } - }); - - ctx.stream_channel_controller - .broadcast(Event::new(COIN_BALANCE_EVENT_TAG.to_string(), payload.to_string())) - .await; - } - } - } - } - } - } - } } impl MarketCoinOps for TendermintCoin { diff --git a/mm2src/coins/tendermint/tendermint_token.rs b/mm2src/coins/tendermint/tendermint_token.rs index ba3025ae63..ab1c3573c3 100644 --- a/mm2src/coins/tendermint/tendermint_token.rs +++ b/mm2src/coins/tendermint/tendermint_token.rs @@ -25,7 +25,7 @@ use async_trait::async_trait; use bitcrypto::sha256; use common::executor::abortable_queue::AbortableQueue; use common::executor::{AbortableSystem, AbortedError}; -use common::log::{debug, warn}; +use common::log::warn; use common::Future01CompatExt; use cosmrs::{bank::MsgSend, tx::{Fee, Msg}, @@ -874,8 +874,4 @@ impl MmCoin for TendermintToken { fn on_disabled(&self) -> Result<(), AbortedError> { self.abortable_system.abort_all() } fn on_token_deactivated(&self, _ticker: &str) {} - - async fn handle_balance_stream(self, _ctx: MmArc) { - debug!("`fn handle_balance_stream` has no effect on Cosmos tokens.") - } } diff --git a/mm2src/coins/test_coin.rs b/mm2src/coins/test_coin.rs index 7cd8ed9d39..24408cf506 100644 --- a/mm2src/coins/test_coin.rs +++ b/mm2src/coins/test_coin.rs @@ -380,8 +380,6 @@ impl MmCoin for TestCoin { fn on_disabled(&self) -> Result<(), AbortedError> { Ok(()) } fn on_token_deactivated(&self, _ticker: &str) { () } - - async fn handle_balance_stream(self, _ctx: MmArc) { todo!() } } #[async_trait] diff --git a/mm2src/coins/utxo/bch.rs b/mm2src/coins/utxo/bch.rs index 7024f7066a..393f25cd54 100644 --- a/mm2src/coins/utxo/bch.rs +++ b/mm2src/coins/utxo/bch.rs @@ -1308,8 +1308,6 @@ impl MmCoin for BchCoin { tokens.remove(ticker); }; } - - async fn handle_balance_stream(self, _ctx: MmArc) { todo!() } } impl CoinWithDerivationMethod for BchCoin { diff --git a/mm2src/coins/utxo/qtum.rs b/mm2src/coins/utxo/qtum.rs index 9bd92db6b4..2f4c57ac6e 100644 --- a/mm2src/coins/utxo/qtum.rs +++ b/mm2src/coins/utxo/qtum.rs @@ -975,8 +975,6 @@ impl MmCoin for QtumCoin { fn on_disabled(&self) -> Result<(), AbortedError> { AbortableSystem::abort_all(&self.as_ref().abortable_system) } fn on_token_deactivated(&self, _ticker: &str) {} - - async fn handle_balance_stream(self, _ctx: MmArc) { todo!() } } #[async_trait] diff --git a/mm2src/coins/utxo/slp.rs b/mm2src/coins/utxo/slp.rs index 561f230e78..07379fcbbf 100644 --- a/mm2src/coins/utxo/slp.rs +++ b/mm2src/coins/utxo/slp.rs @@ -1876,8 +1876,6 @@ impl MmCoin for SlpToken { fn on_disabled(&self) -> Result<(), AbortedError> { self.conf.abortable_system.abort_all() } fn on_token_deactivated(&self, _ticker: &str) {} - - async fn handle_balance_stream(self, _ctx: MmArc) { todo!() } } #[async_trait] diff --git a/mm2src/coins/utxo/utxo_standard.rs b/mm2src/coins/utxo/utxo_standard.rs index f352ae381e..47582f8524 100644 --- a/mm2src/coins/utxo/utxo_standard.rs +++ b/mm2src/coins/utxo/utxo_standard.rs @@ -793,8 +793,6 @@ impl MmCoin for UtxoStandardCoin { fn on_disabled(&self) -> Result<(), AbortedError> { AbortableSystem::abort_all(&self.as_ref().abortable_system) } fn on_token_deactivated(&self, _ticker: &str) {} - - async fn handle_balance_stream(self, _ctx: MmArc) { todo!() } } #[async_trait] diff --git a/mm2src/coins/z_coin.rs b/mm2src/coins/z_coin.rs index 49d48b6e44..047a1cf1fd 100644 --- a/mm2src/coins/z_coin.rs +++ b/mm2src/coins/z_coin.rs @@ -1757,8 +1757,6 @@ impl MmCoin for ZCoin { fn on_disabled(&self) -> Result<(), AbortedError> { AbortableSystem::abort_all(&self.as_ref().abortable_system) } fn on_token_deactivated(&self, _ticker: &str) {} - - async fn handle_balance_stream(self, _ctx: MmArc) { todo!() } } #[async_trait] diff --git a/mm2src/coins_activation/Cargo.toml b/mm2src/coins_activation/Cargo.toml index e6ae6401a0..09fd4adf8e 100644 --- a/mm2src/coins_activation/Cargo.toml +++ b/mm2src/coins_activation/Cargo.toml @@ -21,6 +21,7 @@ futures = { version = "0.3", package = "futures", features = ["compat", "async-a hex = "0.4.2" mm2_core = { path = "../mm2_core" } mm2_err_handle = { path = "../mm2_err_handle" } +mm2_event_stream = { path = "../mm2_event_stream" } mm2_metrics = { path = "../mm2_metrics" } mm2_number = { path = "../mm2_number" } parking_lot = { version = "0.12.0", features = ["nightly"] } diff --git a/mm2src/coins_activation/src/bch_with_tokens_activation.rs b/mm2src/coins_activation/src/bch_with_tokens_activation.rs index a6d4c54df8..239cd3ef38 100644 --- a/mm2src/coins_activation/src/bch_with_tokens_activation.rs +++ b/mm2src/coins_activation/src/bch_with_tokens_activation.rs @@ -17,6 +17,7 @@ use common::{drop_mutability, true_f}; use crypto::CryptoCtxError; use mm2_core::mm_ctx::MmArc; use mm2_err_handle::prelude::*; +use mm2_event_stream::EventStreamConfiguration; use mm2_number::BigDecimal; use serde_derive::{Deserialize, Serialize}; use serde_json::Value as Json; @@ -330,4 +331,6 @@ impl PlatformWithTokensActivationOps for BchCoin { let settings = AbortSettings::info_on_abort(format!("bch_and_slp_history_loop stopped for {}", self.ticker())); self.spawner().spawn_with_settings(fut, settings); } + + fn handle_balance_streaming(&self, _config: &EventStreamConfiguration) {} } diff --git a/mm2src/coins_activation/src/eth_with_token_activation.rs b/mm2src/coins_activation/src/eth_with_token_activation.rs index 0f7c8d8455..71a29f0e9a 100644 --- a/mm2src/coins_activation/src/eth_with_token_activation.rs +++ b/mm2src/coins_activation/src/eth_with_token_activation.rs @@ -15,6 +15,7 @@ use common::Future01CompatExt; use common::{drop_mutability, true_f}; use mm2_core::mm_ctx::MmArc; use mm2_err_handle::prelude::*; +use mm2_event_stream::EventStreamConfiguration; #[cfg(target_arch = "wasm32")] use mm2_metamask::MetamaskRpcError; use mm2_number::BigDecimal; @@ -277,6 +278,8 @@ impl PlatformWithTokensActivationOps for EthCoin { _initial_balance: Option, ) { } + + fn handle_balance_streaming(&self, _config: &EventStreamConfiguration) {} } fn eth_priv_key_build_policy( diff --git a/mm2src/coins_activation/src/platform_coin_with_tokens.rs b/mm2src/coins_activation/src/platform_coin_with_tokens.rs index 94b9a16fc9..b90cb2fe2d 100644 --- a/mm2src/coins_activation/src/platform_coin_with_tokens.rs +++ b/mm2src/coins_activation/src/platform_coin_with_tokens.rs @@ -8,6 +8,7 @@ use crypto::CryptoCtxError; use derive_more::Display; use mm2_core::mm_ctx::MmArc; use mm2_err_handle::prelude::*; +use mm2_event_stream::EventStreamConfiguration; use mm2_number::BigDecimal; use ser_error_derive::SerializeErrorType; use serde_derive::{Deserialize, Serialize}; @@ -165,6 +166,8 @@ pub trait PlatformWithTokensActivationOps: Into { storage: impl TxHistoryStorage, initial_balance: Option, ); + + fn handle_balance_streaming(&self, config: &EventStreamConfiguration); } #[derive(Debug, Deserialize)] @@ -364,6 +367,10 @@ where ); } + if let Some(config) = &ctx.event_stream_configuration { + platform_coin.handle_balance_streaming(config); + } + let coins_ctx = CoinsContext::from_ctx(&ctx).unwrap(); coins_ctx .add_platform_with_tokens(platform_coin.into(), mm_tokens) diff --git a/mm2src/coins_activation/src/solana_with_tokens_activation.rs b/mm2src/coins_activation/src/solana_with_tokens_activation.rs index b6bd7b123d..405a51f17d 100644 --- a/mm2src/coins_activation/src/solana_with_tokens_activation.rs +++ b/mm2src/coins_activation/src/solana_with_tokens_activation.rs @@ -18,6 +18,7 @@ use crypto::CryptoCtxError; use futures::future::try_join_all; use mm2_core::mm_ctx::MmArc; use mm2_err_handle::prelude::*; +use mm2_event_stream::EventStreamConfiguration; use mm2_number::BigDecimal; use serde_derive::{Deserialize, Serialize}; use serde_json::Value as Json; @@ -288,4 +289,6 @@ impl PlatformWithTokensActivationOps for SolanaCoin { _initial_balance: Option, ) { } + + fn handle_balance_streaming(&self, _config: &EventStreamConfiguration) {} } diff --git a/mm2src/coins_activation/src/tendermint_with_assets_activation.rs b/mm2src/coins_activation/src/tendermint_with_assets_activation.rs index 006f7993d3..ede3298e10 100644 --- a/mm2src/coins_activation/src/tendermint_with_assets_activation.rs +++ b/mm2src/coins_activation/src/tendermint_with_assets_activation.rs @@ -15,6 +15,8 @@ use common::{true_f, Future01CompatExt}; use crypto::StandardHDCoinAddress; use mm2_core::mm_ctx::MmArc; use mm2_err_handle::prelude::*; +use mm2_event_stream::behaviour::EventBehaviour; +use mm2_event_stream::EventStreamConfiguration; use mm2_number::BigDecimal; use serde::{Deserialize, Serialize}; use serde_json::Value as Json; @@ -275,4 +277,8 @@ impl PlatformWithTokensActivationOps for TendermintCoin { let settings = AbortSettings::info_on_abort(format!("tendermint_history_loop stopped for {}", self.ticker())); self.spawner().spawn_with_settings(fut, settings); } + + fn handle_balance_streaming(&self, config: &EventStreamConfiguration) { + EventBehaviour::spawn_if_active(self.clone(), config); + } } diff --git a/mm2src/mm2_main/src/lp_native_dex.rs b/mm2src/mm2_main/src/lp_native_dex.rs index de6c00f7a6..b678e2f365 100644 --- a/mm2src/mm2_main/src/lp_native_dex.rs +++ b/mm2src/mm2_main/src/lp_native_dex.rs @@ -50,7 +50,6 @@ use crate::mm2::lp_ordermatch::{broadcast_maker_orders_keep_alive_loop, clean_me use crate::mm2::lp_swap::{running_swaps_num, swap_kick_starts}; use crate::mm2::rpc::spawn_rpc; -use coins::coin_balance_event::CoinBalanceEvent; use mm2_event_stream::behaviour::EventBehaviour; use mm2_net::network_event::NetworkEvent; @@ -392,10 +391,8 @@ fn migration_1(_ctx: &MmArc) {} fn init_event_streaming(ctx: &MmArc) { // This condition only executed if events were enabled in mm2 configuration. - if let Some(config) = &ctx.event_stream_configuration { NetworkEvent::new(ctx.clone()).spawn_if_active(config); - CoinBalanceEvent::new(ctx.clone()).spawn_if_active(config); } } From 5464064251e0fc1334e628dc42562a4a4cce8977 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Wed, 4 Oct 2023 11:57:13 +0300 Subject: [PATCH 39/48] ref `active_ticker_and_decimals_from_denom` to be O(1) Signed-off-by: onur-ozkan --- .../tendermint/tendermint_balance_events.rs | 2 +- mm2src/coins/tendermint/tendermint_coin.rs | 18 ++++++++---------- .../src/tendermint_with_assets_activation.rs | 9 ++++++++- 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/mm2src/coins/tendermint/tendermint_balance_events.rs b/mm2src/coins/tendermint/tendermint_balance_events.rs index df6e3489ab..bd34dd26da 100644 --- a/mm2src/coins/tendermint/tendermint_balance_events.rs +++ b/mm2src/coins/tendermint/tendermint_balance_events.rs @@ -72,7 +72,7 @@ impl EventBehaviour for TendermintCoin { Ok(tokio_tungstenite_wasm::Message::Text(data)) => data.clone(), Ok(tokio_tungstenite_wasm::Message::Close(_)) => break, Err(err) => { - log::error!("{err}"); + log::error!("Server returned an unknown message type - {err}"); break; }, _ => continue, diff --git a/mm2src/coins/tendermint/tendermint_coin.rs b/mm2src/coins/tendermint/tendermint_coin.rs index 9885fd482c..5d7cb9a69a 100644 --- a/mm2src/coins/tendermint/tendermint_coin.rs +++ b/mm2src/coins/tendermint/tendermint_coin.rs @@ -142,7 +142,7 @@ pub struct TendermintProtocolInfo { #[derive(Clone)] pub struct ActivatedTokenInfo { pub(crate) decimals: u8, - pub(crate) denom: Denom, + pub ticker: String, } pub struct TendermintConf { @@ -442,14 +442,14 @@ impl TendermintCommons for TendermintCoin { let ibc_assets_info = self.tokens_info.lock().clone(); let mut requests = Vec::new(); - for (ticker, info) in ibc_assets_info { + for (denom, info) in ibc_assets_info { let fut = async move { let balance_denom = self - .account_balance_for_denom(&self.account_id, info.denom.to_string()) + .account_balance_for_denom(&self.account_id, denom) .await .map_err(|e| e.into_inner())?; let balance_decimal = big_decimal_from_sat_unsigned(balance_denom, info.decimals); - Ok::<_, TendermintCoinRpcError>((ticker.clone(), balance_decimal)) + Ok::<_, TendermintCoinRpcError>((info.ticker, balance_decimal)) }; requests.push(fut); } @@ -1180,7 +1180,7 @@ impl TendermintCoin { pub fn add_activated_token_info(&self, ticker: String, decimals: u8, denom: Denom) { self.tokens_info .lock() - .insert(ticker, ActivatedTokenInfo { decimals, denom }); + .insert(denom.to_string(), ActivatedTokenInfo { decimals, ticker }); } fn estimate_blocks_from_duration(&self, duration: u64) -> i64 { @@ -1825,16 +1825,14 @@ impl TendermintCoin { } pub(crate) fn active_ticker_and_decimals_from_denom(&self, denom: &str) -> Option<(String, u8)> { - if self.denom.to_string() == denom { + if self.denom.as_ref() == denom { return Some((self.ticker.clone(), self.decimals)); } let tokens = self.tokens_info.lock(); - for (ticker, token) in &*tokens { - if token.denom.to_string() == denom { - return Some((ticker.to_owned(), token.decimals)); - } + if let Some(token_info) = tokens.get(denom) { + return Some((token_info.ticker.to_owned(), token_info.decimals)); } None diff --git a/mm2src/coins_activation/src/tendermint_with_assets_activation.rs b/mm2src/coins_activation/src/tendermint_with_assets_activation.rs index ede3298e10..8fed2b66cd 100644 --- a/mm2src/coins_activation/src/tendermint_with_assets_activation.rs +++ b/mm2src/coins_activation/src/tendermint_with_assets_activation.rs @@ -233,7 +233,14 @@ impl PlatformWithTokensActivationOps for TendermintCoin { current_block, balance: None, tokens_balances: None, - tokens_tickers: Some(self.tokens_info.lock().clone().into_keys().collect()), + tokens_tickers: Some( + self.tokens_info + .lock() + .clone() + .into_values() + .map(|t| t.ticker) + .collect(), + ), }); } From 3c50310ec5b0b795eeaea8e5480965e015aba909 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Wed, 4 Oct 2023 12:31:22 +0300 Subject: [PATCH 40/48] replace plain json with `jsonrpc_core::MethodCall` Signed-off-by: onur-ozkan --- .../tendermint/tendermint_balance_events.rs | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/mm2src/coins/tendermint/tendermint_balance_events.rs b/mm2src/coins/tendermint/tendermint_balance_events.rs index bd34dd26da..5af80ea913 100644 --- a/mm2src/coins/tendermint/tendermint_balance_events.rs +++ b/mm2src/coins/tendermint/tendermint_balance_events.rs @@ -2,6 +2,8 @@ use async_trait::async_trait; use common::{executor::{AbortSettings, SpawnAbortable}, http_uri_to_ws_address, log}; use futures_util::{SinkExt, StreamExt}; +use jsonrpc_core::MethodCall; +use jsonrpc_core::{Id as RpcId, Params as RpcParams, Value as RpcValue, Version as RpcVersion}; use mm2_event_stream::{behaviour::EventBehaviour, Event, EventStreamConfiguration}; use mm2_number::BigDecimal; use std::collections::HashMap; @@ -15,16 +17,17 @@ impl EventBehaviour for TendermintCoin { async fn handle(self, _interval: f64) { fn generate_subscription_query(query_filter: String) -> String { - let q = json!({ - "jsonrpc": "2.0", - "method": "subscribe", - "id": 0, - "params": { - "query": query_filter - } - }); + let mut params = serde_json::Map::with_capacity(1); + params.insert("query".to_owned(), RpcValue::String(query_filter)); + + let q = MethodCall { + id: RpcId::Num(0), + jsonrpc: Some(RpcVersion::V2), + method: "subscribe".to_owned(), + params: RpcParams::Map(params), + }; - q.to_string() + serde_json::to_string(&q).expect("This should never happen") } let account_id = self.account_id.to_string(); From 35e58e423a59238b875dc875d3039f5838cccffb Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Wed, 4 Oct 2023 12:47:11 +0300 Subject: [PATCH 41/48] explain how to examine incoming data from tendermint socket Signed-off-by: onur-ozkan --- mm2src/coins/tendermint/tendermint_balance_events.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mm2src/coins/tendermint/tendermint_balance_events.rs b/mm2src/coins/tendermint/tendermint_balance_events.rs index 5af80ea913..76d6092694 100644 --- a/mm2src/coins/tendermint/tendermint_balance_events.rs +++ b/mm2src/coins/tendermint/tendermint_balance_events.rs @@ -81,6 +81,9 @@ impl EventBehaviour for TendermintCoin { _ => continue, }; + // Here, we receive raw data from the socket. + // To examine this data, you can use tools like wscat/websocat or visit + // https://pastebin.pl/view/499cbf2c for sample data. if let Ok(json_val) = serde_json::from_str::(&msg) { let transfers: Vec = serde_json::from_value(json_val["result"]["events"]["transfer.amount"].clone()) From 0e41ae7f7599b2070bf188187a432d7dbf70c3c2 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Wed, 4 Oct 2023 13:00:19 +0300 Subject: [PATCH 42/48] update helper logs for Tendermint COIN_BALANCE event Signed-off-by: onur-ozkan --- mm2src/coins/tendermint/tendermint_balance_events.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mm2src/coins/tendermint/tendermint_balance_events.rs b/mm2src/coins/tendermint/tendermint_balance_events.rs index 76d6092694..e88ea2caca 100644 --- a/mm2src/coins/tendermint/tendermint_balance_events.rs +++ b/mm2src/coins/tendermint/tendermint_balance_events.rs @@ -146,14 +146,15 @@ impl EventBehaviour for TendermintCoin { fn spawn_if_active(self, config: &EventStreamConfiguration) { if let Some(event) = config.get_event(Self::EVENT_NAME) { log::info!( - "{} event is activated. `stream_interval_seconds`({}) has no effect for this event.", + "{} event is activated for {}. `stream_interval_seconds`({}) has no effect on this.", Self::EVENT_NAME, + self.ticker(), event.stream_interval_seconds ); let fut = self.clone().handle(event.stream_interval_seconds); let settings = - AbortSettings::info_on_abort(format!("Balance streaming stopped for {}", self.ticker().to_owned())); + AbortSettings::info_on_abort(format!("{} event is stopped for {}.", Self::EVENT_NAME, self.ticker())); self.spawner().spawn_with_settings(fut, settings); } } From 7e190037f3e6e2361ed5d7dbeb53424dc802323c Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Fri, 6 Oct 2023 00:24:16 +0300 Subject: [PATCH 43/48] fix minor notes Signed-off-by: onur-ozkan --- mm2src/coins/tendermint/mod.rs | 2 +- mm2src/coins/tendermint/tendermint_balance_events.rs | 7 ++----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/mm2src/coins/tendermint/mod.rs b/mm2src/coins/tendermint/mod.rs index 400d95071c..60a4c61ec1 100644 --- a/mm2src/coins/tendermint/mod.rs +++ b/mm2src/coins/tendermint/mod.rs @@ -5,7 +5,7 @@ mod ibc; mod iris; mod rpc; -pub mod tendermint_balance_events; +mod tendermint_balance_events; mod tendermint_coin; mod tendermint_token; pub mod tendermint_tx_history_v2; diff --git a/mm2src/coins/tendermint/tendermint_balance_events.rs b/mm2src/coins/tendermint/tendermint_balance_events.rs index e88ea2caca..bb10fae917 100644 --- a/mm2src/coins/tendermint/tendermint_balance_events.rs +++ b/mm2src/coins/tendermint/tendermint_balance_events.rs @@ -6,7 +6,7 @@ use jsonrpc_core::MethodCall; use jsonrpc_core::{Id as RpcId, Params as RpcParams, Value as RpcValue, Version as RpcVersion}; use mm2_event_stream::{behaviour::EventBehaviour, Event, EventStreamConfiguration}; use mm2_number::BigDecimal; -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; use super::TendermintCoin; use crate::{tendermint::TendermintCommons, utxo::utxo_common::big_decimal_from_sat_unsigned, MarketCoinOps, MmCoin}; @@ -89,7 +89,7 @@ impl EventBehaviour for TendermintCoin { serde_json::from_value(json_val["result"]["events"]["transfer.amount"].clone()) .unwrap_or_default(); - let mut denoms: Vec = transfers + let denoms: HashSet = transfers .iter() .map(|t| { let amount: String = t.chars().take_while(|c| c.is_numeric()).collect(); @@ -98,9 +98,6 @@ impl EventBehaviour for TendermintCoin { }) .collect(); - denoms.dedup(); - drop_mutability!(denoms); - for denom in denoms { if let Some((ticker, decimals)) = self.active_ticker_and_decimals_from_denom(&denom) { let balance_denom = match self.account_balance_for_denom(&self.account_id, denom).await { From 799e4e8316ab8b2fd2d83114fc7e116d08d7460d Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Fri, 6 Oct 2023 11:19:33 +0300 Subject: [PATCH 44/48] upgrade from weak pointer for Tendermint to Mm context Signed-off-by: onur-ozkan --- mm2src/coins/tendermint/tendermint_balance_events.rs | 6 ++++-- mm2src/coins/tendermint/tendermint_coin.rs | 6 +++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/mm2src/coins/tendermint/tendermint_balance_events.rs b/mm2src/coins/tendermint/tendermint_balance_events.rs index bb10fae917..6c4cd3481c 100644 --- a/mm2src/coins/tendermint/tendermint_balance_events.rs +++ b/mm2src/coins/tendermint/tendermint_balance_events.rs @@ -4,6 +4,7 @@ use common::{executor::{AbortSettings, SpawnAbortable}, use futures_util::{SinkExt, StreamExt}; use jsonrpc_core::MethodCall; use jsonrpc_core::{Id as RpcId, Params as RpcParams, Value as RpcValue, Version as RpcVersion}; +use mm2_core::mm_ctx::MmArc; use mm2_event_stream::{behaviour::EventBehaviour, Event, EventStreamConfiguration}; use mm2_number::BigDecimal; use std::collections::{HashMap, HashSet}; @@ -30,6 +31,8 @@ impl EventBehaviour for TendermintCoin { serde_json::to_string(&q).expect("This should never happen") } + let ctx = MmArc::from_weak(&self.ctx).expect("MM context must have been initialized already."); + let account_id = self.account_id.to_string(); let mut current_balances: HashMap = HashMap::new(); @@ -128,8 +131,7 @@ impl EventBehaviour for TendermintCoin { "balance": { "spendable": balance_decimal, "unspendable": BigDecimal::default() } }); - self.ctx - .stream_channel_controller + ctx.stream_channel_controller .broadcast(Event::new(Self::EVENT_NAME.to_string(), payload.to_string())) .await; } diff --git a/mm2src/coins/tendermint/tendermint_coin.rs b/mm2src/coins/tendermint/tendermint_coin.rs index 5d7cb9a69a..4cb6c4ea71 100644 --- a/mm2src/coins/tendermint/tendermint_coin.rs +++ b/mm2src/coins/tendermint/tendermint_coin.rs @@ -60,7 +60,7 @@ use futures01::Future; use hex::FromHexError; use itertools::Itertools; use keys::KeyPair; -use mm2_core::mm_ctx::MmArc; +use mm2_core::mm_ctx::{MmArc, MmWeak}; use mm2_err_handle::prelude::*; use mm2_git::{FileMetadata, GitController, GithubClient, RepositoryOperations, GITHUB_API_URI}; use mm2_number::MmNumber; @@ -237,7 +237,7 @@ pub struct TendermintCoinImpl { pub(crate) history_sync_state: Mutex, client: TendermintRpcClient, chain_registry_name: Option, - pub(crate) ctx: MmArc, + pub(crate) ctx: MmWeak, } #[derive(Clone)] @@ -545,7 +545,7 @@ impl TendermintCoin { history_sync_state: Mutex::new(history_sync_state), client: TendermintRpcClient(AsyncMutex::new(client_impl)), chain_registry_name: protocol_info.chain_registry_name, - ctx: ctx.clone(), + ctx: ctx.weak(), }))) } From dbb2b22cc28dafda36052c727c1837e2b0a76f57 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Mon, 9 Oct 2023 13:45:23 +0300 Subject: [PATCH 45/48] handle event initializations Signed-off-by: onur-ozkan --- Cargo.lock | 1 + .../tendermint/tendermint_balance_events.rs | 28 +++++++++++++++---- mm2src/coins/tendermint/tendermint_coin.rs | 1 + .../src/bch_with_tokens_activation.rs | 7 ++++- .../src/eth_with_token_activation.rs | 7 ++++- .../src/platform_coin_with_tokens.rs | 7 +++-- .../src/solana_with_tokens_activation.rs | 7 ++++- .../src/tendermint_with_assets_activation.rs | 15 ++++++++-- mm2src/mm2_event_stream/Cargo.toml | 1 + mm2src/mm2_event_stream/src/behaviour.rs | 13 +++++++-- mm2src/mm2_main/src/lp_native_dex.rs | 17 +++++++---- mm2src/mm2_net/src/network_event.rs | 18 ++++++++---- 12 files changed, 96 insertions(+), 26 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 94b003f869..adcb1724af 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4337,6 +4337,7 @@ dependencies = [ "async-trait", "cfg-if 1.0.0", "common", + "futures 0.3.28", "parking_lot 0.12.0", "serde", "tokio", diff --git a/mm2src/coins/tendermint/tendermint_balance_events.rs b/mm2src/coins/tendermint/tendermint_balance_events.rs index 6c4cd3481c..7a0dc6b5d1 100644 --- a/mm2src/coins/tendermint/tendermint_balance_events.rs +++ b/mm2src/coins/tendermint/tendermint_balance_events.rs @@ -1,11 +1,13 @@ use async_trait::async_trait; use common::{executor::{AbortSettings, SpawnAbortable}, http_uri_to_ws_address, log}; +use futures::channel::oneshot::{self, Receiver, Sender}; use futures_util::{SinkExt, StreamExt}; use jsonrpc_core::MethodCall; use jsonrpc_core::{Id as RpcId, Params as RpcParams, Value as RpcValue, Version as RpcVersion}; use mm2_core::mm_ctx::MmArc; -use mm2_event_stream::{behaviour::EventBehaviour, Event, EventStreamConfiguration}; +use mm2_event_stream::{behaviour::{EventBehaviour, EventInitStatus}, + Event, EventStreamConfiguration}; use mm2_number::BigDecimal; use std::collections::{HashMap, HashSet}; @@ -16,7 +18,7 @@ use crate::{tendermint::TendermintCommons, utxo::utxo_common::big_decimal_from_s impl EventBehaviour for TendermintCoin { const EVENT_NAME: &'static str = "COIN_BALANCE"; - async fn handle(self, _interval: f64) { + async fn handle(self, _interval: f64, tx: oneshot::Sender) { fn generate_subscription_query(query_filter: String) -> String { let mut params = serde_json::Map::with_capacity(1); params.insert("query".to_owned(), RpcValue::String(query_filter)); @@ -31,7 +33,15 @@ impl EventBehaviour for TendermintCoin { serde_json::to_string(&q).expect("This should never happen") } - let ctx = MmArc::from_weak(&self.ctx).expect("MM context must have been initialized already."); + let ctx = match MmArc::from_weak(&self.ctx) { + Some(ctx) => ctx, + None => { + let msg = "MM context must have been initialized already."; + tx.send(EventInitStatus::Failed(msg.to_owned())) + .expect("Receiver is dropped, which should never happen."); + panic!("{}", msg); + }, + }; let account_id = self.account_id.to_string(); let mut current_balances: HashMap = HashMap::new(); @@ -42,6 +52,9 @@ impl EventBehaviour for TendermintCoin { let spender_q = generate_subscription_query(format!("coin_spent.spender = '{}'", account_id)); let spender_q = tokio_tungstenite_wasm::Message::Text(spender_q); + tx.send(EventInitStatus::Success) + .expect("Receiver is dropped, which should never happen."); + loop { let node_uri = match self.rpc_client().await { Ok(client) => client.uri(), @@ -142,7 +155,7 @@ impl EventBehaviour for TendermintCoin { } } - fn spawn_if_active(self, config: &EventStreamConfiguration) { + async fn spawn_if_active(self, config: &EventStreamConfiguration) -> EventInitStatus { if let Some(event) = config.get_event(Self::EVENT_NAME) { log::info!( "{} event is activated for {}. `stream_interval_seconds`({}) has no effect on this.", @@ -151,10 +164,15 @@ impl EventBehaviour for TendermintCoin { event.stream_interval_seconds ); - let fut = self.clone().handle(event.stream_interval_seconds); + let (tx, rx): (Sender, Receiver) = oneshot::channel(); + let fut = self.clone().handle(event.stream_interval_seconds, tx); let settings = AbortSettings::info_on_abort(format!("{} event is stopped for {}.", Self::EVENT_NAME, self.ticker())); self.spawner().spawn_with_settings(fut, settings); + + rx.await.expect("Event initialization status must be recieved.") + } else { + EventInitStatus::Inactive } } } diff --git a/mm2src/coins/tendermint/tendermint_coin.rs b/mm2src/coins/tendermint/tendermint_coin.rs index 4cb6c4ea71..b65caf13e7 100644 --- a/mm2src/coins/tendermint/tendermint_coin.rs +++ b/mm2src/coins/tendermint/tendermint_coin.rs @@ -280,6 +280,7 @@ pub enum TendermintInitErrorKind { AvgBlockTimeMissing, #[display(fmt = "avg_blocktime must be in-between '0' and '255'.")] AvgBlockTimeInvalid, + BalanceStreamInitError(String), } #[derive(Display, Debug)] diff --git a/mm2src/coins_activation/src/bch_with_tokens_activation.rs b/mm2src/coins_activation/src/bch_with_tokens_activation.rs index 239cd3ef38..b99b49235a 100644 --- a/mm2src/coins_activation/src/bch_with_tokens_activation.rs +++ b/mm2src/coins_activation/src/bch_with_tokens_activation.rs @@ -332,5 +332,10 @@ impl PlatformWithTokensActivationOps for BchCoin { self.spawner().spawn_with_settings(fut, settings); } - fn handle_balance_streaming(&self, _config: &EventStreamConfiguration) {} + async fn handle_balance_streaming( + &self, + _config: &EventStreamConfiguration, + ) -> Result<(), MmError> { + Ok(()) + } } diff --git a/mm2src/coins_activation/src/eth_with_token_activation.rs b/mm2src/coins_activation/src/eth_with_token_activation.rs index 71a29f0e9a..3a93f3ad07 100644 --- a/mm2src/coins_activation/src/eth_with_token_activation.rs +++ b/mm2src/coins_activation/src/eth_with_token_activation.rs @@ -279,7 +279,12 @@ impl PlatformWithTokensActivationOps for EthCoin { ) { } - fn handle_balance_streaming(&self, _config: &EventStreamConfiguration) {} + async fn handle_balance_streaming( + &self, + _config: &EventStreamConfiguration, + ) -> Result<(), MmError> { + Ok(()) + } } fn eth_priv_key_build_policy( diff --git a/mm2src/coins_activation/src/platform_coin_with_tokens.rs b/mm2src/coins_activation/src/platform_coin_with_tokens.rs index b90cb2fe2d..bd12c99a22 100644 --- a/mm2src/coins_activation/src/platform_coin_with_tokens.rs +++ b/mm2src/coins_activation/src/platform_coin_with_tokens.rs @@ -167,7 +167,10 @@ pub trait PlatformWithTokensActivationOps: Into { initial_balance: Option, ); - fn handle_balance_streaming(&self, config: &EventStreamConfiguration); + async fn handle_balance_streaming( + &self, + config: &EventStreamConfiguration, + ) -> Result<(), MmError>; } #[derive(Debug, Deserialize)] @@ -368,7 +371,7 @@ where } if let Some(config) = &ctx.event_stream_configuration { - platform_coin.handle_balance_streaming(config); + platform_coin.handle_balance_streaming(config).await?; } let coins_ctx = CoinsContext::from_ctx(&ctx).unwrap(); diff --git a/mm2src/coins_activation/src/solana_with_tokens_activation.rs b/mm2src/coins_activation/src/solana_with_tokens_activation.rs index 405a51f17d..aa049d0867 100644 --- a/mm2src/coins_activation/src/solana_with_tokens_activation.rs +++ b/mm2src/coins_activation/src/solana_with_tokens_activation.rs @@ -290,5 +290,10 @@ impl PlatformWithTokensActivationOps for SolanaCoin { ) { } - fn handle_balance_streaming(&self, _config: &EventStreamConfiguration) {} + async fn handle_balance_streaming( + &self, + _config: &EventStreamConfiguration, + ) -> Result<(), MmError> { + Ok(()) + } } diff --git a/mm2src/coins_activation/src/tendermint_with_assets_activation.rs b/mm2src/coins_activation/src/tendermint_with_assets_activation.rs index 8fed2b66cd..e2e8fda8f0 100644 --- a/mm2src/coins_activation/src/tendermint_with_assets_activation.rs +++ b/mm2src/coins_activation/src/tendermint_with_assets_activation.rs @@ -15,7 +15,7 @@ use common::{true_f, Future01CompatExt}; use crypto::StandardHDCoinAddress; use mm2_core::mm_ctx::MmArc; use mm2_err_handle::prelude::*; -use mm2_event_stream::behaviour::EventBehaviour; +use mm2_event_stream::behaviour::{EventBehaviour, EventInitStatus}; use mm2_event_stream::EventStreamConfiguration; use mm2_number::BigDecimal; use serde::{Deserialize, Serialize}; @@ -285,7 +285,16 @@ impl PlatformWithTokensActivationOps for TendermintCoin { self.spawner().spawn_with_settings(fut, settings); } - fn handle_balance_streaming(&self, config: &EventStreamConfiguration) { - EventBehaviour::spawn_if_active(self.clone(), config); + async fn handle_balance_streaming( + &self, + config: &EventStreamConfiguration, + ) -> Result<(), MmError> { + if let EventInitStatus::Failed(err) = EventBehaviour::spawn_if_active(self.clone(), config).await { + return MmError::err(TendermintInitError { + ticker: self.ticker().to_owned(), + kind: TendermintInitErrorKind::BalanceStreamInitError(err), + }); + } + Ok(()) } } diff --git a/mm2src/mm2_event_stream/Cargo.toml b/mm2src/mm2_event_stream/Cargo.toml index 2865e0a01f..adf20e7ee2 100644 --- a/mm2src/mm2_event_stream/Cargo.toml +++ b/mm2src/mm2_event_stream/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" async-trait = "0.1" cfg-if = "1.0" common = { path = "../common" } +futures = { version = "0.3", default-features = false } parking_lot = "0.12" serde = { version = "1", features = ["derive", "rc"] } tokio = { version = "1", features = ["sync"] } diff --git a/mm2src/mm2_event_stream/src/behaviour.rs b/mm2src/mm2_event_stream/src/behaviour.rs index bb905af3fc..f76cad44e7 100644 --- a/mm2src/mm2_event_stream/src/behaviour.rs +++ b/mm2src/mm2_event_stream/src/behaviour.rs @@ -1,5 +1,14 @@ use crate::EventStreamConfiguration; use async_trait::async_trait; +use futures::channel::oneshot; + +#[derive(Clone, Debug)] +pub enum EventInitStatus { + NotInitialized, + Inactive, + Success, + Failed(String), +} #[async_trait] pub trait EventBehaviour { @@ -7,9 +16,9 @@ pub trait EventBehaviour { const EVENT_NAME: &'static str; /// Event handler that is responsible for broadcasting event data to the streaming channels. - async fn handle(self, interval: f64); + async fn handle(self, interval: f64, tx: oneshot::Sender); /// Spawns the `Self::handle` in a separate thread if the event is active according to the mm2 configuration. /// Does nothing if the event is not active. - fn spawn_if_active(self, config: &EventStreamConfiguration); + async fn spawn_if_active(self, config: &EventStreamConfiguration) -> EventInitStatus; } diff --git a/mm2src/mm2_main/src/lp_native_dex.rs b/mm2src/mm2_main/src/lp_native_dex.rs index b678e2f365..cfe63525da 100644 --- a/mm2src/mm2_main/src/lp_native_dex.rs +++ b/mm2src/mm2_main/src/lp_native_dex.rs @@ -28,9 +28,11 @@ use enum_from::EnumFromTrait; use mm2_core::mm_ctx::{MmArc, MmCtx}; use mm2_err_handle::common_errors::InternalError; use mm2_err_handle::prelude::*; +use mm2_event_stream::behaviour::{EventBehaviour, EventInitStatus}; use mm2_libp2p::{spawn_gossipsub, AdexBehaviourError, NodeType, RelayAddress, RelayAddressError, SwarmRuntime, WssCerts}; use mm2_metrics::mm_gauge; +use mm2_net::network_event::NetworkEvent; use mm2_net::p2p::P2PContext; use rpc_task::RpcTaskError; use serde_json::{self as json}; @@ -50,9 +52,6 @@ use crate::mm2::lp_ordermatch::{broadcast_maker_orders_keep_alive_loop, clean_me use crate::mm2::lp_swap::{running_swaps_num, swap_kick_starts}; use crate::mm2::rpc::spawn_rpc; -use mm2_event_stream::behaviour::EventBehaviour; -use mm2_net::network_event::NetworkEvent; - cfg_native! { use db_common::sqlite::rusqlite::Error as SqlError; use mm2_io::fs::{ensure_dir_is_writable, ensure_file_is_writable}; @@ -166,6 +165,8 @@ pub enum MmInitError { EmptyPassphrase, #[display(fmt = "Invalid passphrase: {}", _0)] InvalidPassphrase(String), + #[display(fmt = "NETWORK event initialization failed: {}", _0)] + NetworkEventInitFailed(String), #[from_trait(WithHwRpcError::hw_rpc_error)] #[display(fmt = "{}", _0)] HwError(HwRpcError), @@ -389,11 +390,15 @@ fn migrate_db(ctx: &MmArc) -> MmInitResult<()> { #[cfg(not(target_arch = "wasm32"))] fn migration_1(_ctx: &MmArc) {} -fn init_event_streaming(ctx: &MmArc) { +async fn init_event_streaming(ctx: &MmArc) -> MmInitResult<()> { // This condition only executed if events were enabled in mm2 configuration. if let Some(config) = &ctx.event_stream_configuration { - NetworkEvent::new(ctx.clone()).spawn_if_active(config); + if let EventInitStatus::Failed(err) = NetworkEvent::new(ctx.clone()).spawn_if_active(config).await { + return MmError::err(MmInitError::NetworkEventInitFailed(err)); + } } + + Ok(()) } #[cfg(target_arch = "wasm32")] @@ -433,7 +438,7 @@ pub async fn lp_init_continue(ctx: MmArc) -> MmInitResult<()> { // an order and start new swap that might get started 2 times because of kick-start kick_start(ctx.clone()).await?; - init_event_streaming(&ctx); + init_event_streaming(&ctx).await?; ctx.spawner().spawn(lp_ordermatch_loop(ctx.clone())); diff --git a/mm2src/mm2_net/src/network_event.rs b/mm2src/mm2_net/src/network_event.rs index 09484e1eb7..b6ec916662 100644 --- a/mm2src/mm2_net/src/network_event.rs +++ b/mm2src/mm2_net/src/network_event.rs @@ -2,9 +2,10 @@ use crate::p2p::P2PContext; use async_trait::async_trait; use common::{executor::{SpawnFuture, Timer}, log::info}; +use futures::channel::oneshot::{self, Receiver, Sender}; use mm2_core::mm_ctx::MmArc; pub use mm2_event_stream::behaviour::EventBehaviour; -use mm2_event_stream::{Event, EventStreamConfiguration}; +use mm2_event_stream::{behaviour::EventInitStatus, Event, EventStreamConfiguration}; use mm2_libp2p::behaviours::atomicdex; use serde_json::json; @@ -20,11 +21,12 @@ impl NetworkEvent { impl EventBehaviour for NetworkEvent { const EVENT_NAME: &'static str = "NETWORK"; - async fn handle(self, interval: f64) { + async fn handle(self, interval: f64, tx: oneshot::Sender) { let p2p_ctx = P2PContext::fetch_from_mm_arc(&self.ctx); - let mut previously_sent = json!({}); + tx.send(EventInitStatus::Success).unwrap(); + loop { let p2p_cmd_tx = p2p_ctx.cmd_tx.lock().clone(); @@ -55,13 +57,19 @@ impl EventBehaviour for NetworkEvent { } } - fn spawn_if_active(self, config: &EventStreamConfiguration) { + async fn spawn_if_active(self, config: &EventStreamConfiguration) -> EventInitStatus { if let Some(event) = config.get_event(Self::EVENT_NAME) { info!( "NETWORK event is activated with {} seconds interval.", event.stream_interval_seconds ); - self.ctx.spawner().spawn(self.handle(event.stream_interval_seconds)); + + let (tx, rx): (Sender, Receiver) = oneshot::channel(); + self.ctx.spawner().spawn(self.handle(event.stream_interval_seconds, tx)); + + rx.await.expect("Event initialization status must be recieved.") + } else { + EventInitStatus::Inactive } } } From d7bd0d701d046e5061b176514ad0d27aaf3a30d9 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Mon, 9 Oct 2023 13:59:09 +0300 Subject: [PATCH 46/48] remove `NotInitialized` variant in `EventInitStatus` Signed-off-by: onur-ozkan --- mm2src/mm2_event_stream/src/behaviour.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/mm2src/mm2_event_stream/src/behaviour.rs b/mm2src/mm2_event_stream/src/behaviour.rs index f76cad44e7..8539754061 100644 --- a/mm2src/mm2_event_stream/src/behaviour.rs +++ b/mm2src/mm2_event_stream/src/behaviour.rs @@ -4,7 +4,6 @@ use futures::channel::oneshot; #[derive(Clone, Debug)] pub enum EventInitStatus { - NotInitialized, Inactive, Success, Failed(String), From 7ccf765bedd2b090a106479e1c227ae3bce5d814 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Mon, 9 Oct 2023 17:27:09 +0300 Subject: [PATCH 47/48] return EventInitStatus::Failed if tx isn't present Signed-off-by: onur-ozkan --- mm2src/coins/tendermint/tendermint_balance_events.rs | 4 +++- mm2src/mm2_net/src/network_event.rs | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/mm2src/coins/tendermint/tendermint_balance_events.rs b/mm2src/coins/tendermint/tendermint_balance_events.rs index 7a0dc6b5d1..122262eb51 100644 --- a/mm2src/coins/tendermint/tendermint_balance_events.rs +++ b/mm2src/coins/tendermint/tendermint_balance_events.rs @@ -170,7 +170,9 @@ impl EventBehaviour for TendermintCoin { AbortSettings::info_on_abort(format!("{} event is stopped for {}.", Self::EVENT_NAME, self.ticker())); self.spawner().spawn_with_settings(fut, settings); - rx.await.expect("Event initialization status must be recieved.") + rx.await.unwrap_or_else(|e| { + EventInitStatus::Failed(format!("Event initialization status must be received: {}", e)) + }) } else { EventInitStatus::Inactive } diff --git a/mm2src/mm2_net/src/network_event.rs b/mm2src/mm2_net/src/network_event.rs index b6ec916662..beee72e36f 100644 --- a/mm2src/mm2_net/src/network_event.rs +++ b/mm2src/mm2_net/src/network_event.rs @@ -67,7 +67,9 @@ impl EventBehaviour for NetworkEvent { let (tx, rx): (Sender, Receiver) = oneshot::channel(); self.ctx.spawner().spawn(self.handle(event.stream_interval_seconds, tx)); - rx.await.expect("Event initialization status must be recieved.") + rx.await.unwrap_or_else(|e| { + EventInitStatus::Failed(format!("Event initialization status must be received: {}", e)) + }) } else { EventInitStatus::Inactive } From b3d774c428c8dc9f8d5c1d7a2d984a9821401b39 Mon Sep 17 00:00:00 2001 From: shamardy Date: Fri, 27 Oct 2023 16:06:57 +0200 Subject: [PATCH 48/48] update adex-cli cargo.lock --- mm2src/adex_cli/Cargo.lock | 1 + 1 file changed, 1 insertion(+) diff --git a/mm2src/adex_cli/Cargo.lock b/mm2src/adex_cli/Cargo.lock index ab1f4548d9..7d513ab8d2 100644 --- a/mm2src/adex_cli/Cargo.lock +++ b/mm2src/adex_cli/Cargo.lock @@ -1781,6 +1781,7 @@ dependencies = [ "async-trait", "cfg-if 1.0.0", "common", + "futures 0.3.28", "parking_lot", "serde", "tokio",