Skip to content
This repository was archived by the owner on Feb 3, 2025. It is now read-only.

Commit 5bd275c

Browse files
committed
Fedimint resync
1 parent 07cc2df commit 5bd275c

File tree

8 files changed

+496
-71
lines changed

8 files changed

+496
-71
lines changed

Cargo.lock

Lines changed: 306 additions & 50 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,11 @@ lightning-background-processor = { git = 'https://github.com/MutinyWallet/rust-l
2222
lightning-transaction-sync = { git = 'https://github.com/MutinyWallet/rust-lightning.git', rev = "e660e068f6f93b13dc782b2d607795716b48ed15" }
2323
lightning-net-tokio = { git = 'https://github.com/MutinyWallet/rust-lightning.git', rev = "e660e068f6f93b13dc782b2d607795716b48ed15" }
2424

25-
fedimint-client = { git = 'https://github.com/MutinyWallet/fedimint.git', rev = "450d9f6d3b6252ad3d80f2e96717722cbb6dd9cf" }
26-
fedimint-core = { git = 'https://github.com/MutinyWallet/fedimint.git', rev = "450d9f6d3b6252ad3d80f2e96717722cbb6dd9cf" }
27-
fedimint-wallet-client = { git = 'https://github.com/MutinyWallet/fedimint.git', rev = "450d9f6d3b6252ad3d80f2e96717722cbb6dd9cf" }
28-
fedimint-mint-client = { git = 'https://github.com/MutinyWallet/fedimint.git', rev = "450d9f6d3b6252ad3d80f2e96717722cbb6dd9cf" }
29-
fedimint-ln-client = { git = 'https://github.com/MutinyWallet/fedimint.git', rev = "450d9f6d3b6252ad3d80f2e96717722cbb6dd9cf" }
30-
fedimint-bip39 = { git = 'https://github.com/MutinyWallet/fedimint.git', rev = "450d9f6d3b6252ad3d80f2e96717722cbb6dd9cf" }
31-
fedimint-ln-common = { git = 'https://github.com/MutinyWallet/fedimint.git', rev = "450d9f6d3b6252ad3d80f2e96717722cbb6dd9cf" }
32-
fedimint-tbs = { git = 'https://github.com/MutinyWallet/fedimint.git', rev = "450d9f6d3b6252ad3d80f2e96717722cbb6dd9cf" }
25+
fedimint-client = { git = 'https://github.com/MutinyWallet/fedimint.git', rev = "ae2503ed4e9fb8d80dd34271455bf3b31c4fe139" }
26+
fedimint-core = { git = 'https://github.com/MutinyWallet/fedimint.git', rev = "ae2503ed4e9fb8d80dd34271455bf3b31c4fe139" }
27+
fedimint-wallet-client = { git = 'https://github.com/MutinyWallet/fedimint.git', rev = "ae2503ed4e9fb8d80dd34271455bf3b31c4fe139" }
28+
fedimint-mint-client = { git = 'https://github.com/MutinyWallet/fedimint.git', rev = "ae2503ed4e9fb8d80dd34271455bf3b31c4fe139" }
29+
fedimint-ln-client = { git = 'https://github.com/MutinyWallet/fedimint.git', rev = "ae2503ed4e9fb8d80dd34271455bf3b31c4fe139" }
30+
fedimint-bip39 = { git = 'https://github.com/MutinyWallet/fedimint.git', rev = "ae2503ed4e9fb8d80dd34271455bf3b31c4fe139" }
31+
fedimint-ln-common = { git = 'https://github.com/MutinyWallet/fedimint.git', rev = "ae2503ed4e9fb8d80dd34271455bf3b31c4fe139" }
32+
fedimint-tbs = { git = 'https://github.com/MutinyWallet/fedimint.git', rev = "ae2503ed4e9fb8d80dd34271455bf3b31c4fe139" }

mutiny-core/Cargo.toml

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -50,14 +50,14 @@ hex-conservative = "0.1.1"
5050
async-lock = "3.2.0"
5151
bitcoin-waila = "0.5.0"
5252

53-
fedimint-client = "0.3.0"
54-
fedimint-core = "0.3.0"
55-
fedimint-wallet-client = "0.3.0"
56-
fedimint-mint-client = "0.3.0"
57-
fedimint-ln-client = "0.3.0"
58-
fedimint-bip39 = "0.3.0"
59-
fedimint-ln-common = "0.3.0"
60-
fedimint-tbs = "0.3.0"
53+
fedimint-client = "0.3.2"
54+
fedimint-core = "0.3.2"
55+
fedimint-wallet-client = "0.3.2"
56+
fedimint-mint-client = "0.3.2"
57+
fedimint-ln-client = "0.3.2"
58+
fedimint-bip39 = "0.3.2"
59+
fedimint-ln-common = "0.3.2"
60+
fedimint-tbs = "0.3.2"
6161
moksha-core = "0.2.1"
6262

6363
base64 = "0.13.0"

mutiny-core/src/federation.rs

Lines changed: 109 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ use fedimint_client::{
3838
};
3939
use fedimint_core::bitcoin_migration::bitcoin30_to_bitcoin29_address;
4040
use fedimint_core::config::ClientConfig;
41+
use fedimint_core::core::LEGACY_HARDCODED_INSTANCE_ID_MINT;
4142
use fedimint_core::{
4243
api::InviteCode,
4344
config::FederationId,
@@ -143,6 +144,13 @@ impl From<LnPayState> for HTLCStatus {
143144
}
144145
}
145146

147+
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
148+
pub struct ResyncProgress {
149+
pub total: u32,
150+
pub complete: u32,
151+
pub done: bool,
152+
}
153+
146154
// This is the FederationStorage object saved to the DB
147155
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
148156
pub struct FederationStorage {
@@ -262,6 +270,7 @@ impl<S: MutinyStorage> FederationClient<S> {
262270
network: Network,
263271
stop: Arc<AtomicBool>,
264272
logger: Arc<MutinyLogger>,
273+
safe_mode: bool,
265274
) -> Result<Self, MutinyError> {
266275
log_info!(logger, "initializing a new federation client: {uuid}");
267276

@@ -282,6 +291,10 @@ impl<S: MutinyStorage> FederationClient<S> {
282291

283292
client_builder.with_primary_module(1);
284293

294+
if safe_mode {
295+
client_builder.stopped();
296+
}
297+
285298
log_trace!(logger, "Building fedimint client db");
286299
let secret = create_federation_secret(xprivkey, network)?;
287300

@@ -349,7 +362,7 @@ impl<S: MutinyStorage> FederationClient<S> {
349362
let mut gateway_lock = gateway_clone.write().await;
350363
let lightning_module = client_clone.get_first_module::<LightningClientModule>();
351364

352-
match lightning_module.update_gateway_cache(true).await {
365+
match lightning_module.update_gateway_cache().await {
353366
Ok(_) => {
354367
log_trace!(logger_clone, "Updated lightning gateway cache");
355368
}
@@ -482,6 +495,101 @@ impl<S: MutinyStorage> FederationClient<S> {
482495
);
483496
}
484497

498+
/// Starts a resync of the federation
499+
pub async fn start_resync(
500+
federation_code: InviteCode,
501+
xprivkey: ExtendedPrivKey,
502+
storage: S,
503+
network: Network,
504+
logger: Arc<MutinyLogger>,
505+
) -> Result<(), MutinyError> {
506+
let federation_id = federation_code.federation_id();
507+
508+
let storage_key = format!("resync_state/{federation_id}");
509+
storage.set_data(storage_key.clone(), ResyncProgress::default(), None)?;
510+
511+
log_trace!(logger, "Building fedimint client db");
512+
let fedimint_storage =
513+
FedimintStorage::new(storage.clone(), federation_id.to_string(), logger.clone())
514+
.await?;
515+
let db = fedimint_storage.clone().into();
516+
517+
let mut client_builder = fedimint_client::Client::builder(db);
518+
client_builder.with_module(WalletClientInit(None));
519+
client_builder.with_module(MintClientInit);
520+
client_builder.with_module(LightningClientInit);
521+
522+
client_builder.with_primary_module(1);
523+
524+
log_trace!(logger, "Building fedimint client db");
525+
let secret = create_federation_secret(xprivkey, network)?;
526+
527+
// need to use a fresh database for resync
528+
fedimint_storage.delete_store().await?;
529+
530+
let config = ClientConfig::download_from_invite_code(&federation_code)
531+
.await
532+
.map_err(|e| {
533+
log_error!(logger, "Could not download federation info: {e}");
534+
e
535+
})?;
536+
537+
let fedimint_client = client_builder
538+
.recover(
539+
get_default_client_secret(&secret, &federation_id),
540+
config,
541+
None,
542+
)
543+
.await
544+
.map_err(|e| {
545+
log_error!(logger, "Could not open federation client: {e}");
546+
MutinyError::FederationConnectionFailed
547+
})?;
548+
let fedimint_client = Arc::new(fedimint_client);
549+
550+
log_debug!(logger, "Built fedimint resync client");
551+
552+
spawn(async move {
553+
let mut stream = fedimint_client.subscribe_to_recovery_progress();
554+
555+
while let Some((id, progress)) = stream.next().await {
556+
// only can rescan mint client, don't care about sync progress of others
557+
if id != LEGACY_HARDCODED_INSTANCE_ID_MINT || progress.is_none() {
558+
continue;
559+
}
560+
561+
log_debug!(logger, "Got recovery progress: {progress:?}");
562+
563+
// save progress state to storage so frontend can show progress
564+
if let Err(e) = storage.set_data(
565+
storage_key.clone(),
566+
ResyncProgress {
567+
total: progress.total,
568+
complete: progress.complete,
569+
done: progress.is_done(),
570+
},
571+
None,
572+
) {
573+
log_error!(logger, "Error saving resync progress: {e}");
574+
}
575+
}
576+
577+
log_debug!(logger, "No more progress, waiting for recoveries");
578+
579+
// wait for all recoveries to complete just to be sure
580+
if let Err(e) = fedimint_client.wait_for_all_recoveries().await {
581+
log_error!(logger, "Error waiting for recoveries: {e}");
582+
}
583+
584+
// can now delete the progress state
585+
if let Err(e) = storage.delete(&[storage_key]) {
586+
log_error!(logger, "Error deleting resync progress state: {e}");
587+
}
588+
});
589+
590+
Ok(())
591+
}
592+
485593
pub(crate) async fn gateway_fee(&self) -> Result<GatewayFees, MutinyError> {
486594
let gateway = self.gateway.read().await;
487595
Ok(gateway.as_ref().map(|x| x.fees.into()).unwrap_or_default())

mutiny-core/src/lib.rs

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ pub mod vss;
4343
#[cfg(test)]
4444
mod test_utils;
4545

46-
use crate::federation::get_federation_identity;
46+
use crate::federation::{get_federation_identity, ResyncProgress};
4747
pub use crate::gossip::{GOSSIP_SYNC_TIME_KEY, NETWORK_GRAPH_KEY, PROB_SCORER_KEY};
4848
pub use crate::keymanager::generate_seed;
4949
pub use crate::ldkstorage::{CHANNEL_CLOSURE_PREFIX, CHANNEL_MANAGER_KEY, MONITORS_PREFIX_KEY};
@@ -1004,6 +1004,7 @@ impl<S: MutinyStorage> MutinyWalletBuilder<S> {
10041004
esplora.clone(),
10051005
stop.clone(),
10061006
&logger,
1007+
self.safe_mode,
10071008
)
10081009
.await?;
10091010
log_debug!(
@@ -2982,6 +2983,7 @@ impl<S: MutinyStorage> MutinyWallet<S> {
29822983
self.esplora.clone(),
29832984
federation_code,
29842985
self.stop.clone(),
2986+
self.safe_mode,
29852987
)
29862988
.await;
29872989
log_trace!(self.logger, "finished calling new_federation");
@@ -3111,6 +3113,43 @@ impl<S: MutinyStorage> MutinyWallet<S> {
31113113
Ok(FederationBalances { balances })
31123114
}
31133115

3116+
pub async fn resync_federation(&self, federation_id: FederationId) -> Result<(), MutinyError> {
3117+
if !self.safe_mode {
3118+
// cannot safely run unless in safe mode
3119+
return Err(MutinyError::AlreadyRunning);
3120+
}
3121+
3122+
let invite_code = self
3123+
.federation_storage
3124+
.read()
3125+
.await
3126+
.federations
3127+
.values()
3128+
.find(|f| f.federation_code.federation_id() == federation_id)
3129+
.ok_or(MutinyError::NotFound)?
3130+
.federation_code
3131+
.clone();
3132+
3133+
FederationClient::start_resync(
3134+
invite_code,
3135+
self.xprivkey,
3136+
self.storage.clone(),
3137+
self.network,
3138+
self.logger.clone(),
3139+
)
3140+
.await?;
3141+
3142+
Ok(())
3143+
}
3144+
3145+
pub fn get_federation_resync_progress(
3146+
&self,
3147+
federation_id: FederationId,
3148+
) -> Result<Option<ResyncProgress>, MutinyError> {
3149+
let storage_key = format!("resync_state/{federation_id}");
3150+
self.storage.get_data(storage_key)
3151+
}
3152+
31143153
/// Starts a background process that will check pending fedimint operations
31153154
pub(crate) async fn start_fedimint_background_checker(&self) {
31163155
log_trace!(self.logger, "calling start_fedimint_background_checker");
@@ -3734,6 +3773,7 @@ async fn create_federations<S: MutinyStorage>(
37343773
esplora: Arc<AsyncClient>,
37353774
stop: Arc<AtomicBool>,
37363775
logger: &Arc<MutinyLogger>,
3776+
safe_mode: bool,
37373777
) -> Result<Arc<RwLock<HashMap<FederationId, Arc<FederationClient<S>>>>>, MutinyError> {
37383778
let mut federation_map = HashMap::with_capacity(federation_storage.federations.len());
37393779
for (uuid, federation_index) in federation_storage.federations {
@@ -3746,6 +3786,7 @@ async fn create_federations<S: MutinyStorage>(
37463786
c.network,
37473787
stop.clone(),
37483788
logger.clone(),
3789+
safe_mode,
37493790
)
37503791
.await?;
37513792

@@ -3770,6 +3811,7 @@ pub(crate) async fn create_new_federation<S: MutinyStorage>(
37703811
esplora: Arc<AsyncClient>,
37713812
federation_code: InviteCode,
37723813
stop: Arc<AtomicBool>,
3814+
safe_mode: bool,
37733815
) -> Result<FederationIdentity, MutinyError> {
37743816
// Begin with a mutex lock so that nothing else can
37753817
// save or alter the federation list while it is about to
@@ -3801,6 +3843,7 @@ pub(crate) async fn create_new_federation<S: MutinyStorage>(
38013843
network,
38023844
stop.clone(),
38033845
logger.clone(),
3846+
safe_mode,
38043847
)
38053848
.await?;
38063849

mutiny-wasm/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ urlencoding = "2.1.2"
4343
once_cell = "1.18.0"
4444
hex-conservative = "0.1.1"
4545
payjoin = { version = "0.13.0", features = ["send", "base64"] }
46-
fedimint-core = "0.3.0"
46+
fedimint-core = "0.3.2"
4747
moksha-core = "0.2.1"
4848

4949
bitcoin-waila = "0.5.0"

mutiny-wasm/src/indexed_db.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use bip39::Mnemonic;
44
use futures::lock::Mutex;
55
use gloo_utils::format::JsValueSerdeExt;
66
use lightning::util::logger::Logger;
7-
use lightning::{log_debug, log_error, log_trace};
7+
use lightning::{log_debug, log_error, log_info, log_trace};
88
use log::error;
99
use mutiny_core::blindauth::TokenStorage;
1010
use mutiny_core::logging::LOGGING_KEY;
@@ -346,11 +346,12 @@ impl IndexedDbStorage {
346346

347347
match vss {
348348
None => {
349+
log_info!(logger, "No VSS configured");
349350
let final_map = map.memory.read().unwrap();
350351
Ok(final_map.clone())
351352
}
352353
Some(vss) => {
353-
log_trace!(logger, "Reading from vss");
354+
log_info!(logger, "Reading from vss");
354355
let start = instant::Instant::now();
355356
let keys = vss.list_key_versions(None).await?;
356357
let mut futs = Vec::with_capacity(keys.len());

mutiny-wasm/src/lib.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2103,6 +2103,23 @@ impl MutinyWallet {
21032103
Ok(())
21042104
}
21052105

2106+
pub async fn resync_federation(&self, federation_id: String) -> Result<(), MutinyJsError> {
2107+
let federation_id = FederationId::from_str(&federation_id)
2108+
.map_err(|_| MutinyJsError::InvalidArgumentsError)?;
2109+
self.inner.resync_federation(federation_id).await?;
2110+
Ok(())
2111+
}
2112+
2113+
pub fn get_federation_resync_progress(
2114+
&self,
2115+
federation_id: String,
2116+
) -> Result<JsValue, MutinyJsError> {
2117+
let federation_id = FederationId::from_str(&federation_id)
2118+
.map_err(|_| MutinyJsError::InvalidArgumentsError)?;
2119+
let res = self.inner.get_federation_resync_progress(federation_id)?;
2120+
Ok(JsValue::from_serde(&res)?)
2121+
}
2122+
21062123
/// Restore's the mnemonic after deleting the previous state.
21072124
///
21082125
/// Backup the state beforehand. Does not restore lightning data.

0 commit comments

Comments
 (0)