Skip to content

Commit

Permalink
Add comments and debug assertions for list_unspent_utxos
Browse files Browse the repository at this point in the history
We previously erroneously included the version byte trying to construct
a `WitnessProgram`, which was was recently fixed. Here we add some more
comments to the code explaining what went wrong, and also add a debug
assertion checking `list_unspent_utxos` retrieves at least one `Utxo`
when we see any confirmed balances.
  • Loading branch information
tnull committed Oct 28, 2024
1 parent bcea1c2 commit 3b5f00b
Showing 1 changed file with 42 additions and 10 deletions.
52 changes: 42 additions & 10 deletions src/wallet/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,16 @@ where
) -> Result<(u64, u64), Error> {
let balance = self.inner.lock().unwrap().balance();

// Make sure `list_confirmed_utxos` returns at least one `Utxo` we could use to spend/bump
// Anchors if we have any confirmed amounts.
#[cfg(debug_assertions)]
if balance.confirmed != Amount::ZERO {
debug_assert!(
self.list_confirmed_utxos().map_or(false, |v| !v.is_empty()),
"Confirmed amounts should always be available for Anchor spending"
);
}

let (total, spendable) = (
balance.total().to_sat(),
balance.trusted_spendable().to_sat().saturating_sub(total_anchor_channels_reserve_sats),
Expand Down Expand Up @@ -387,12 +397,23 @@ where
let script_pubkey = u.txout.script_pubkey;
match script_pubkey.witness_version() {
Some(version @ WitnessVersion::V0) => {
// According to the SegWit rules of [BIP 141] a witness program is defined as:
// > A scriptPubKey (or redeemScript as defined in BIP16/P2SH) that consists of
// > a 1-byte push opcode (one of OP_0,OP_1,OP_2,.. .,OP_16) followed by a direct
// > data push between 2 and 40 bytes gets a new special meaning. The value of
// > the first push is called the "version byte". The following byte vector
// > pushed is called the "witness program"."
//
// We therefore skip the first byte we just read via `witness_version` and use
// the rest (i.e., the data push) as the raw bytes to construct the
// `WitnessProgram` below.
//
// [BIP 141]: https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#witness-program
let witness_bytes = &script_pubkey.as_bytes()[2..];
let witness_program =
WitnessProgram::new(version, &script_pubkey.as_bytes()[2..]).map_err(
|e| {
log_error!(self.logger, "Failed to retrieve script payload: {}", e);
},
)?;
WitnessProgram::new(version, witness_bytes).map_err(|e| {
log_error!(self.logger, "Failed to retrieve script payload: {}", e);
})?;

let wpkh = WPubkeyHash::from_slice(&witness_program.program().as_bytes())
.map_err(|e| {
Expand All @@ -402,12 +423,23 @@ where
utxos.push(utxo);
},
Some(version @ WitnessVersion::V1) => {
// According to the SegWit rules of [BIP 141] a witness program is defined as:
// > A scriptPubKey (or redeemScript as defined in BIP16/P2SH) that consists of
// > a 1-byte push opcode (one of OP_0,OP_1,OP_2,.. .,OP_16) followed by a direct
// > data push between 2 and 40 bytes gets a new special meaning. The value of
// > the first push is called the "version byte". The following byte vector
// > pushed is called the "witness program"."
//
// We therefore skip the first byte we just read via `witness_version` and use
// the rest (i.e., the data push) as the raw bytes to construct the
// `WitnessProgram` below.
//
// [BIP 141]: https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#witness-program
let witness_bytes = &script_pubkey.as_bytes()[2..];
let witness_program =
WitnessProgram::new(version, &script_pubkey.as_bytes()[2..]).map_err(
|e| {
log_error!(self.logger, "Failed to retrieve script payload: {}", e);
},
)?;
WitnessProgram::new(version, witness_bytes).map_err(|e| {
log_error!(self.logger, "Failed to retrieve script payload: {}", e);
})?;

XOnlyPublicKey::from_slice(&witness_program.program().as_bytes()).map_err(
|e| {
Expand Down

0 comments on commit 3b5f00b

Please sign in to comment.