diff --git a/token-core/tcx/src/migration.rs b/token-core/tcx/src/migration.rs index 39a1c0cd..b80872d2 100644 --- a/token-core/tcx/src/migration.rs +++ b/token-core/tcx/src/migration.rs @@ -3,7 +3,7 @@ use crate::api::{ MigrateKeystoreParam, MigrateKeystoreResult, ScanLegacyKeystoresResult, }; use crate::error_handling::Result; -use crate::filemanager::{cache_keystore, KEYSTORE_MAP}; +use crate::filemanager::{cache_keystore, KEYSTORE_MAP, WALLET_FILE_DIR}; use crate::filemanager::{flush_keystore, LEGACY_WALLET_FILE_DIR}; use crate::handler::{encode_message, encrypt_xpub}; use anyhow::anyhow; @@ -138,7 +138,11 @@ pub(crate) fn migrate_keystore(data: &[u8]) -> Result> { .collect(); if existed_ks.len() > 0 { is_existed = true; - existed_id = existed_ks[0].id().to_string(); + existed_id = existed_ks + .iter() + .find(|ks| existed_keystore_file(&ks.id())) + .expect("At least one keystore file should be existed") + .id(); // Note: Temporary retention of the old ID, // so that users can continue to use the old ID for subsequent operations. keystore_map.insert(param.id, keystore.clone()); @@ -182,6 +186,12 @@ pub(crate) fn migrate_keystore(data: &[u8]) -> Result> { } } +pub fn existed_keystore_file(id: &str) -> bool { + let file_path = format!("{}/{}.json", WALLET_FILE_DIR.read(), id); + let path = Path::new(&file_path); + path.exists() +} + #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct LegacyAccount { diff --git a/token-core/tcx/tests/migration_test.rs b/token-core/tcx/tests/migration_test.rs index 5093e3eb..66bb46d4 100644 --- a/token-core/tcx/tests/migration_test.rs +++ b/token-core/tcx/tests/migration_test.rs @@ -76,6 +76,69 @@ pub fn test_migrate_keystores_existed() { fs::remove_dir_all("../test-data/walletsV2").unwrap(); } +#[test] +#[serial] +pub fn test_migrate_keystores_multi_times() { + let _ = fs::remove_dir_all("../test-data/walletsV2"); + init_token_core_x("../test-data"); + + let param: MigrateKeystoreParam = MigrateKeystoreParam { + id: "0a2756cd-ff70-437b-9bdb-ad46b8bb0819".to_string(), + network: "TESTNET".to_string(), + key: Some(migrate_keystore_param::Key::Password( + TEST_PASSWORD.to_string(), + )), + }; + let ret = call_api("migrate_keystore", param).unwrap(); + let result: MigrateKeystoreResult = MigrateKeystoreResult::decode(ret.as_slice()).unwrap(); + let keystore = result.keystore.unwrap(); + assert_eq!(keystore.id, "0a2756cd-ff70-437b-9bdb-ad46b8bb0819"); + assert_eq!( + keystore.identifier, + "im18MDKM8hcTykvMmhLnov9m2BaFqsdjoA7cwNg" + ); + assert_eq!( + keystore.ipfs_id, + "QmSTTidyfa4np9ak9BZP38atuzkCHy4K59oif23f4dNAGU" + ); + assert_eq!(keystore.created_at, 1703213098); + assert_eq!(keystore.source, "MNEMONIC"); + assert_eq!(keystore.name, "tcx-wallet"); + assert_eq!( + keystore.source_fingerprint, + "0x1468dba9c246fe22183c056540ab4d8b04553217" + ); + + let param: MigrateKeystoreParam = MigrateKeystoreParam { + id: "00fc0804-7cea-46d8-9e95-ed1efac65358".to_string(), + network: "TESTNET".to_string(), + key: Some(migrate_keystore_param::Key::DerivedKey( + "2d7380db28736ae5b0693340a5731e137759d32bbcc1f7988574bc5a1ffd97f3411b4edc14ea648fa17d511129e81a84d2b8a00d45bc37f4784e49b641d5c3be".to_string(), + )), + }; + let ret = call_api("migrate_keystore", param).unwrap(); + let result: MigrateKeystoreResult = MigrateKeystoreResult::decode(ret.as_slice()).unwrap(); + assert!(result.is_existed); + assert_eq!(result.existed_id, "0a2756cd-ff70-437b-9bdb-ad46b8bb0819"); + + let param: MigrateKeystoreParam = MigrateKeystoreParam { + id: "1bfddca9-84dc-4561-bbe9-844a9ff2b281".to_string(), + network: "TESTNET".to_string(), + key: Some(migrate_keystore_param::Key::DerivedKey( + "2d7380db28736ae5b0693340a5731e137759d32bbcc1f7988574bc5a1ffd97f3411b4edc14ea648fa17d511129e81a84d2b8a00d45bc37f4784e49b641d5c3be".to_string(), + )), + }; + + for _ in 1..100 { + let ret = call_api("migrate_keystore", param.clone()).unwrap(); + let result: MigrateKeystoreResult = MigrateKeystoreResult::decode(ret.as_slice()).unwrap(); + assert!(result.is_existed); + assert_eq!(result.existed_id, "0a2756cd-ff70-437b-9bdb-ad46b8bb0819"); + } + + fs::remove_dir_all("../test-data/walletsV2").unwrap(); +} + #[test] #[serial] pub fn test_migrate_keystores_existed_mainnet() { diff --git a/token-core/test-data/wallets/1bfddca9-84dc-4561-bbe9-844a9ff2b281 b/token-core/test-data/wallets/1bfddca9-84dc-4561-bbe9-844a9ff2b281 new file mode 100644 index 00000000..85a05f79 --- /dev/null +++ b/token-core/test-data/wallets/1bfddca9-84dc-4561-bbe9-844a9ff2b281 @@ -0,0 +1,39 @@ +{ + "address": "2MwN441dq8qudMvtM5eLVwC3u4zfKuGSQAB", + "imTokenMeta": { + "source": "RECOVERED_IDENTITY", + "timestamp": "1703213076.948025", + "backup": [], + "mode": "normal", + "name": "a clone of 00fc0804-7cea-46d8-9e95-ed1efac65358", + "version": "iOS-2.14.1.1742", + "passwordHint": "", + "chain": "BITCOIN", + "network": "TESTNET", + "segWit": "P2WPKH" + }, + "id": "1bfddca9-84dc-4561-bbe9-844a9ff2b281", + "encMnemonic": { + "nonce": "406c972f073ebf5b9102d262e6713408", + "encStr": "76b940d06641023f995cffde6ee9c4bc7c063a780897b5debd619aafc769b37db684eafb10dd48c3c3cbcb810952bb4455984fde5aa34a1dfb4d5ad93293c0d3f3a78124639a4530b4c2" + }, + "xpub": "tpubDCwNET9ErXmBracx3ZBfi6rXQZRjYkpitFe23FAW9M3RcCw4aveNC4SAV5yYrFDjtP3b46eFfv4VtiYP3EXoTZsbnJia2yNznExS8EEcACv", + "crypto": { + "kdfparams": { + "dklen": 32, + "r": 8, + "salt": "8fac63b4cc6d75817269a380bc8107572ecba3a8fe1ab87e46e30ab696ce2320", + "p": 1, + "n": 262144 + }, + "mac": "6daa39ee727416a135b02d6183c71624de0b7cf74fb3a3d1562488e66f308c76", + "cipher": "aes-128-ctr", + "ciphertext": "cdde8cafd9eff3f9715ef40577913e2ded3b8a9f009781d3367e4a1b02e95894c45ab6ef2658e7ef99b8437cba0f05f5c12caca60e97745b71581075f086a57afac8f626f3d2f7c94813edb6eb26b5cf8147fd32419a3abc762d71dc2be77d555cb75e983a74fa45f7b08e59ce7945", + "cipherparams": { + "iv": "a575c61a89577eea45af32df6aa4005a" + }, + "kdf": "scrypt" + }, + "version": 44, + "mnemonicPath": "m/49'/1'/0'" +}