Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rescan wallet when restoring from mnemonic #4041

Merged
merged 2 commits into from
Nov 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions crates/mockcore/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -321,11 +321,16 @@ impl Handle {
}

pub fn descriptors(&self) -> Vec<String> {
self.state().descriptors.clone()
self
.state()
.descriptors
.iter()
.map(|(descriptor, _timestamp)| descriptor.clone())
.collect()
}

pub fn import_descriptor(&self, desc: String) {
self.state().descriptors.push(desc);
self.state().descriptors.push((desc, Timestamp::Now));
}

pub fn lock(&self, output: OutPoint) {
Expand Down
13 changes: 7 additions & 6 deletions crates/mockcore/src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -803,10 +803,11 @@ impl Api for Server {
&self,
req: Vec<ImportDescriptors>,
) -> Result<Vec<ImportMultiResult>, jsonrpc_core::Error> {
self
.state()
.descriptors
.extend(req.into_iter().map(|params| params.descriptor));
self.state().descriptors.extend(
req
.into_iter()
.map(|params| (params.descriptor, params.timestamp)),
);

Ok(vec![ImportMultiResult {
success: true,
Expand Down Expand Up @@ -901,9 +902,9 @@ impl Api for Server {
.state()
.descriptors
.iter()
.map(|desc| Descriptor {
.map(|(desc, timestamp)| Descriptor {
desc: desc.to_string(),
timestamp: Timestamp::Now,
timestamp: *timestamp,
active: true,
internal: None,
range: None,
Expand Down
2 changes: 1 addition & 1 deletion crates/mockcore/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use {
#[derive(Debug)]
pub struct State {
pub blocks: BTreeMap<BlockHash, Block>,
pub descriptors: Vec<String>,
pub descriptors: Vec<(String, bitcoincore_rpc::json::Timestamp)>,
pub fail_lock_unspent: bool,
pub hashes: Vec<BlockHash>,
pub loaded_wallets: BTreeSet<String>,
Expand Down
7 changes: 6 additions & 1 deletion src/subcommand/wallet/create.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,12 @@ impl Create {

let mnemonic = Mnemonic::from_entropy(&entropy)?;

Wallet::initialize(name, settings, mnemonic.to_seed(&self.passphrase))?;
Wallet::initialize(
name,
settings,
mnemonic.to_seed(&self.passphrase),
bitcoincore_rpc::json::Timestamp::Now,
)?;

Ok(Some(Box::new(Output {
mnemonic,
Expand Down
1 change: 1 addition & 0 deletions src/subcommand/wallet/restore.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ impl Restore {
name,
settings,
mnemonic.to_seed(self.passphrase.unwrap_or_default()),
bitcoincore_rpc::json::Timestamp::Time(0),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we allow setting the timestamp for mnemonic restoration?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should, but this PR is an improvement, so I'd like to merge it right away and create a new issue. There are potentially considerations like should the user be able to set a date instead of a unix timestamp, etc.

)?;
}
}
Expand Down
13 changes: 10 additions & 3 deletions src/wallet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use {
bip32::{ChildNumber, DerivationPath, Fingerprint, Xpriv},
psbt::Psbt,
},
bitcoincore_rpc::bitcoincore_rpc_json::{ImportDescriptors, Timestamp},
bitcoincore_rpc::json::ImportDescriptors,
entry::{EtchingEntry, EtchingEntryValue},
fee_rate::FeeRate,
index::entry::Entry,
Expand Down Expand Up @@ -495,7 +495,12 @@ impl Wallet {
Ok(())
}

pub(crate) fn initialize(name: String, settings: &Settings, seed: [u8; 64]) -> Result {
pub(crate) fn initialize(
name: String,
settings: &Settings,
seed: [u8; 64],
timestamp: bitcoincore_rpc::json::Timestamp,
) -> Result {
Self::check_version(settings.bitcoin_rpc_client(None)?)?.create_wallet(
&name,
None,
Expand Down Expand Up @@ -529,6 +534,7 @@ impl Wallet {
(fingerprint, derivation_path.clone()),
derived_private_key,
change,
timestamp,
)?;
}

Expand All @@ -542,6 +548,7 @@ impl Wallet {
origin: (Fingerprint, DerivationPath),
derived_private_key: Xpriv,
change: bool,
timestamp: bitcoincore_rpc::json::Timestamp,
) -> Result {
let secret_key = DescriptorSecretKey::XPrv(DescriptorXKey {
origin: Some(origin),
Expand All @@ -563,7 +570,7 @@ impl Wallet {
.bitcoin_rpc_client(Some(name.clone()))?
.import_descriptors(ImportDescriptors {
descriptor: descriptor.to_string_with_secret(&key_map),
timestamp: Timestamp::Now,
timestamp,
active: Some(true),
range: None,
next_index: None,
Expand Down
28 changes: 28 additions & 0 deletions tests/wallet/restore.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,24 @@ fn restore_generates_same_descriptors() {
let (mnemonic, descriptors) = {
let core = mockcore::spawn();

let ord = TestServer::spawn(&core);

let create::Output { mnemonic, .. } = CommandBuilder::new("wallet create")
.core(&core)
.run_and_deserialize_output();

let output = CommandBuilder::new("wallet dump")
.core(&core)
.ord(&ord)
.stderr_regex(".*THIS STRING CONTAINS YOUR PRIVATE KEYS.*")
.run_and_deserialize_output::<ListDescriptorsResult>();

// new descriptors are created with timestamp `now`
assert!(output
.descriptors
.iter()
.all(|descriptor| descriptor.timestamp == bitcoincore_rpc::json::Timestamp::Now));

(mnemonic, core.descriptors())
};

Expand All @@ -19,6 +33,20 @@ fn restore_generates_same_descriptors() {
.core(&core)
.run_and_extract_stdout();

let ord = TestServer::spawn(&core);

let output = CommandBuilder::new("wallet dump")
.core(&core)
.ord(&ord)
.stderr_regex(".*THIS STRING CONTAINS YOUR PRIVATE KEYS.*")
.run_and_deserialize_output::<ListDescriptorsResult>();

// restored descriptors are created with timestamp `0`
assert!(output
.descriptors
.iter()
.all(|descriptor| descriptor.timestamp == bitcoincore_rpc::json::Timestamp::Time(0)));

assert_eq!(core.descriptors(), descriptors);
}

Expand Down
Loading