Skip to content

Commit c28d618

Browse files
committed
commands: increment change index on each use
This is a fix to ensure the change index in the database is incremented if a new spend is created with a change address derived from the current index, regardless of whether this new spend is broadcast or not.
1 parent 1b68922 commit c28d618

File tree

2 files changed

+41
-3
lines changed

2 files changed

+41
-3
lines changed

src/commands/mod.rs

+40-3
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@ impl DaemonControl {
261261
addr_info: &Option<AddrInfo>,
262262
) {
263263
if let Some(AddrInfo { index, is_change }) = addr_info {
264-
if *is_change && db_conn.change_index() < *index {
264+
if *is_change && db_conn.change_index() <= *index {
265265
let next_index = index
266266
.increment()
267267
.expect("Must not get into hardened territory");
@@ -1699,9 +1699,46 @@ mod tests {
16991699
panic!("expect successful spend creation")
17001700
};
17011701
let tx_manual = psbt.unsigned_tx;
1702-
// Check that manual and auto selection give same outputs (including change).
1703-
assert_eq!(tx_auto.output, tx_manual.output);
1702+
// Check that manual and auto selection give same outputs (except change address).
1703+
assert_ne!(tx_auto.output, tx_manual.output);
1704+
assert_eq!(tx_auto.output.len(), tx_manual.output.len());
1705+
assert_eq!(tx_auto.output[0], tx_manual.output[0]);
1706+
assert_eq!(tx_auto.output[1].value, tx_manual.output[1].value);
1707+
assert_ne!(
1708+
tx_auto.output[1].script_pubkey,
1709+
tx_manual.output[1].script_pubkey
1710+
);
17041711
// Check inputs are also the same. Need to sort as order is not guaranteed by `create_spend`.
1712+
let mut auto_input = tx_auto.clone().input;
1713+
let mut manual_input = tx_manual.input;
1714+
auto_input.sort();
1715+
manual_input.sort();
1716+
assert_eq!(auto_input, manual_input);
1717+
1718+
// Now do the same again, but this time specifying the change address to be the same
1719+
// as for the auto spend.
1720+
let change_address = bitcoin::Address::from_script(
1721+
tx_auto.output[1].script_pubkey.as_script(),
1722+
bitcoin::Network::Bitcoin,
1723+
)
1724+
.unwrap();
1725+
let psbt = if let CreateSpendResult::Success { psbt, .. } = control
1726+
.create_spend(
1727+
&destinations,
1728+
&[confirmed_op_1, confirmed_op_2],
1729+
1,
1730+
Some(change_address.as_unchecked().clone()),
1731+
)
1732+
.unwrap()
1733+
{
1734+
psbt
1735+
} else {
1736+
panic!("expect successful spend creation")
1737+
};
1738+
let tx_manual = psbt.unsigned_tx;
1739+
// Now the outputs of each transaction are the same.
1740+
assert_eq!(tx_auto.output, tx_manual.output);
1741+
// Check again that inputs are still the same.
17051742
let mut auto_input = tx_auto.input;
17061743
let mut manual_input = tx_manual.input;
17071744
auto_input.sort();

tests/test_spend.py

+1
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,7 @@ def test_coin_selection(lianad, bitcoind):
327327
assert auto_psbt.tx.vout[0].scriptPubKey == manual_psbt.tx.vout[0].scriptPubKey
328328
# Change amount is the same (change address will be different).
329329
assert auto_psbt.tx.vout[1].nValue == manual_psbt.tx.vout[1].nValue
330+
assert auto_psbt.tx.vout[1].scriptPubKey != manual_psbt.tx.vout[1].scriptPubKey
330331

331332

332333
def test_coin_selection_changeless(lianad, bitcoind):

0 commit comments

Comments
 (0)