diff --git a/subprojects/gdk_rust/gdk_common/src/network.rs b/subprojects/gdk_rust/gdk_common/src/network.rs index 5ff30b890..42ea2a1f3 100644 --- a/subprojects/gdk_rust/gdk_common/src/network.rs +++ b/subprojects/gdk_rust/gdk_common/src/network.rs @@ -1,6 +1,8 @@ use crate::be::asset_to_bin; use crate::be::AssetId; use crate::error::Error; +use bitcoin::hashes::{sha256, Hash}; +use bitcoin::util::bip32::ExtendedPubKey; use elements::confidential::Asset; use elements::{confidential, issuance}; use serde::{Deserialize, Serialize}; @@ -26,10 +28,13 @@ pub struct Network { pub ct_exponent: Option, pub ct_min_value: Option, pub spv_enabled: Option, - pub spv_cross_validation: Option, - pub spv_cross_validation_servers: Option>, pub asset_registry_url: Option, pub asset_registry_onion_url: Option, + + // These fields must NOT be encoded as part of the wallet identifier + // to retain backwards compatibility. + pub spv_cross_validation: Option, + pub spv_cross_validation_servers: Option>, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -91,4 +96,38 @@ impl Network { .map(|s| s.to_string()) .ok_or_else(|| Error::Generic("asset regitry url not available".into())) } + + // Unique wallet identifier for the given xpub on this network. Used as part of the database + // root path, any changes will result in the creation of a new separate database. + pub fn unique_id(&self, xpub: &ExtendedPubKey) -> sha256::Hash { + // Fields used to compute the unique identifier. Must be kept with the exact same names, + // data types and ordering. + #[derive(Debug, Deserialize)] + struct Network { + name: String, + network: String, + development: bool, + liquid: bool, + mainnet: bool, + tx_explorer_url: String, + address_explorer_url: String, + tls: Option, + electrum_url: Option, + validate_domain: Option, + policy_asset: Option, + sync_interval: Option, + ct_bits: Option, + ct_exponent: Option, + ct_min_value: Option, + spv_enabled: Option, + asset_registry_url: Option, + asset_registry_onion_url: Option, + } + + let net_unique: Network = + serde_json::from_value(serde_json::to_value(self).unwrap()).unwrap(); + + let wallet_desc = format!("{}{:?}", xpub, net_unique); + sha256::Hash::hash(wallet_desc.as_bytes()) + } } diff --git a/subprojects/gdk_rust/gdk_electrum/src/lib.rs b/subprojects/gdk_rust/gdk_electrum/src/lib.rs index 8aeeb759b..233f3f7d4 100644 --- a/subprojects/gdk_rust/gdk_electrum/src/lib.rs +++ b/subprojects/gdk_rust/gdk_electrum/src/lib.rs @@ -372,8 +372,7 @@ impl Session for ElectrumSession { let xprv = xprv.derive_priv(&secp, &path)?; let xpub = ExtendedPubKey::from_private(&secp, &xprv); - let wallet_desc = format!("{}{:?}", xpub, self.network); - let wallet_id = hex::encode(sha256::Hash::hash(wallet_desc.as_bytes())); + let wallet_id = self.network.unique_id(&xpub); let sync_interval = self.network.sync_interval.unwrap_or(7); let master_blinding = if self.network.liquid { @@ -386,7 +385,7 @@ impl Session for ElectrumSession { if !path.exists() { std::fs::create_dir_all(&path)?; } - path.push(wallet_id); + path.push(hex::encode(wallet_id)); info!("Store root path: {:?}", path); let store = match self.get_wallet() { Ok(wallet) => wallet.store.clone(),