Skip to content

Commit 32dbe08

Browse files
authored
fix: dont start second utxo scanner for recovery (#7298)
Description --- Dont start a new utxo scanning service, simply listen to its feedback. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Simplified the wallet recovery process to use the existing UTXO scanner service for monitoring progress. * **Refactor** * Streamlined the recovery workflow by removing redundant parameters and tasks, resulting in a cleaner and more efficient recovery operation. * Removed unused message settings from the UTXO scanner configuration. * **Chores** * Updated function signatures and field visibility for improved integration and maintainability. * Cleaned up related test setups and documentation to reflect the simplified recovery interface. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
1 parent 453ebb6 commit 32dbe08

File tree

9 files changed

+15
-143
lines changed

9 files changed

+15
-143
lines changed

Cargo.lock

Lines changed: 0 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

base_layer/wallet/src/utxo_scanner_service/uxto_scanner_service_builder.rs

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,6 @@ impl Debug for UtxoScannerMode {
6363
pub struct UtxoScannerServiceBuilder<TWalletClientFactory> {
6464
retry_limit: usize,
6565
mode: Option<UtxoScannerMode>,
66-
one_sided_message: String,
67-
recovery_message: String,
6866
client_factory: Option<TWalletClientFactory>,
6967
scanning_interval: u64,
7068
}
@@ -74,8 +72,6 @@ impl<T> Default for UtxoScannerServiceBuilder<T> {
7472
Self {
7573
retry_limit: 0,
7674
mode: None,
77-
one_sided_message: "Detected one-sided payment on blockchain".to_string(),
78-
recovery_message: "Output found on blockchain during Wallet Recovery".to_string(),
7975
client_factory: None,
8076
scanning_interval: 60, // Default scanning interval in seconds
8177
}
@@ -95,16 +91,6 @@ impl<T: HttpClientFactory + Clone + Send + Sync + 'static> UtxoScannerServiceBui
9591
self
9692
}
9793

98-
pub fn with_one_sided_message(&mut self, message: String) -> &mut Self {
99-
self.one_sided_message = message;
100-
self
101-
}
102-
103-
pub fn with_recovery_message(&mut self, message: String) -> &mut Self {
104-
self.recovery_message = message;
105-
self
106-
}
107-
10894
pub fn with_client_factory(&mut self, factory: T) -> &mut Self {
10995
self.client_factory = Some(factory);
11096
self

base_layer/wallet/tests/utxo_scanner/mod.rs

Lines changed: 6 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,6 @@ async fn setup(
102102
key_manager: MemoryDbKeyManager,
103103
mode: UtxoScannerMode,
104104
previous_db: Option<WalletDatabase<WalletSqliteDatabase>>,
105-
recovery_message: Option<String>,
106-
one_sided_message: Option<String>,
107105
) -> UtxoScannerTestInterface {
108106
let shutdown = Shutdown::new();
109107

@@ -169,14 +167,6 @@ async fn setup(
169167

170168
scanner_service_builder.with_retry_limit(1).with_mode(mode);
171169

172-
if let Some(message) = one_sided_message {
173-
scanner_service_builder.with_one_sided_message(message);
174-
}
175-
176-
if let Some(message) = recovery_message {
177-
scanner_service_builder.with_recovery_message(message);
178-
}
179-
180170
let view_key = key_manager.get_view_key().await.unwrap();
181171
let tari_address = TariAddress::new_dual_address_with_default_features(
182172
view_key.pub_key,
@@ -284,7 +274,7 @@ async fn generate_block_headers_and_utxos(
284274
async fn test_utxo_scanner_recovery() {
285275
// env_logger::builder().filter_level(log::LevelFilter::Trace).init(); // > ./target/output.log 2>&1
286276
let key_manager = create_memory_db_key_manager().unwrap();
287-
let mut test_interface = setup(key_manager.clone(), UtxoScannerMode::Recovery, None, None, None).await;
277+
let mut test_interface = setup(key_manager.clone(), UtxoScannerMode::Recovery, None).await;
288278

289279
let cipher_seed = CipherSeed::new();
290280
// get birthday duration, in seconds, from unix epoch
@@ -379,7 +369,7 @@ async fn test_utxo_scanner_recovery() {
379369
#[allow(clippy::too_many_lines)]
380370
async fn test_utxo_scanner_recovery_with_restart() {
381371
let key_manager = create_memory_db_key_manager().unwrap();
382-
let mut test_interface = setup(key_manager.clone(), UtxoScannerMode::Recovery, None, None, None).await;
372+
let mut test_interface = setup(key_manager.clone(), UtxoScannerMode::Recovery, None).await;
383373

384374
let cipher_seed = CipherSeed::new();
385375
// get birthday duration, in seconds, from unix epoch
@@ -480,8 +470,6 @@ async fn test_utxo_scanner_recovery_with_restart() {
480470
key_manager.clone(),
481471
UtxoScannerMode::Recovery,
482472
Some(test_interface.wallet_db),
483-
Some("recovery".to_string()),
484-
None,
485473
)
486474
.await;
487475
test_interface2
@@ -528,7 +516,7 @@ async fn test_utxo_scanner_recovery_with_restart() {
528516
#[allow(clippy::too_many_lines)]
529517
async fn test_utxo_scanner_recovery_with_restart_and_reorg() {
530518
let key_manager = create_memory_db_key_manager().unwrap();
531-
let mut test_interface = setup(key_manager.clone(), UtxoScannerMode::Recovery, None, None, None).await;
519+
let mut test_interface = setup(key_manager.clone(), UtxoScannerMode::Recovery, None).await;
532520

533521
let cipher_seed = CipherSeed::new();
534522
// get birthday duration, in seconds, from unix epoch
@@ -625,8 +613,6 @@ async fn test_utxo_scanner_recovery_with_restart_and_reorg() {
625613
key_manager.clone(),
626614
UtxoScannerMode::Recovery,
627615
Some(test_interface.wallet_db),
628-
None,
629-
None,
630616
)
631617
.await;
632618
test_interface2
@@ -712,7 +698,7 @@ async fn test_utxo_scanner_recovery_with_restart_and_reorg() {
712698
#[allow(clippy::too_many_lines)]
713699
async fn test_utxo_scanner_scanned_block_cache_clearing() {
714700
let key_manager = create_memory_db_key_manager().unwrap();
715-
let mut test_interface = setup(key_manager.clone(), UtxoScannerMode::Recovery, None, None, None).await;
701+
let mut test_interface = setup(key_manager.clone(), UtxoScannerMode::Recovery, None).await;
716702

717703
for h in 0u64..800u64 {
718704
// let num_outputs = if h % 2 == 1 { Some(1) } else { None };
@@ -850,14 +836,7 @@ async fn test_utxo_scanner_scanned_block_cache_clearing() {
850836
async fn test_utxo_scanner_one_sided_payments() {
851837
// env_logger::builder().filter_level(log::LevelFilter::Trace).init(); // > ./target/output.log 2>&1
852838
let key_manager = create_memory_db_key_manager().unwrap();
853-
let mut test_interface = setup(
854-
key_manager.clone(),
855-
UtxoScannerMode::Scanning,
856-
None,
857-
None,
858-
Some("one-sided non-default".to_string()),
859-
)
860-
.await;
839+
let mut test_interface = setup(key_manager.clone(), UtxoScannerMode::Scanning, None).await;
861840

862841
let cipher_seed = CipherSeed::new();
863842
// get birthday duration, in seconds, from unix epoch
@@ -1041,7 +1020,7 @@ async fn test_utxo_scanner_one_sided_payments() {
10411020
#[tokio::test]
10421021
async fn test_birthday_timestamp_over_chain() {
10431022
let key_manager = create_memory_db_key_manager().unwrap();
1044-
let test_interface = setup(key_manager, UtxoScannerMode::Recovery, None, None, None).await;
1023+
let test_interface = setup(key_manager, UtxoScannerMode::Recovery, None).await;
10451024

10461025
let cipher_seed = CipherSeed::new();
10471026
// get birthday duration, in seconds, from unix epoch

base_layer/wallet_ffi/Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ num-traits = "0.2.15"
4343
itertools = "0.10.3"
4444
zeroize = "1"
4545
serde_json = "1.0"
46-
url = { version = "2.5.4", features = ["default", "serde"] }
4746

4847
[target.'cfg(target_os="android")'.dependencies]
4948
openssl = { version = "0.10.72", features = ["vendored"] }

base_layer/wallet_ffi/src/lib.rs

Lines changed: 7 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,6 @@ use log4rs::{
8181
};
8282
use minotari_wallet::{
8383
base_node_service::config::BaseNodeServiceConfig,
84-
client::http_client_factory::{DefaultHttpClientFactory, HttpClientFactory},
8584
connectivity_service::WalletConnectivityInterface,
8685
error::{WalletError, WalletStorageError},
8786
output_manager_service::{
@@ -95,7 +94,6 @@ use minotari_wallet::{
9594
},
9695
storage::{
9796
database::WalletDatabase,
98-
sqlite_db::wallet::WalletSqliteDatabase,
9997
sqlite_utilities::{get_last_network, get_last_version, initialize_sqlite_database_backends},
10098
},
10199
transaction_service::{
@@ -106,11 +104,10 @@ use minotari_wallet::{
106104
models::{CompletedTransaction, InboundTransaction, OutboundTransaction},
107105
},
108106
},
109-
utxo_scanner_service::{service::UtxoScannerService, RECOVERY_KEY},
107+
utxo_scanner_service::RECOVERY_KEY,
110108
wallet::{derive_comms_secret_key, read_or_create_master_seed, WalletMessageSigningDomain},
111109
Wallet,
112110
WalletConfig,
113-
WalletKeyManager,
114111
WalletSqlite,
115112
};
116113
use num_traits::FromPrimitive;
@@ -192,7 +189,6 @@ use tari_utilities::{
192189
SafePassword,
193190
};
194191
use tokio::runtime::Runtime;
195-
use url::Url;
196192
use zeroize::Zeroize;
197193

198194
use crate::{
@@ -281,7 +277,7 @@ pub struct TariSeedWords(SeedWords);
281277
pub struct TariPublicKeys(Vec<TariPublicKey>);
282278

283279
pub struct TariWallet {
284-
wallet: WalletSqlite,
280+
pub wallet: WalletSqlite,
285281
runtime: Runtime,
286282
shutdown: Shutdown,
287283
context: Context,
@@ -10064,7 +10060,6 @@ pub unsafe extern "C" fn wallet_is_recovery_in_progress(wallet: *mut TariWallet,
1006410060
///
1006510061
/// ## Arguments
1006610062
/// `wallet` - The TariWallet pointer.
10067-
/// `base_node_public_keys` - An optional TariPublicKeys pointer of the Base Nodes the recovery process must use
1006810063
/// `recovery_progress_callback` - The callback function pointer that will be used to asynchronously communicate
1006910064
/// progress to the client. The first argument of the callback is an event enum encoded as a u8 as follows:
1007010065
/// ```
@@ -10102,9 +10097,6 @@ pub unsafe extern "C" fn wallet_is_recovery_in_progress(wallet: *mut TariWallet,
1010210097
/// - If a unrecoverable error occurs the `RecoveryFailed` event will be returned and the client will need to start
1010310098
/// a new process.
1010410099
///
10105-
/// `recovered_output_message` - A string that will be used as the message for any recovered outputs. If Null the
10106-
/// default message will be used
10107-
///
1010810100
/// `error_out` - Pointer to an int which will be modified to an error code should one occur, may not be null. Functions
1010910101
/// as an out parameter.
1011010102
///
@@ -10118,9 +10110,7 @@ pub unsafe extern "C" fn wallet_is_recovery_in_progress(wallet: *mut TariWallet,
1011810110
#[no_mangle]
1011910111
pub unsafe extern "C" fn wallet_start_recovery(
1012010112
wallet: *mut TariWallet,
10121-
http_base_node: *const c_char,
1012210113
recovery_progress_callback: unsafe extern "C" fn(context: *mut c_void, u8, u64, u64),
10123-
recovered_output_message: *const c_char,
1012410114
error_out: *mut c_int,
1012510115
) -> bool {
1012610116
if error_out.is_null() {
@@ -10133,68 +10123,11 @@ pub unsafe extern "C" fn wallet_start_recovery(
1013310123
return false;
1013410124
}
1013510125

10136-
let runtime = match Runtime::new() {
10137-
Ok(r) => r,
10138-
Err(e) => {
10139-
*error_out = LibWalletError::from(InterfaceError::TokioError(e.to_string())).code;
10140-
return false;
10141-
},
10142-
};
10143-
let shutdown_signal = (*wallet).shutdown.to_signal();
10144-
let mut recovery_task_builder =
10145-
UtxoScannerService::<WalletSqliteDatabase, WalletKeyManager, DefaultHttpClientFactory>::builder();
10146-
10147-
if !recovered_output_message.is_null() {
10148-
let message_str = match CStr::from_ptr(recovered_output_message).to_str() {
10149-
Ok(v) => v.to_owned(),
10150-
_ => {
10151-
*error_out =
10152-
LibWalletError::from(InterfaceError::PointerError("recovered_output_message".to_string())).code;
10153-
return false;
10154-
},
10155-
};
10156-
recovery_task_builder.with_recovery_message(message_str);
10157-
}
10158-
let http_url = if http_base_node.is_null() {
10159-
*error_out = LibWalletError::from(InterfaceError::NullError("http_base_node".to_string())).code;
10160-
return false;
10161-
} else {
10162-
match CStr::from_ptr(http_base_node).to_str() {
10163-
Ok(v) => match Url::parse(v) {
10164-
Ok(url) => url,
10165-
Err(e) => {
10166-
*error_out =
10167-
LibWalletError::from(InterfaceError::InvalidArgument(format!("Url is not valid: {}", e))).code;
10168-
return false;
10169-
},
10170-
},
10171-
_ => {
10172-
*error_out = LibWalletError::from(InterfaceError::PointerError("http_base_node".to_string())).code;
10173-
return false;
10174-
},
10175-
}
10176-
};
10177-
let mut recovery_task = match runtime.block_on(async {
10178-
recovery_task_builder
10179-
.with_client_factory(DefaultHttpClientFactory::new(http_url))
10180-
.with_retry_limit(10)
10181-
.build_with_wallet(&(*wallet).wallet, shutdown_signal)
10182-
.await
10183-
}) {
10184-
Ok(v) => v,
10185-
Err(e) => {
10186-
*error_out = LibWalletError::from(WalletError::ServiceInitializationError(e)).code;
10187-
return false;
10188-
},
10189-
};
10190-
10191-
let event_stream = recovery_task.get_event_receiver();
10192-
let recovery_join_handle = (*wallet).runtime.spawn(recovery_task.run());
10126+
let event_stream = (*wallet).wallet.utxo_scanner_service.clone().get_event_receiver();
1019310127

1019410128
// Spawn a task to monitor the recovery process events and call the callback appropriately
1019510129
(*wallet).runtime.spawn(recovery_event_monitoring(
1019610130
event_stream,
10197-
recovery_join_handle,
1019810131
recovery_progress_callback,
1019910132
(*wallet).context,
1020010133
));
@@ -10835,7 +10768,10 @@ mod test {
1083510768
use std::{ffi::c_void, str::from_utf8, sync::Mutex};
1083610769

1083710770
use minotari_wallet::{
10838-
storage::sqlite_utilities::run_migration_and_create_sqlite_connection,
10771+
storage::{
10772+
sqlite_db::wallet::WalletSqliteDatabase,
10773+
sqlite_utilities::run_migration_and_create_sqlite_connection,
10774+
},
1083910775
transaction_service::handle::TransactionSendStatus,
1084010776
};
1084110777
use once_cell::sync::Lazy;

base_layer/wallet_ffi/src/tasks.rs

Lines changed: 2 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@
2323
use std::ffi::c_void;
2424

2525
use log::*;
26-
use minotari_wallet::{error::WalletError, utxo_scanner_service::handle::UtxoScannerEvent};
26+
use minotari_wallet::utxo_scanner_service::handle::UtxoScannerEvent;
2727
use tari_utilities::hex::Hex;
28-
use tokio::{sync::broadcast, task::JoinHandle};
28+
use tokio::sync::broadcast;
2929

3030
use crate::callback_handler::Context;
3131

@@ -45,7 +45,6 @@ enum RecoveryEvent {
4545
#[allow(clippy::too_many_lines)]
4646
pub async fn recovery_event_monitoring(
4747
mut event_stream: broadcast::Receiver<UtxoScannerEvent>,
48-
recovery_join_handle: JoinHandle<Result<(), WalletError>>,
4948
recovery_progress_callback: unsafe extern "C" fn(context: *mut c_void, u8, u64, u64),
5049
context: Context,
5150
) {
@@ -158,21 +157,4 @@ pub async fn recovery_event_monitoring(
158157
},
159158
}
160159
}
161-
162-
let recovery_result = recovery_join_handle.await;
163-
match recovery_result {
164-
Ok(Ok(_)) => {},
165-
Ok(Err(e)) => {
166-
unsafe {
167-
(recovery_progress_callback)(context.0, RecoveryEvent::RecoveryFailed as u8, 0u64, 1u64);
168-
}
169-
error!(target: LOG_TARGET, "Recovery error: {:?}", e);
170-
},
171-
Err(e) => {
172-
unsafe {
173-
(recovery_progress_callback)(context.0, RecoveryEvent::RecoveryFailed as u8, 1u64, 0u64);
174-
}
175-
error!(target: LOG_TARGET, "Recovery error: {}", e);
176-
},
177-
}
178160
}

base_layer/wallet_ffi/wallet.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4411,7 +4411,6 @@ bool wallet_is_recovery_in_progress(struct TariWallet *wallet,
44114411
*
44124412
* ## Arguments
44134413
* `wallet` - The TariWallet pointer.
4414-
* `base_node_public_keys` - An optional TariPublicKeys pointer of the Base Nodes the recovery process must use
44154414
* `recovery_progress_callback` - The callback function pointer that will be used to asynchronously communicate
44164415
* progress to the client. The first argument of the callback is an event enum encoded as a u8 as follows:
44174416
* ```
@@ -4449,9 +4448,6 @@ bool wallet_is_recovery_in_progress(struct TariWallet *wallet,
44494448
* - If a unrecoverable error occurs the `RecoveryFailed` event will be returned and the client will need to start
44504449
* a new process.
44514450
*
4452-
* `recovered_output_message` - A string that will be used as the message for any recovered outputs. If Null the
4453-
* default message will be used
4454-
*
44554451
* `error_out` - Pointer to an int which will be modified to an error code should one occur, may not be null. Functions
44564452
* as an out parameter.
44574453
*
@@ -4464,12 +4460,10 @@ bool wallet_is_recovery_in_progress(struct TariWallet *wallet,
44644460
* None
44654461
*/
44664462
bool wallet_start_recovery(struct TariWallet *wallet,
4467-
const char *http_base_node,
44684463
void (*recovery_progress_callback)(void *context,
44694464
uint8_t,
44704465
uint64_t,
44714466
uint64_t),
4472-
const char *recovered_output_message,
44734467
int *error_out);
44744468

44754469
/**

docs/guide/ffi_overview.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -360,7 +360,6 @@ uint64_t wallet_start_txo_validation(
360360
```c
361361
bool wallet_start_recovery(
362362
TariWallet* wallet,
363-
TariPublicKey* base_node_public_key,
364363
void (*callback_recovery_progress)(uint8_t, uint64_t, uint64_t),
365364
int* error_out
366365
);

0 commit comments

Comments
 (0)