diff --git a/modules/fedimint-mint-client/src/backup/recovery.rs b/modules/fedimint-mint-client/src/backup/recovery.rs index 0366fc5d48d..8f20f0bffc8 100644 --- a/modules/fedimint-mint-client/src/backup/recovery.rs +++ b/modules/fedimint-mint-client/src/backup/recovery.rs @@ -86,7 +86,7 @@ impl RecoveryFromHistory for MintRecovery { .get_value(&RecoveryStateKey) .await .and_then(|(state, common)| { - if let MintRecoveryState::V0(state) = state { + if let MintRecoveryState::V1(state) = state { Some((state, common)) } else { warn!(target: LOG_CLIENT_RECOVERY, "Found unknown version recovery state. Ignoring"); @@ -112,7 +112,7 @@ impl RecoveryFromHistory for MintRecovery { ) { dbtx.insert_entry( &RecoveryStateKey, - &(MintRecoveryState::V0(self.state.clone()), common.clone()), + &(MintRecoveryState::V1(self.state.clone()), common.clone()), ) .await; } @@ -266,7 +266,7 @@ impl From for BlindedMessage { #[derive(Debug, Clone, Decodable, Encodable)] pub enum MintRecoveryState { - V0(MintRecoveryStateV0), + V1(MintRecoveryStateV0), #[encodable_default] Default { variant: u64, diff --git a/modules/fedimint-mint-client/src/client_db.rs b/modules/fedimint-mint-client/src/client_db.rs index 76ddfaf876d..67fda26cf2a 100644 --- a/modules/fedimint-mint-client/src/client_db.rs +++ b/modules/fedimint-mint-client/src/client_db.rs @@ -1,5 +1,6 @@ use fedimint_client::module::init::recovery::RecoveryFromHistoryCommon; use fedimint_core::core::OperationId; +use fedimint_core::db::{DatabaseTransaction, IDatabaseTransactionOpsCoreTyped as _}; use fedimint_core::encoding::{Decodable, Encodable}; use fedimint_core::{impl_db_lookup, impl_db_record, Amount}; use fedimint_mint_common::Nonce; @@ -98,3 +99,14 @@ impl_db_lookup!( key = CancelledOOBSpendKey, query_prefix = CancelledOOBSpendKeyPrefix, ); + +pub async fn migrate_to_v1( + dbtx: &mut DatabaseTransaction<'_>, +) -> anyhow::Result, OperationId)>, Vec<(Vec, OperationId)>)>> { + // between v0 and v1, we changed the format of `MintRecoveryState`, and instead + // of migrating it, we can just delete it, so the recovery will just start + // again, ignoring any existing state from before the migration + dbtx.remove_entry(&RecoveryStateKey).await; + + Ok(None) +} diff --git a/modules/fedimint-mint-client/src/lib.rs b/modules/fedimint-mint-client/src/lib.rs index 892e57ef5de..c876afc79e7 100644 --- a/modules/fedimint-mint-client/src/lib.rs +++ b/modules/fedimint-mint-client/src/lib.rs @@ -33,7 +33,8 @@ use async_stream::{stream, try_stream}; use backup::recovery::MintRecovery; use base64::Engine as _; use bitcoin_hashes::{sha256, sha256t, Hash, HashEngine as BitcoinHashEngine}; -use client_db::{DbKeyPrefix, NoteKeyPrefix, RecoveryFinalizedKey}; +use client_db::{migrate_to_v1, DbKeyPrefix, NoteKeyPrefix, RecoveryFinalizedKey}; +use fedimint_client::db::ClientMigrationFn; use fedimint_client::module::init::{ ClientModuleInit, ClientModuleInitArgs, ClientModuleRecoverArgs, }; @@ -509,7 +510,7 @@ pub struct MintClientInit; impl ModuleInit for MintClientInit { type Common = MintCommonInit; - const DATABASE_VERSION: DatabaseVersion = DatabaseVersion(0); + const DATABASE_VERSION: DatabaseVersion = DatabaseVersion(1); async fn dump_database( &self, @@ -595,6 +596,15 @@ impl ClientModuleInit for MintClientInit { args.recover_from_history::(self, snapshot) .await } + + fn get_database_migrations(&self) -> BTreeMap { + let mut migrations: BTreeMap = BTreeMap::new(); + migrations.insert(DatabaseVersion(0), |dbtx, _, _| { + Box::pin(migrate_to_v1(dbtx)) + }); + + migrations + } } /// The `MintClientModule` is responsible for handling e-cash minting diff --git a/modules/fedimint-mint-tests/tests/tests.rs b/modules/fedimint-mint-tests/tests/tests.rs index a839ead886f..6779857dde3 100644 --- a/modules/fedimint-mint-tests/tests/tests.rs +++ b/modules/fedimint-mint-tests/tests/tests.rs @@ -387,7 +387,8 @@ mod fedimint_migration_tests { use fedimint_mint_client::backup::{EcashBackup, EcashBackupV0}; use fedimint_mint_client::client_db::{ CancelledOOBSpendKey, CancelledOOBSpendKeyPrefix, NextECashNoteIndexKey, - NextECashNoteIndexKeyPrefix, NoteKey, NoteKeyPrefix, RecoveryStateKey, + NextECashNoteIndexKeyPrefix, NoteKey, NoteKeyPrefix, RecoveryFinalizedKey, + RecoveryStateKey, }; use fedimint_mint_client::output::NoteIssuanceRequest; use fedimint_mint_client::{MintClientInit, MintClientModule, NoteIndex, SpendableNote}; @@ -522,7 +523,7 @@ mod fedimint_migration_tests { let backup = create_ecash_backup_v0(spendable_note, secret.clone()); - let mint_recovery_state = MintRecoveryState::V0(MintRecoveryStateV0::from_backup( + let mint_recovery_state = MintRecoveryState::V1(MintRecoveryStateV0::from_backup( backup, 10, tbs_pks, @@ -711,13 +712,13 @@ mod fedimint_migration_tests { fedimint_mint_client::client_db::DbKeyPrefix::RecoveryState => { let restore_state = dbtx.get_value(&RecoveryStateKey).await; ensure!( - restore_state.is_some(), - "validate_migrations was not able to read any RecoveryState" + restore_state.is_none(), + "validate_migrations expect the restore state to get deleted" ); info!("Validated RecoveryState"); } fedimint_mint_client::client_db::DbKeyPrefix::RecoveryFinalized => { - let recovery_finalized = dbtx.get_value(&RecoveryStateKey).await; + let recovery_finalized = dbtx.get_value(&RecoveryFinalizedKey).await; ensure!( recovery_finalized.is_some(), "validate_migrations was not able to read any RecoveryFinalized"