Skip to content

Commit 0769f7e

Browse files
author
Antoine Riard
committed
Modify HoldersCommitment's package_weight/amount to account for CPFP
A HolderCommitmentTx package may be attached a CPFP if its feerate needs a bumping and thus an accurate operation need to scope both parent and children weight. Also disable feerate computation for pre-committed feerate package as their package amounts available for feerate-reducing will be 0.
1 parent 1e68aa3 commit 0769f7e

File tree

3 files changed

+60
-11
lines changed

3 files changed

+60
-11
lines changed

lightning/src/chain/onchaintx.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -360,7 +360,7 @@ impl<ChannelSigner: Sign> OnchainTxHandler<ChannelSigner> {
360360
// didn't receive confirmation of it before, or not enough reorg-safe depth on top of it).
361361
let new_timer = Some(cached_request.get_height_timer(height));
362362
if cached_request.is_malleable() {
363-
let predicted_weight = cached_request.package_weight(&self.destination_script);
363+
let predicted_weight = cached_request.package_weight(&self.destination_script, self.holder_commitment.get_num_outputs());
364364
if let Some((output_value, new_feerate)) = cached_request.compute_package_output(predicted_weight, fee_estimator, logger) {
365365
assert!(new_feerate != 0);
366366

lightning/src/chain/package.rs

Lines changed: 38 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -288,25 +288,53 @@ impl PackageSolvingData {
288288
PackageSolvingData::RevokedHTLCOutput(ref outp) => { outp.amount },
289289
PackageSolvingData::CounterpartyOfferedHTLCOutput(ref outp) => { outp.htlc.amount_msat / 1000 },
290290
PackageSolvingData::CounterpartyReceivedHTLCOutput(ref outp) => { outp.htlc.amount_msat / 1000 },
291+
PackageSolvingData::HolderFundingOutput(ref outp) => {
292+
if let Some(ref utxo_input) = outp.utxo_input {
293+
return utxo_input.1.amount + 330; //TODO: move ANCHOR_OUTPUT_VALUE in chan_utils
294+
} else {
295+
return 0;
296+
}
297+
},
291298
// Note: Currently, amounts of holder outputs spending witnesses aren't used
292299
// as we can't malleate spending package to increase their feerate. This
293300
// should change with the remaining anchor output patchset.
294301
PackageSolvingData::HolderHTLCOutput(..) => { unreachable!() },
295-
PackageSolvingData::HolderFundingOutput(..) => { unreachable!() },
296302
};
297303
amt
298304
}
299-
fn weight(&self) -> usize {
305+
fn weight(&self, destination_script: &Script, num_commitment_outputs: usize) -> usize {
300306
let weight = match self {
301307
PackageSolvingData::RevokedOutput(ref outp) => { outp.weight as usize },
302308
PackageSolvingData::RevokedHTLCOutput(ref outp) => { outp.weight as usize },
303309
PackageSolvingData::CounterpartyOfferedHTLCOutput(..) => { WEIGHT_OFFERED_HTLC as usize },
304310
PackageSolvingData::CounterpartyReceivedHTLCOutput(..) => { WEIGHT_RECEIVED_HTLC as usize },
305-
// Note: Currently, weights of holder outputs spending witnesses aren't used
306-
// as we can't malleate spending package to increase their feerate. This
307-
// should change with the remaining anchor output patchset.
308-
PackageSolvingData::HolderHTLCOutput(..) => { unreachable!() },
309-
PackageSolvingData::HolderFundingOutput(..) => { unreachable!() },
311+
PackageSolvingData::HolderFundingOutput(ref outp) => {
312+
// Post-Anchor Commitment Package weight accoutning:
313+
let commitment_weight =
314+
900 // base commitment tx (900 WU)
315+
+ num_commitment_outputs * 172 // num-outputs * P2WSH-output (172 WU)
316+
+ 224; // funding spending witness (224 WU)
317+
// If a feerate-bump is required:
318+
let cpfp_weight: usize = if let Some(ref utxo_input) = outp.utxo_input {
319+
40 // CPFP transaction basic fields (40 WU)
320+
+ 2 // witness marker (2 WU)
321+
+ 164 // anchor input (164 WU)
322+
+ 115 // anchor witness (115 WU)
323+
+ 164 // bumping input (164 WU)
324+
+ utxo_input.1.witness_weight as usize // bumping witness (`utxo_input.1.witness_weight`)
325+
+ 32 // output amount (32 WU)
326+
+ 4 // output scriptpubkey-length (4 WU)
327+
+ destination_script.len() * 4 // output scriptpubkey (`destination_script.len() * 4`)
328+
} else { 0 };
329+
return commitment_weight + cpfp_weight;
330+
},
331+
PackageSolvingData::HolderHTLCOutput(ref outp) => {
332+
if outp.preimage.is_some() {
333+
return 706; // HTLC-Success with option_anchor_outputs
334+
} else {
335+
return 666; // HTLC-Timeout with option_anchor_outputs
336+
}
337+
},
310338
};
311339
weight
312340
}
@@ -589,13 +617,13 @@ impl PackageTemplate {
589617
self.inputs.iter().map(|(_, outp)| outp.absolute_tx_timelock(self.height_original))
590618
.max().expect("There must always be at least one output to spend in a PackageTemplate")
591619
}
592-
pub(crate) fn package_weight(&self, destination_script: &Script) -> usize {
620+
pub(crate) fn package_weight(&self, destination_script: &Script, num_commitment_outputs: usize) -> usize {
593621
let mut inputs_weight = 0;
594622
let mut witnesses_weight = 2; // count segwit flags
595623
for (_, outp) in self.inputs.iter() {
596624
// previous_out_point: 36 bytes ; var_int: 1 byte ; sequence: 4 bytes
597625
inputs_weight += 41 * WITNESS_SCALE_FACTOR;
598-
witnesses_weight += outp.weight();
626+
witnesses_weight += outp.weight(destination_script, num_commitment_outputs);
599627
}
600628
// version: 4 bytes ; count_tx_in: 1 byte ; count_tx_out: 1 byte ; lock_time: 4 bytes
601629
let transaction_weight = 10 * WITNESS_SCALE_FACTOR;
@@ -1081,6 +1109,6 @@ mod tests {
10811109
let package = PackageTemplate::build_package(txid, 0, revk_outp, 0, true, 100);
10821110
// (nVersion (4) + nLocktime (4) + count_tx_in (1) + prevout (36) + sequence (4) + script_length (1) + count_tx_out (1) + value (8) + var_int (1)) * WITNESS_SCALE_FACTOR
10831111
// + witness marker (2) + WEIGHT_REVOKED_OUTPUT
1084-
assert_eq!(package.package_weight(&Script::new()), (4 + 4 + 1 + 36 + 4 + 1 + 1 + 8 + 1) * WITNESS_SCALE_FACTOR + 2 + WEIGHT_REVOKED_OUTPUT as usize);
1112+
assert_eq!(package.package_weight(&Script::new(), 0), (4 + 4 + 1 + 36 + 4 + 1 + 1 + 8 + 1) * WITNESS_SCALE_FACTOR + 2 + WEIGHT_REVOKED_OUTPUT as usize);
10851113
}
10861114
}

lightning/src/ln/chan_utils.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -811,6 +811,13 @@ impl HolderCommitmentTransaction {
811811
tx.input[0].witness.push(funding_redeemscript.as_bytes().to_vec());
812812
tx
813813
}
814+
815+
/// Get the number of outputs attached on this transaction.
816+
///
817+
/// This can be used to compute the transaction weight.
818+
pub fn get_num_outputs(&self) -> usize {
819+
self.inner.get_num_outputs()
820+
}
814821
}
815822

816823
/// A pre-built Bitcoin commitment transaction and its txid.
@@ -845,6 +852,13 @@ impl BuiltCommitmentTransaction {
845852
let sighash = self.get_sighash_all(funding_redeemscript, channel_value_satoshis);
846853
secp_ctx.sign(&sighash, funding_key)
847854
}
855+
856+
/// Get the number of outputs attached on this transaction.
857+
///
858+
/// This can be used to compute the transaction weight.
859+
pub fn get_num_outputs(&self) -> usize {
860+
self.transaction.output.len()
861+
}
848862
}
849863

850864
/// This class tracks the per-transaction information needed to build a commitment transaction and to
@@ -1148,6 +1162,13 @@ impl CommitmentTransaction {
11481162
}
11491163
Ok(TrustedCommitmentTransaction { inner: self })
11501164
}
1165+
1166+
/// Get the number of outputs attached on this transaction.
1167+
///
1168+
/// This can be used to compute the transaction weight.
1169+
pub fn get_num_outputs(&self) -> usize {
1170+
self.built.get_num_outputs()
1171+
}
11511172
}
11521173

11531174
/// A wrapper on CommitmentTransaction indicating that the derived fields (the built bitcoin

0 commit comments

Comments
 (0)