From 08505b25452e61a92d5b7eb4a02c893f0d585a91 Mon Sep 17 00:00:00 2001 From: Antoine Poinsot Date: Fri, 4 Nov 2022 19:04:24 +0100 Subject: [PATCH] commands: actually use the change descriptor when creating a Spend --- src/commands/mod.rs | 5 +++-- src/commands/utils.rs | 34 ++++++++++++++++++---------------- 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/src/commands/mod.rs b/src/commands/mod.rs index da16d6c5..4c189e23 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -348,7 +348,7 @@ impl DaemonControl { let change_desc = self .config .main_descriptor - .receive_descriptor() + .change_descriptor() .derive(db_conn.change_index(), &self.secp); db_conn.increment_change_index(&self.secp); let mut change_txo = bitcoin::TxOut { @@ -451,7 +451,8 @@ impl DaemonControl { .list_spend() .into_iter() .map(|psbt| { - let change_index = change_index(&psbt).map(|i| i.try_into().expect("insane usize")); + let change_index = + change_index(&psbt, &mut db_conn).map(|i| i.try_into().expect("insane usize")); ListSpendEntry { psbt, change_index } }) .collect(); diff --git a/src/commands/utils.rs b/src/commands/utils.rs index 2e3a7f3d..72d5ada7 100644 --- a/src/commands/utils.rs +++ b/src/commands/utils.rs @@ -1,3 +1,5 @@ +use crate::database::DatabaseConnection; + use miniscript::bitcoin::{self, consensus, util::psbt::PartiallySignedTransaction as Psbt}; use serde::{de, Deserialize, Deserializer, Serializer}; @@ -34,21 +36,21 @@ where } // Utility to gather the index of a change output in a Psbt, if there is one. -// FIXME: this is temporary! This is based on create_spend's behaviour that reuses the -// first coin address and doesn't shuffle the outputs! -pub fn change_index(psbt: &Psbt) -> Option { - // We always set the witness UTxO in the PSBTs we create. - let first_coin_spk = match psbt.inputs[0] - .witness_utxo - .as_ref() - .map(|o| &o.script_pubkey) - { - Some(spk) => spk, - None => return None, - }; +pub fn change_index(psbt: &Psbt, db_conn: &mut Box) -> Option { + let network = db_conn.network(); - let tx = &psbt.unsigned_tx; - (0..tx.output.len()) - .rev() - .find(|&i| &tx.output[i].script_pubkey == first_coin_spk) + for (i, txo) in psbt.unsigned_tx.output.iter().enumerate() { + // Small optimization. TODO: adapt once we have Taproot support. + if !txo.script_pubkey.is_v0_p2wsh() { + continue; + } + + if let Ok(address) = bitcoin::Address::from_script(&txo.script_pubkey, network) { + if let Some((_, true)) = db_conn.derivation_index_by_address(&address) { + return Some(i); + } + } + } + + None }