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.
This commit is contained in:
jp1ac4 2024-02-07 12:29:22 +00:00 committed by Antoine Poinsot
parent c88224ca71
commit cc5e396ace
No known key found for this signature in database
GPG Key ID: E13FC145CD3F4304
2 changed files with 42 additions and 6 deletions

View File

@ -262,7 +262,7 @@ impl DaemonControl {
addr_info: &Option<AddrInfo>,
) {
if let Some(AddrInfo { index, is_change }) = addr_info {
if *is_change && db_conn.change_index() < *index {
if *is_change && db_conn.change_index() <= *index {
let next_index = index
.increment()
.expect("Must not get into hardened territory");
@ -1760,9 +1760,46 @@ mod tests {
panic!("expect successful spend creation")
};
let tx_manual = psbt.unsigned_tx;
// Check that manual and auto selection give same outputs (including change).
assert_eq!(tx_auto.output, tx_manual.output);
// Check that manual and auto selection give same outputs (except change address).
assert_ne!(tx_auto.output, tx_manual.output);
assert_eq!(tx_auto.output.len(), tx_manual.output.len());
assert_eq!(tx_auto.output[0], tx_manual.output[0]);
assert_eq!(tx_auto.output[1].value, tx_manual.output[1].value);
assert_ne!(
tx_auto.output[1].script_pubkey,
tx_manual.output[1].script_pubkey
);
// Check inputs are also the same. Need to sort as order is not guaranteed by `create_spend`.
let mut auto_input = tx_auto.clone().input;
let mut manual_input = tx_manual.input;
auto_input.sort();
manual_input.sort();
assert_eq!(auto_input, manual_input);
// Now do the same again, but this time specifying the change address to be the same
// as for the auto spend.
let change_address = bitcoin::Address::from_script(
tx_auto.output[1].script_pubkey.as_script(),
bitcoin::Network::Bitcoin,
)
.unwrap();
let psbt = if let CreateSpendResult::Success { psbt, .. } = control
.create_spend(
&destinations,
&[confirmed_op_1, confirmed_op_2],
1,
Some(change_address.as_unchecked().clone()),
)
.unwrap()
{
psbt
} else {
panic!("expect successful spend creation")
};
let tx_manual = psbt.unsigned_tx;
// Now the outputs of each transaction are the same.
assert_eq!(tx_auto.output, tx_manual.output);
// Check again that inputs are still the same.
let mut auto_input = tx_auto.input;
let mut manual_input = tx_manual.input;
auto_input.sort();

View File

@ -423,10 +423,9 @@ def test_coin_selection(lianad, bitcoind):
# Recipient details are the same for both.
assert spend_psbt_4.tx.vout[0].nValue == psbt_manual.tx.vout[0].nValue
assert spend_psbt_4.tx.vout[0].scriptPubKey == psbt_manual.tx.vout[0].scriptPubKey
# Change details are also the same
# (change address is same as neither transaction has been broadcast)
# Change amount is the same (change address will be different).
assert spend_psbt_4.tx.vout[1].nValue == psbt_manual.tx.vout[1].nValue
assert spend_psbt_4.tx.vout[1].scriptPubKey == psbt_manual.tx.vout[1].scriptPubKey
assert spend_psbt_4.tx.vout[1].scriptPubKey != psbt_manual.tx.vout[1].scriptPubKey
def test_coin_selection_changeless(lianad, bitcoind):