From ede9a67ed985bfc9cfdc88ffc54ec1f3680bea27 Mon Sep 17 00:00:00 2001 From: Anton Yemelyanov Date: Fri, 8 Sep 2023 08:46:37 +0300 Subject: [PATCH] rename wallet event members for serde serialization misc wallet functionality update --- Cargo.lock | 38 -------------------- Cargo.toml | 40 +++++++++++----------- cli/src/cli.rs | 18 ++++++---- cli/src/modules/monitor.rs | 2 +- cli/src/modules/wallet.rs | 11 ++++++ kaspad/src/daemon.rs | 6 ++-- kaspad/src/main.rs | 2 +- testing/integration/src/common/daemon.rs | 2 +- wallet/core/src/events.rs | 10 ++++-- wallet/core/src/runtime/sync.rs | 10 +++--- wallet/core/src/runtime/wallet.rs | 24 +++++++++---- wallet/core/src/storage/interface.rs | 4 +++ wallet/core/src/storage/local/interface.rs | 16 +++++++++ wallet/core/src/utxo/processor.rs | 16 ++++----- 14 files changed, 106 insertions(+), 93 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8f81a1a50..f92136edd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5676,8 +5676,6 @@ dependencies = [ [[package]] name = "workflow-core" version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38b35eec0ad8613e9ecc16eff2b08ca8664685403fb820c0ba864ea5670908b8" dependencies = [ "async-channel", "async-std", @@ -5706,8 +5704,6 @@ dependencies = [ [[package]] name = "workflow-core-macros" version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "674307f4212fc4d88048376afd11f4f79e32cb88db536e5027f7e396f4fbbac3" dependencies = [ "convert_case 0.6.0", "parse-variants", @@ -5723,8 +5719,6 @@ dependencies = [ [[package]] name = "workflow-d3" version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a90370f6a956e4d6197519292967304d2970a308020082f0c48578638529d28e" dependencies = [ "atomic_float", "js-sys", @@ -5740,8 +5734,6 @@ dependencies = [ [[package]] name = "workflow-dom" version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60ec7f9a66bae5110a202b0244ec0e49b9d99a4516574f1471f907b676497585" dependencies = [ "futures", "js-sys", @@ -5758,8 +5750,6 @@ dependencies = [ [[package]] name = "workflow-log" version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61c7efd64dd4b11b20bab2bd1ce32b53233983b08d3601ca854d3f9935d9cb38" dependencies = [ "cfg-if 1.0.0", "console", @@ -5774,8 +5764,6 @@ dependencies = [ [[package]] name = "workflow-macro-tools" version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40f1eabad4a080f068b480b4f78674bdf6a724cd20f17dc8450af3e6ca43d5ef" dependencies = [ "convert_case 0.6.0", "parse-variants", @@ -5787,8 +5775,6 @@ dependencies = [ [[package]] name = "workflow-node" version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47713beb7429f908cafe3f0c30050921da884301d841819ab469d611ac5ff690" dependencies = [ "borsh", "futures", @@ -5808,8 +5794,6 @@ dependencies = [ [[package]] name = "workflow-nw" version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c9f59ac7e450d4a4a5fb91dd5d80ddeca7136f0cbc567c6ad27fa198568ee0a" dependencies = [ "ahash 0.8.3", "async-trait", @@ -5832,8 +5816,6 @@ dependencies = [ [[package]] name = "workflow-panic-hook" version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c877a03eb59e3b2cc579dbd6b40fe9a991fca94a17027fbc483165a2e9c8f049" dependencies = [ "cfg-if 1.0.0", "wasm-bindgen", @@ -5857,8 +5839,6 @@ dependencies = [ [[package]] name = "workflow-rpc" version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eccb7ec23c6acf1369e15e06f322a321550f571a4803fcd53f6a59d2d7af7c22" dependencies = [ "ahash 0.8.3", "async-std", @@ -5886,8 +5866,6 @@ dependencies = [ [[package]] name = "workflow-rpc-macros" version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0aef8d20c23c68724df5b34318d12d21626b78586ebb2071aee0d5cab341863" dependencies = [ "parse-variants", "proc-macro-error", @@ -5899,8 +5877,6 @@ dependencies = [ [[package]] name = "workflow-store" version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03e5e712429629272cb26868a1643063842d1ec74378e4eb525e9e7d8ece4e2a" dependencies = [ "async-std", "base64 0.21.2", @@ -5924,8 +5900,6 @@ dependencies = [ [[package]] name = "workflow-task" version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b63361b6dc6c54fa79d3cd0eefe55b35df9f566688effb1d59e0b4cc31550ab" dependencies = [ "futures", "thiserror", @@ -5936,8 +5910,6 @@ dependencies = [ [[package]] name = "workflow-task-macros" version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0191357065dab5be2ff361efc41e94409dd6d081ba824dda7c5ccb94fabe364b" dependencies = [ "convert_case 0.6.0", "parse-variants", @@ -5952,8 +5924,6 @@ dependencies = [ [[package]] name = "workflow-terminal" version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "352e28815e7234996958d5b36a48a05f055c5f48a08ab490298acdd6d066c458" dependencies = [ "async-std", "async-trait", @@ -5981,8 +5951,6 @@ dependencies = [ [[package]] name = "workflow-terminal-macros" version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6105fb18c17fd36d4712d87e5e6360e699fce717397a87dea65a2f16c2752b27" dependencies = [ "convert_case 0.6.0", "parse-variants", @@ -5997,8 +5965,6 @@ dependencies = [ [[package]] name = "workflow-wasm" version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d87f799a46745701f69606fc5012f5e63e6856b9c5e4f798c364d2785ad05642" dependencies = [ "cfg-if 1.0.0", "faster-hex 0.8.0", @@ -6018,8 +5984,6 @@ dependencies = [ [[package]] name = "workflow-wasm-macros" version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6118b89201b1ff702c8e3a98d5d27e1c0aa22a57aa0595f88f7173445d35c9d2" dependencies = [ "js-sys", "proc-macro-error", @@ -6032,8 +5996,6 @@ dependencies = [ [[package]] name = "workflow-websocket" version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df3a5adc02ea7ff9b4b4209dd0534ba0efffc7a817711ec894fed077712992bc" dependencies = [ "ahash 0.8.3", "async-std", diff --git a/Cargo.toml b/Cargo.toml index d788e8ce5..efa9c9196 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -203,31 +203,31 @@ pbkdf2 = { version = "0.12.1" } # pbkdf2 = { version = "0.11", default-features = false} # workflow dependencies -workflow-d3 = { version = "0.6.0" } -workflow-nw = { version = "0.6.0" } -workflow-log = { version = "0.6.0" } -workflow-core = { version = "0.6.0" } -workflow-wasm = { version = "0.6.1" } -workflow-dom = { version = "0.6.0" } -workflow-rpc = { version = "0.6.0" } -workflow-node = { version = "0.6.0" } -workflow-store = { version = "0.6.0" } -workflow-terminal = { version = "0.6.0" } +# workflow-d3 = { version = "0.6.0" } +# workflow-nw = { version = "0.6.0" } +# workflow-log = { version = "0.6.0" } +# workflow-core = { version = "0.6.0" } +# workflow-wasm = { version = "0.6.1" } +# workflow-dom = { version = "0.6.0" } +# workflow-rpc = { version = "0.6.0" } +# workflow-node = { version = "0.6.0" } +# workflow-store = { version = "0.6.0" } +# workflow-terminal = { version = "0.6.0" } nw-sys = "0.1.5" # if below is enabled, this means that there is an ongoing work # on the workflow-rs crate. This requires that you clone workflow-rs # into a sibling folder from https://github.com/workflow-rs/workflow-rs -# workflow-d3 = { path = "../workflow-rs/d3" } -# workflow-nw = { path = "../workflow-rs/nw" } -# workflow-log = { path = "../workflow-rs/log" } -# workflow-core = { path = "../workflow-rs/core" } -# workflow-wasm = { path = "../workflow-rs/wasm" } -# workflow-dom = { path = "../workflow-rs/dom" } -# workflow-rpc = { path = "../workflow-rs/rpc" } -# workflow-node = { path = "../workflow-rs/node" } -# workflow-store = { path = "../workflow-rs/store" } -# workflow-terminal = { path = "../workflow-rs/terminal" } +workflow-d3 = { path = "../workflow-rs/d3" } +workflow-nw = { path = "../workflow-rs/nw" } +workflow-log = { path = "../workflow-rs/log" } +workflow-core = { path = "../workflow-rs/core" } +workflow-wasm = { path = "../workflow-rs/wasm" } +workflow-dom = { path = "../workflow-rs/dom" } +workflow-rpc = { path = "../workflow-rs/rpc" } +workflow-node = { path = "../workflow-rs/node" } +workflow-store = { path = "../workflow-rs/store" } +workflow-terminal = { path = "../workflow-rs/terminal" } # https://github.com/aspectron/nw-sys # nw-sys = { path = "../nw-sys" } diff --git a/cli/src/cli.rs b/cli/src/cli.rs index 90763c10e..da7633804 100644 --- a/cli/src/cli.rs +++ b/cli/src/cli.rs @@ -283,8 +283,8 @@ impl KaspaCli { match msg { Events::UtxoProcStart => {}, Events::UtxoProcStop => {}, - Events::UtxoProcError(err) => { - terrorln!(this,"{err}"); + Events::UtxoProcError { message } => { + terrorln!(this,"{message}"); }, #[allow(unused_variables)] Events::Connect{ url, network_id } => { @@ -298,8 +298,8 @@ impl KaspaCli { Events::UtxoIndexNotEnabled => { tprintln!(this, "Error: Kaspa node UTXO index is not enabled...") }, - Events::SyncState(state) => { - this.sync_state.lock().unwrap().replace(state); + Events::SyncState { sync_state } => { + this.sync_state.lock().unwrap().replace(sync_state); this.term().refresh_prompt(); } Events::ServerStatus { @@ -334,11 +334,15 @@ impl KaspaCli { } }, + Events::AccountSelection { .. } => { }, + Events::WalletError { .. } => { }, Events::WalletOpen | Events::WalletReload => { // load all accounts - this.wallet().activate_all_stored_accounts().await.unwrap_or_else(|err|terrorln!(this, "{err}")); + if let Err(err) = this.wallet().activate_all_stored_accounts().await { + terrorln!(this, "{err}"); + } // list all accounts this.list().await.unwrap_or_else(|err|terrorln!(this, "{err}")); @@ -351,9 +355,9 @@ impl KaspaCli { Events::WalletClose => { this.term().refresh_prompt(); }, - Events::DAAScoreChange(daa) => { + Events::DAAScoreChange { daa_score } => { if this.is_mutted() && this.flags.get(Track::Daa) { - tprintln!(this, "{NOTIFY} DAA: {daa}"); + tprintln!(this, "{NOTIFY} DAA: {daa_score}"); } }, Events::Reorg { diff --git a/cli/src/modules/monitor.rs b/cli/src/modules/monitor.rs index 325d30d82..4b51b2435 100644 --- a/cli/src/modules/monitor.rs +++ b/cli/src/modules/monitor.rs @@ -109,7 +109,7 @@ impl Monitor { let events = events.lock().unwrap(); events.iter().for_each(|event| match event { - Events::DAAScoreChange(..) => {} + Events::DAAScoreChange { .. } => {} Events::Balance { balance, id, mature_utxo_size, pending_utxo_size } => { let network_id = wallet.network_id().expect("missing network type"); let network_type = NetworkType::from(network_id); diff --git a/cli/src/modules/wallet.rs b/cli/src/modules/wallet.rs index a5b00b27a..39b39320f 100644 --- a/cli/src/modules/wallet.rs +++ b/cli/src/modules/wallet.rs @@ -14,6 +14,17 @@ impl Wallet { } match argv.remove(0).as_str() { + "list" => { + let wallets = ctx.store().wallet_list().await?; + if wallets.is_empty() { + tprintln!(ctx, "No wallets found"); + } else { + tprintln!(ctx, "Wallets:"); + for wallet in wallets { + tprintln!(ctx, " {}", wallet); + } + } + } "create" => { let wallet_name = if argv.is_empty() { None diff --git a/kaspad/src/daemon.rs b/kaspad/src/daemon.rs index 8568b6acc..156c172cb 100644 --- a/kaspad/src/daemon.rs +++ b/kaspad/src/daemon.rs @@ -131,12 +131,12 @@ impl Runtime { } } -pub fn create_core(args: Args) -> (Arc,Arc) { +pub fn create_core(args: Args) -> (Arc, Arc) { let rt = Runtime::from_args(&args); create_core_with_runtime(&rt, &args) } -pub fn create_core_with_runtime(runtime: &Runtime, args: &Args) -> (Arc,Arc) { +pub fn create_core_with_runtime(runtime: &Runtime, args: &Args) -> (Arc, Arc) { let network = args.network(); // Make sure args forms a valid set of properties @@ -353,5 +353,5 @@ do you confirm? (answer y/n or pass --yes to the Kaspad command line to confirm core.bind(consensus_manager); core.bind(async_runtime); - (core,rpc_core_service) + (core, rpc_core_service) } diff --git a/kaspad/src/main.rs b/kaspad/src/main.rs index 97151769e..8316ebd8e 100644 --- a/kaspad/src/main.rs +++ b/kaspad/src/main.rs @@ -16,7 +16,7 @@ pub fn main() { let _profiler = dhat::Profiler::builder().file_name("kaspad-heap.json").build(); let args = parse_args(); - let (core,_) = create_core(args); + let (core, _) = create_core(args); // Bind the keyboard signal to the core Arc::new(Signals::new(&core)).init(); diff --git a/testing/integration/src/common/daemon.rs b/testing/integration/src/common/daemon.rs index bbb7b2538..db89fdab1 100644 --- a/testing/integration/src/common/daemon.rs +++ b/testing/integration/src/common/daemon.rs @@ -54,7 +54,7 @@ impl Daemon { args.appdir = Some(appdir_tempdir.path().to_str().unwrap().to_owned()); let network = args.network(); - let core = create_core_with_runtime(&Default::default(), &args); + let (core, _) = create_core_with_runtime(&Default::default(), &args); Daemon { network, rpc_port, p2p_port, core, workers: None, _appdir_tempdir: appdir_tempdir } } diff --git a/wallet/core/src/events.rs b/wallet/core/src/events.rs index a84700910..ff873c379 100644 --- a/wallet/core/src/events.rs +++ b/wallet/core/src/events.rs @@ -67,16 +67,20 @@ pub enum Events { UtxoIndexNotEnabled, /// [`SyncState`] notification posted /// when the node sync state changes - SyncState(SyncState), + SyncState { sync_state: SyncState }, /// Emitted after the wallet has loaded and /// contains anti-phishing 'hint' set by the user. WalletHint { hint: Option }, /// Wallet has opened WalletOpen, + /// Wallet open failure + WalletError { message: String }, /// Wallet reload initiated (development only) WalletReload, /// Wallet has been closed WalletClose, + /// Account selection change (`None` if no account is selected) + AccountSelection { id: Option }, /// Emitted after successful RPC connection /// after the initial state negotiation. ServerStatus { @@ -99,9 +103,9 @@ pub enum Events { UtxoProcStop, /// Occurs when UtxoProcessor has failed to connect to the node /// for an unknown reason. (general error trap) - UtxoProcError(String), + UtxoProcError { message: String }, /// DAA score change - DAAScoreChange(u64), + DAAScoreChange { daa_score: u64 }, /// New incoming pending UTXO/transaction Pending { record: TransactionRecord, diff --git a/wallet/core/src/runtime/sync.rs b/wallet/core/src/runtime/sync.rs index 42a8930ce..68da4bef5 100644 --- a/wallet/core/src/runtime/sync.rs +++ b/wallet/core/src/runtime/sync.rs @@ -48,7 +48,7 @@ impl SyncMonitor { log_trace!("sync monitor: stopping sync monitor task"); self.stop_task().await?; } - self.notify(Events::SyncState(SyncState::Synced)).await?; + self.notify(Events::SyncState { sync_state: SyncState::Synced }).await?; } else { self.inner.is_synced.store(false, Ordering::SeqCst); log_trace!("sync monitor: node is not synced"); @@ -56,7 +56,7 @@ impl SyncMonitor { log_trace!("sync monitor: starting sync monitor task"); self.start_task().await?; } - self.notify(Events::SyncState(SyncState::NotSynced)).await?; + self.notify(Events::SyncState { sync_state: SyncState::NotSynced }).await?; } } @@ -133,7 +133,7 @@ impl SyncMonitor { if is_synced { if is_synced != this.is_synced() { this.inner.is_synced.store(true, Ordering::SeqCst); - this.notify(Events::SyncState(SyncState::Synced)).await.unwrap_or_else(|err|log_error!("SyncProc error dispatching notification event: {err}")); + this.notify(Events::SyncState { sync_state : SyncState::Synced }).await.unwrap_or_else(|err|log_error!("SyncProc error dispatching notification event: {err}")); // this.notify(Events::NodeSync { is_synced }).await.unwrap_or_else(|err|log_error!("SyncProc error dispatching notification event: {err}")); } @@ -181,8 +181,8 @@ impl SyncMonitor { } } } - if let Some(state) = state { - self.notify(Events::SyncState(state)).await?; + if let Some(sync_state) = state { + self.notify(Events::SyncState { sync_state }).await?; } Ok(()) diff --git a/wallet/core/src/runtime/wallet.rs b/wallet/core/src/runtime/wallet.rs index 51d8b5068..bcd368de8 100644 --- a/wallet/core/src/runtime/wallet.rs +++ b/wallet/core/src/runtime/wallet.rs @@ -220,9 +220,8 @@ impl Wallet { /// For end-user wallets only - activates all accounts in the wallet /// storage. - pub async fn activate_all_stored_accounts(self: &Arc) -> Result<()> { - self.accounts(None).await?.try_collect::>().await?; - Ok(()) + pub async fn activate_all_stored_accounts(self: &Arc) -> Result>> { + Ok(self.accounts(None).await?.try_collect::>().await?) } /// Select an account as 'active'. Supply `None` to remove active selection. @@ -231,6 +230,9 @@ impl Wallet { if let Some(account) = account { // log_info!("selecting account: {}", account.name_or_id()); account.clone().start().await?; + self.notify(Events::AccountSelection{ id : Some(*account.id()) }).await?; + } else { + self.notify(Events::AccountSelection{ id : None }).await?; } Ok(()) } @@ -246,7 +248,7 @@ impl Wallet { } /// Loads a wallet from storage. Accounts are not activated by this call. - pub async fn load(self: &Arc, secret: Secret, name: Option) -> Result<()> { + async fn load_impl(self: &Arc, secret: Secret, name: Option) -> Result<()> { self.reset().await?; let name = name.or_else(|| self.settings().get(WalletSettings::Wallet)); @@ -260,6 +262,16 @@ impl Wallet { Ok(()) } + /// Loads a wallet from storage. Accounts are not activated by this call. + pub async fn load(self: &Arc, secret: Secret, name: Option) -> Result<()> { + if let Err(err) = self.load_impl(secret, name).await { + self.notify(Events::WalletError { message: err.to_string() }).await?; + Err(err) + } else { + Ok(()) + } + } + pub async fn get_prv_key_data(&self, wallet_secret: Secret, id: &PrvKeyDataId) -> Result> { let ctx: Arc = Arc::new(AccessContext::new(wallet_secret)); self.inner.store.as_prv_key_data_store()?.load_key_data(&ctx, id).await @@ -541,8 +553,8 @@ impl Wallet { Events::Reorg { record } | Events::External { record } | Events::Outgoing { record } => { self.store().as_transaction_record_store()?.store(&[record]).await?; } - Events::SyncState(state) => { - if state.is_synced() && self.is_open() { + Events::SyncState { sync_state } => { + if sync_state.is_synced() && self.is_open() { self.reload().await?; } } diff --git a/wallet/core/src/storage/interface.rs b/wallet/core/src/storage/interface.rs index 483b18785..817799006 100644 --- a/wallet/core/src/storage/interface.rs +++ b/wallet/core/src/storage/interface.rs @@ -123,6 +123,10 @@ impl OpenArgs { #[async_trait] pub trait Interface: Send + Sync + AnySync { + /// enumerate all wallets available in the storage + async fn wallet_list(&self) -> Result>; + + /// check if a wallet is currently open fn is_open(&self) -> bool; /// return storage information string (file location) diff --git a/wallet/core/src/storage/local/interface.rs b/wallet/core/src/storage/local/interface.rs index df823bb16..e1b35de48 100644 --- a/wallet/core/src/storage/local/interface.rs +++ b/wallet/core/src/storage/local/interface.rs @@ -14,6 +14,7 @@ use crate::storage::*; use std::sync::atomic::AtomicBool; use std::sync::atomic::Ordering; use workflow_core::runtime::is_web; +use workflow_store::fs; pub enum Store { Resident, @@ -227,6 +228,21 @@ impl Interface for LocalStore { Ok(()) } + async fn wallet_list(&self) -> Result> { + let location = self.location.lock().unwrap().clone().unwrap(); + + let folder = fs::resolve_path(&location.folder)?; + let files = fs::readdir(folder, false).await?; + let wallets = files + .iter() + .filter_map(|de| { + let file_name = de.file_name(); + file_name.ends_with(".wallet").then(|| file_name.trim_end_matches(".wallet").to_string()) + }) + .collect::>(); + Ok(wallets) + } + fn is_open(&self) -> bool { self.inner.lock().unwrap().is_some() } diff --git a/wallet/core/src/utxo/processor.rs b/wallet/core/src/utxo/processor.rs index 60efd8a79..4888f1d10 100644 --- a/wallet/core/src/utxo/processor.rs +++ b/wallet/core/src/utxo/processor.rs @@ -165,20 +165,20 @@ impl UtxoProcessor { Ok(()) } - pub async fn handle_daa_score_change(&self, current_daa_score: u64) -> Result<()> { - self.inner.current_daa_score.store(current_daa_score, Ordering::SeqCst); - self.notify(Events::DAAScoreChange(current_daa_score)).await?; - self.handle_pending(current_daa_score).await?; - self.handle_recoverable(current_daa_score).await?; + pub async fn handle_daa_score_change(&self, daa_score: u64) -> Result<()> { + self.inner.current_daa_score.store(daa_score, Ordering::SeqCst); + self.notify(Events::DAAScoreChange { daa_score }).await?; + self.handle_pending(daa_score).await?; + self.handle_recoverable(daa_score).await?; Ok(()) } - pub async fn handle_pending(&self, current_daa_score: u64) -> Result<()> { + pub async fn handle_pending(&self, daa_score: u64) -> Result<()> { let mature_entries = { let mut mature_entries = vec![]; let pending_entries = &self.inner.pending; pending_entries.retain(|_, pending| { - if pending.is_mature(current_daa_score) { + if pending.is_mature(daa_score) { mature_entries.push(pending.clone()); false } else { @@ -318,7 +318,7 @@ impl UtxoProcessor { pub async fn handle_connect(&self) -> Result<()> { if let Err(err) = self.handle_connect_impl().await { - self.notify(Events::UtxoProcError(err.to_string())).await?; + self.notify(Events::UtxoProcError { message: err.to_string() }).await?; self.rpc_client().disconnect().await?; } Ok(())