Skip to content

Commit

Permalink
rbf: modify is_cancel candidates logic
Browse files Browse the repository at this point in the history
  • Loading branch information
jp1ac4 committed Nov 23, 2023
1 parent a0586df commit 15da167
Showing 1 changed file with 40 additions and 8 deletions.
48 changes: 40 additions & 8 deletions src/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1036,17 +1036,28 @@ impl DaemonControl {
}
};
}
// We take all previous inputs as mandatory candidates and, if not self-send, include
// confirmed coins as optional.
// TODO: For `is_cancel`, shall we include just one previous input?
let candidate_coins: Vec<CandidateCoin> = prev_coins
// If `!is_cancel`, we take the previous coins as mandatory candidates and add confirmed coins as optional.
// Otherwise, we take the previous coins as optional candidates and let coin selection find the
// best solution that includes at least one of these. If there are insufficient funds to create the replacement
// transaction in this way, then we set candidates in the same way as for the `!is_cancel` case.
let mut candidate_coins: Vec<CandidateCoin> = prev_coins
.values()
.chain(db_conn.coins(&[CoinStatus::Confirmed], &[]).values())
.map(|c| CandidateCoin {
coin: *c,
must_select: prev_coins.contains_key(&c.outpoint),
must_select: !is_cancel,
})
.collect();
if !is_cancel {
candidate_coins.extend(
db_conn
.coins(&[CoinStatus::Confirmed], &[])
.into_values()
.map(|c| CandidateCoin {
coin: c,
must_select: false,
}),
);
}
// Try with increasing feerate until fee paid by replacement transaction is high enough.
// Replacement fee must be at least:
// sum of fees paid by original transactions + incremental feerate * replacement size.
Expand All @@ -1057,13 +1068,34 @@ impl DaemonControl {
// will ensure that the PSBT meets the required replacement fee and the loop will exit.
let min_fee = mempool_entry.fees.descendant.to_sat() + rbf_vsize;
println!("trying min_fee of {}", min_fee);
let rbf_psbt = self.create_rbf_spend(
let rbf_psbt = match self.create_rbf_spend(
&destinations,
&candidate_coins,
feerate_vb,
min_fee,
change_index,
)?;
) {
Ok(psbt) => psbt,
// If we get a coin selection error due to insufficient funds and we want to cancel the
// transaction, then set all previous coins as mandatory and add confirmed coins as
// optional, unless we have already done this.
Err(CommandError::CoinSelectionError(_))
if is_cancel && candidate_coins.iter().all(|c| !c.must_select) =>
{
candidate_coins = prev_coins
.values()
.chain(db_conn.coins(&[CoinStatus::Confirmed], &[]).values())
.map(|c| CandidateCoin {
coin: *c,
must_select: prev_coins.contains_key(&c.outpoint),
})
.collect();
continue;
}
Err(e) => {
return Err(e);
}
};
rbf_vsize = {
// TODO: Make this a function (can be used also in `sanity_check`).
let witness_factor: u64 =
Expand Down

0 comments on commit 15da167

Please sign in to comment.