Skip to content

Commit 867f084

Browse files
authored
Merge pull request #4053 from tankyleo/2025-09-p2a-anchor
Create a single P2A anchor on commitment transactions in 0FC channels
2 parents 3324799 + 538c4cc commit 867f084

File tree

7 files changed

+192
-64
lines changed

7 files changed

+192
-64
lines changed

lightning/src/chain/channelmonitor.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -367,7 +367,7 @@ fn write_legacy_holder_commitment_data<W: Writer>(
367367

368368
let txid = trusted_tx.txid();
369369
let to_self_value_sat = commitment_tx.to_broadcaster_value_sat();
370-
let feerate_per_kw = trusted_tx.feerate_per_kw();
370+
let feerate_per_kw = trusted_tx.negotiated_feerate_per_kw();
371371
let revocation_key = &tx_keys.revocation_key;
372372
let a_htlc_key = &tx_keys.broadcaster_htlc_key;
373373
let b_htlc_key = &tx_keys.countersignatory_htlc_key;
@@ -3468,7 +3468,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
34683468
) {
34693469
// We populate this field for downgrades
34703470
self.initial_counterparty_commitment_info = Some((commitment_tx.per_commitment_point(),
3471-
commitment_tx.feerate_per_kw(), commitment_tx.to_broadcaster_value_sat(), commitment_tx.to_countersignatory_value_sat()));
3471+
commitment_tx.negotiated_feerate_per_kw(), commitment_tx.to_broadcaster_value_sat(), commitment_tx.to_countersignatory_value_sat()));
34723472

34733473
#[cfg(debug_assertions)] {
34743474
let rebuilt_commitment_tx = self.initial_counterparty_commitment_tx().unwrap();
@@ -3674,7 +3674,9 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
36743674
{
36753675
return Err("Per-commitment-point mismatch");
36763676
}
3677-
if commitment_tx.feerate_per_kw() != other_commitment_tx.feerate_per_kw() {
3677+
if commitment_tx.negotiated_feerate_per_kw()
3678+
!= other_commitment_tx.negotiated_feerate_per_kw()
3679+
{
36783680
return Err("Commitment fee rate mismatch");
36793681
}
36803682
let nondust_htlcs = commitment_tx.nondust_htlcs();
@@ -4837,7 +4839,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
48374839
commitment_txid: tx.txid(),
48384840
per_commitment_number: tx.commitment_number(),
48394841
per_commitment_point: tx.per_commitment_point(),
4840-
feerate_per_kw: tx.feerate_per_kw(),
4842+
feerate_per_kw: tx.negotiated_feerate_per_kw(),
48414843
htlc: htlc.clone(),
48424844
preimage,
48434845
counterparty_sig: *counterparty_sig,

lightning/src/chain/onchaintx.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1398,7 +1398,7 @@ mod tests {
13981398
commitment_txid: holder_commit_txid,
13991399
per_commitment_number: holder_commit.commitment_number(),
14001400
per_commitment_point: holder_commit.per_commitment_point(),
1401-
feerate_per_kw: holder_commit.feerate_per_kw(),
1401+
feerate_per_kw: holder_commit.negotiated_feerate_per_kw(),
14021402
htlc: htlc.clone(),
14031403
preimage: None,
14041404
counterparty_sig: *counterparty_sig,

lightning/src/chain/package.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -528,7 +528,7 @@ impl HolderHTLCOutput {
528528
commitment_txid: trusted_tx.txid(),
529529
per_commitment_number: trusted_tx.commitment_number(),
530530
per_commitment_point: trusted_tx.per_commitment_point(),
531-
feerate_per_kw: trusted_tx.feerate_per_kw(),
531+
feerate_per_kw: trusted_tx.negotiated_feerate_per_kw(),
532532
htlc: htlc.clone(),
533533
preimage: self.preimage.clone(),
534534
counterparty_sig: *counterparty_sig,
@@ -1893,7 +1893,7 @@ mod tests {
18931893
commitment_txid: trusted_tx.txid(),
18941894
per_commitment_number: trusted_tx.commitment_number(),
18951895
per_commitment_point: trusted_tx.per_commitment_point(),
1896-
feerate_per_kw: trusted_tx.feerate_per_kw(),
1896+
feerate_per_kw: trusted_tx.negotiated_feerate_per_kw(),
18971897
htlc,
18981898
preimage: Some(preimage),
18991899
counterparty_sig: commitment_tx.counterparty_htlc_sigs[0].clone(),
@@ -1930,7 +1930,7 @@ mod tests {
19301930
commitment_txid: trusted_tx.txid(),
19311931
per_commitment_number: trusted_tx.commitment_number(),
19321932
per_commitment_point: trusted_tx.per_commitment_point(),
1933-
feerate_per_kw: trusted_tx.feerate_per_kw(),
1933+
feerate_per_kw: trusted_tx.negotiated_feerate_per_kw(),
19341934
htlc,
19351935
preimage: None,
19361936
counterparty_sig: commitment_tx.counterparty_htlc_sigs[0].clone(),

lightning/src/ln/chan_utils.rs

Lines changed: 72 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,12 @@ pub const ANCHOR_INPUT_WITNESS_WEIGHT: u64 = 114;
8989
#[cfg(not(feature = "grind_signatures"))]
9090
pub const ANCHOR_INPUT_WITNESS_WEIGHT: u64 = 115;
9191

92+
/// The P2A scriptpubkey
93+
pub const P2A_SCRIPT: &[u8] = &[0x51, 0x02, 0x4e, 0x73];
94+
95+
/// The maximum value of the P2A anchor
96+
pub const P2A_MAX_VALUE: u64 = 240;
97+
9298
/// The upper bound weight of an HTLC timeout input from a commitment transaction with anchor
9399
/// outputs.
94100
pub const HTLC_TIMEOUT_INPUT_ANCHOR_WITNESS_WEIGHT: u64 = 288;
@@ -804,18 +810,30 @@ pub(crate) fn make_funding_redeemscript_from_slices(broadcaster_funding_key: &[u
804810
///
805811
/// Panics if htlc.transaction_output_index.is_none() (as such HTLCs do not appear in the
806812
/// commitment transaction).
807-
#[rustfmt::skip]
808-
pub fn build_htlc_transaction(commitment_txid: &Txid, feerate_per_kw: u32, contest_delay: u16, htlc: &HTLCOutputInCommitment, channel_type_features: &ChannelTypeFeatures, broadcaster_delayed_payment_key: &DelayedPaymentKey, revocation_key: &RevocationKey) -> Transaction {
809-
let txins= vec![build_htlc_input(commitment_txid, htlc, channel_type_features)];
810-
811-
let mut txouts: Vec<TxOut> = Vec::new();
812-
txouts.push(build_htlc_output(
813-
feerate_per_kw, contest_delay, htlc, channel_type_features,
814-
broadcaster_delayed_payment_key, revocation_key
815-
));
813+
pub fn build_htlc_transaction(
814+
commitment_txid: &Txid, feerate_per_kw: u32, contest_delay: u16, htlc: &HTLCOutputInCommitment,
815+
channel_type_features: &ChannelTypeFeatures,
816+
broadcaster_delayed_payment_key: &DelayedPaymentKey, revocation_key: &RevocationKey,
817+
) -> Transaction {
818+
let txins = vec![build_htlc_input(commitment_txid, htlc, channel_type_features)];
819+
820+
let txouts: Vec<TxOut> = vec![build_htlc_output(
821+
feerate_per_kw,
822+
contest_delay,
823+
htlc,
824+
channel_type_features,
825+
broadcaster_delayed_payment_key,
826+
revocation_key,
827+
)];
828+
829+
let version = if channel_type_features.supports_anchor_zero_fee_commitments() {
830+
Version::non_standard(3)
831+
} else {
832+
Version::TWO
833+
};
816834

817835
Transaction {
818-
version: Version::TWO,
836+
version,
819837
lock_time: LockTime::from_consensus(if htlc.offered { htlc.cltv_expiry } else { 0 }),
820838
input: txins,
821839
output: txouts,
@@ -859,12 +877,13 @@ pub(crate) fn build_htlc_output(
859877
}
860878

861879
/// Returns the witness required to satisfy and spend a HTLC input.
862-
#[rustfmt::skip]
863880
pub fn build_htlc_input_witness(
864881
local_sig: &Signature, remote_sig: &Signature, preimage: &Option<PaymentPreimage>,
865882
redeem_script: &Script, channel_type_features: &ChannelTypeFeatures,
866883
) -> Witness {
867-
let remote_sighash_type = if channel_type_features.supports_anchors_zero_fee_htlc_tx() {
884+
let remote_sighash_type = if channel_type_features.supports_anchors_zero_fee_htlc_tx()
885+
|| channel_type_features.supports_anchor_zero_fee_commitments()
886+
{
868887
EcdsaSighashType::SinglePlusAnyoneCanPay
869888
} else {
870889
EcdsaSighashType::All
@@ -873,7 +892,10 @@ pub fn build_htlc_input_witness(
873892
let mut witness = Witness::new();
874893
// First push the multisig dummy, note that due to BIP147 (NULLDUMMY) it must be a zero-length element.
875894
witness.push(vec![]);
876-
witness.push_ecdsa_signature(&BitcoinSignature { signature: *remote_sig, sighash_type: remote_sighash_type });
895+
witness.push_ecdsa_signature(&BitcoinSignature {
896+
signature: *remote_sig,
897+
sighash_type: remote_sighash_type,
898+
});
877899
witness.push_ecdsa_signature(&BitcoinSignature::sighash_all(*local_sig));
878900
if let Some(preimage) = preimage {
879901
witness.push(preimage.0.to_vec());
@@ -1232,6 +1254,11 @@ impl<'a> DirectedChannelTransactionParameters<'a> {
12321254
pub fn channel_type_features(&self) -> &'a ChannelTypeFeatures {
12331255
&self.inner.channel_type_features
12341256
}
1257+
1258+
/// The value locked in the channel, denominated in satoshis.
1259+
pub fn channel_value_satoshis(&self) -> u64 {
1260+
self.inner.channel_value_satoshis
1261+
}
12351262
}
12361263

12371264
/// Information needed to build and sign a holder's commitment transaction.
@@ -1637,7 +1664,7 @@ impl CommitmentTransaction {
16371664
let outputs = Self::build_outputs_and_htlcs(&keys, to_broadcaster_value_sat, to_countersignatory_value_sat, &mut nondust_htlcs, channel_parameters);
16381665

16391666
let (obscured_commitment_transaction_number, txins) = Self::build_inputs(commitment_number, channel_parameters);
1640-
let transaction = Self::make_transaction(obscured_commitment_transaction_number, txins, outputs);
1667+
let transaction = Self::make_transaction(obscured_commitment_transaction_number, txins, outputs, channel_parameters);
16411668
let txid = transaction.compute_txid();
16421669
CommitmentTransaction {
16431670
commitment_number,
@@ -1691,6 +1718,8 @@ impl CommitmentTransaction {
16911718
// First rebuild the htlc outputs, note that `outputs` is now the same length as `self.nondust_htlcs`
16921719
let mut outputs = Self::build_htlc_outputs(keys, &self.nondust_htlcs, channel_parameters.channel_type_features());
16931720

1721+
let nondust_htlcs_value_sum_sat = self.nondust_htlcs.iter().map(|htlc| htlc.to_bitcoin_amount()).sum();
1722+
16941723
// Check that the HTLC outputs are sorted by value, script pubkey, and cltv expiry.
16951724
// Note that this only iterates if the length of `outputs` and `self.nondust_htlcs` is >= 2.
16961725
if (1..outputs.len()).into_iter().any(|i| Self::is_left_greater(i, &outputs, &self.nondust_htlcs)) {
@@ -1713,11 +1742,11 @@ impl CommitmentTransaction {
17131742
self.to_broadcaster_value_sat,
17141743
self.to_countersignatory_value_sat,
17151744
channel_parameters,
1716-
!self.nondust_htlcs.is_empty(),
1745+
nondust_htlcs_value_sum_sat,
17171746
insert_non_htlc_output
17181747
);
17191748

1720-
let transaction = Self::make_transaction(obscured_commitment_transaction_number, txins, outputs);
1749+
let transaction = Self::make_transaction(obscured_commitment_transaction_number, txins, outputs, channel_parameters);
17211750
let txid = transaction.compute_txid();
17221751
let built_transaction = BuiltCommitmentTransaction {
17231752
transaction,
@@ -1727,9 +1756,14 @@ impl CommitmentTransaction {
17271756
}
17281757

17291758
#[rustfmt::skip]
1730-
fn make_transaction(obscured_commitment_transaction_number: u64, txins: Vec<TxIn>, outputs: Vec<TxOut>) -> Transaction {
1759+
fn make_transaction(obscured_commitment_transaction_number: u64, txins: Vec<TxIn>, outputs: Vec<TxOut>, channel_parameters: &DirectedChannelTransactionParameters) -> Transaction {
1760+
let version = if channel_parameters.channel_type_features().supports_anchor_zero_fee_commitments() {
1761+
Version::non_standard(3)
1762+
} else {
1763+
Version::TWO
1764+
};
17311765
Transaction {
1732-
version: Version::TWO,
1766+
version,
17331767
lock_time: LockTime::from_consensus(((0x20 as u32) << 8 * 3) | ((obscured_commitment_transaction_number & 0xffffffu64) as u32)),
17341768
input: txins,
17351769
output: outputs,
@@ -1747,7 +1781,8 @@ impl CommitmentTransaction {
17471781
// First build and sort the HTLC outputs.
17481782
// Also sort the HTLC output data in `nondust_htlcs` in the same order.
17491783
let mut outputs = Self::build_sorted_htlc_outputs(keys, nondust_htlcs, channel_parameters.channel_type_features());
1750-
let tx_has_htlc_outputs = !outputs.is_empty();
1784+
1785+
let nondust_htlcs_value_sum_sat = nondust_htlcs.iter().map(|htlc| htlc.to_bitcoin_amount()).sum();
17511786

17521787
// Initialize the transaction output indices; we will update them below when we
17531788
// add the non-htlc transaction outputs.
@@ -1784,7 +1819,7 @@ impl CommitmentTransaction {
17841819
to_broadcaster_value_sat,
17851820
to_countersignatory_value_sat,
17861821
channel_parameters,
1787-
tx_has_htlc_outputs,
1822+
nondust_htlcs_value_sum_sat,
17881823
insert_non_htlc_output
17891824
);
17901825

@@ -1797,7 +1832,7 @@ impl CommitmentTransaction {
17971832
to_broadcaster_value_sat: Amount,
17981833
to_countersignatory_value_sat: Amount,
17991834
channel_parameters: &DirectedChannelTransactionParameters,
1800-
tx_has_htlc_outputs: bool,
1835+
nondust_htlcs_value_sum_sat: Amount,
18011836
mut insert_non_htlc_output: F,
18021837
) where
18031838
F: FnMut(TxOut),
@@ -1807,6 +1842,7 @@ impl CommitmentTransaction {
18071842
let broadcaster_funding_key = &channel_parameters.broadcaster_pubkeys().funding_pubkey;
18081843
let channel_type = channel_parameters.channel_type_features();
18091844
let contest_delay = channel_parameters.contest_delay();
1845+
let tx_has_htlc_outputs = nondust_htlcs_value_sum_sat != Amount::ZERO;
18101846

18111847
if to_countersignatory_value_sat > Amount::ZERO {
18121848
let script = if channel_type.supports_anchors_zero_fee_htlc_tx() {
@@ -1849,6 +1885,16 @@ impl CommitmentTransaction {
18491885
});
18501886
}
18511887
}
1888+
1889+
if channel_type.supports_anchor_zero_fee_commitments() {
1890+
let channel_value_satoshis = Amount::from_sat(channel_parameters.channel_value_satoshis());
1891+
// These subtractions panic on underflow, but this should never happen
1892+
let trimmed_sum_sat = channel_value_satoshis - nondust_htlcs_value_sum_sat - to_broadcaster_value_sat - to_countersignatory_value_sat;
1893+
insert_non_htlc_output(TxOut {
1894+
script_pubkey: ScriptBuf::from_bytes(P2A_SCRIPT.to_vec()),
1895+
value: cmp::min(Amount::from_sat(P2A_MAX_VALUE), trimmed_sum_sat),
1896+
});
1897+
}
18521898
}
18531899

18541900
#[rustfmt::skip]
@@ -1950,8 +1996,11 @@ impl CommitmentTransaction {
19501996
self.to_countersignatory_value_sat.to_sat()
19511997
}
19521998

1953-
/// The feerate paid per 1000-weight-unit in this commitment transaction.
1954-
pub fn feerate_per_kw(&self) -> u32 {
1999+
/// The feerate paid per 1000-weight-unit we negotiated with our
2000+
/// peer for this commitment transaction. Note that the actual
2001+
/// feerate of the commitment transaction may be higher than the
2002+
/// negotiated feerate.
2003+
pub fn negotiated_feerate_per_kw(&self) -> u32 {
19552004
self.feerate_per_kw
19562005
}
19572006

0 commit comments

Comments
 (0)