-
Notifications
You must be signed in to change notification settings - Fork 401
Remove exclusive reference and generic from CommitmentTransaction
API
#3689
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
tankyleo
commented
Mar 29, 2025
•
edited
Loading
edited
👋 Thanks for assigning @TheBlueMatt as a reviewer! |
1cc3c50
to
fd57c35
Compare
CommitmentTransaction
API
fd57c35
to
ecc7dcf
Compare
CommitmentTransaction
APICommitmentTransaction
API
CommitmentTransaction
APICommitmentTransaction
API
c8a753e
to
b04cc76
Compare
CommitmentTransaction
APICommitmentTransaction
API
f4a3cc3
to
acad6d8
Compare
acad6d8
to
c86b528
Compare
lightning/src/ln/chan_utils.rs
Outdated
/// This is not exported to bindings users due to the generic though we likely should expose a version without | ||
pub fn new_with_auxiliary_htlc_data<T>(commitment_number: u64, per_commitment_point: &PublicKey, to_broadcaster_value_sat: u64, to_countersignatory_value_sat: u64, feerate_per_kw: u32, htlcs_with_aux: &mut Vec<(HTLCOutputInCommitment, T)>, channel_parameters: &DirectedChannelTransactionParameters, secp_ctx: &Secp256k1<secp256k1::All>) -> CommitmentTransaction { | ||
/// The broadcaster and countersignatory amounts MUST be EITHER 0 or ABOVE DUST. | ||
pub fn new(commitment_number: u64, per_commitment_point: &PublicKey, to_broadcaster_value_sat: u64, to_countersignatory_value_sat: u64, feerate_per_kw: u32, nondust_htlcs: &Vec<HTLCOutputInCommitment>, channel_parameters: &DirectedChannelTransactionParameters, secp_ctx: &Secp256k1<secp256k1::All>) -> CommitmentTransaction { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@TheBlueMatt Let me know how this API looks - would bindings be happier if we took the nondust_htlcs
by value instead of by reference ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Passing it by value might make sense, given build_outputs_and_htlcs
is basically cloneing it anyway?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But otherwise I think this makes sense.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you I switched it to a pass-by-value below.
lightning/src/ln/channel.rs
Outdated
let htlc = htlcs_included | ||
.iter_mut() | ||
.filter(|(htlc, _source)| htlc.transaction_output_index.is_none()) | ||
.filter_map(|(htlc, _source)| { | ||
if htlc.is_data_equal(nondust_htlc) { | ||
Some(htlc) | ||
} else { | ||
None | ||
} | ||
}) | ||
.nth(0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Won't this always pick the first HTLC if we have multiple with the same data (but different indices of course)? This only works if we reuse the iterator, but we seem to be using a new one each iteration of the loop.
Never mind, missed that we're filtering for the first one without an output index assigned. We should be able to use find_map
instead of filter_map
though so we stop iterating once we get a match.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Afk now will look more closely - I was thinking nth 0 stops the iteration on the first match.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It does, TIL https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=d810bda4b86bfc0f7012a2d1c52ff1de.
find
is still more idiomatic in this case though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Certainly thanks, should be addressed below.
c86b528
to
fcdacc9
Compare
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #3689 +/- ##
==========================================
+ Coverage 89.07% 89.09% +0.02%
==========================================
Files 156 156
Lines 123507 123661 +154
Branches 123507 123661 +154
==========================================
+ Hits 110017 110179 +162
+ Misses 10801 10800 -1
+ Partials 2689 2682 -7 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One last real comment
@@ -614,6 +614,13 @@ impl HTLCOutputInCommitment { | |||
pub const fn to_bitcoin_amount(&self) -> Amount { | |||
Amount::from_sat(self.amount_msat / 1000) | |||
} | |||
|
|||
pub(crate) fn is_data_equal(&self, other: &HTLCOutputInCommitment) -> bool { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might be worth a quick doc just to make obvious that the intent is to only ignore one field and why.
lightning/src/ln/chan_utils.rs
Outdated
fn build_outputs_and_htlcs(keys: &TxCreationKeys, to_broadcaster_value_sat: Amount, to_countersignatory_value_sat: Amount, nondust_htlcs: &Vec<HTLCOutputInCommitment>, channel_parameters: &DirectedChannelTransactionParameters) -> (Vec<TxOut>, Vec<HTLCOutputInCommitment>) { | ||
let txout_htlc_pairs: Vec<(TxOut, Option<&HTLCOutputInCommitment>)> = Self::build_txout_htlc_pairs(keys, to_broadcaster_value_sat, to_countersignatory_value_sat, nondust_htlcs, channel_parameters); | ||
let mut outputs: Vec<TxOut> = Vec::with_capacity(txout_htlc_pairs.len()); | ||
let mut nondust_htlcs: Vec<HTLCOutputInCommitment> = Vec::with_capacity(txout_htlc_pairs.len()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now that we're passed nondust_htlcs
by ownership, can we at least have build_txout_htlc_pairs
hold references to the specific HTLCOutputInCommitment
s and then update the transaction_output_index
by mutable reference (then sorting) rather than allocating a new nondust_htlcs
vec?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I went with shared references to avoid a clone of self.nondust_htlcs
in rebuild_transaction
. But we could make build_txout_htlc_pairs
generic over &
and &mut
with a T: Borrow<HTLCOutputInCommitment>
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks again - let me know how the latest commit sounds - I'd like to continue passing &self.nondust_htlcs
to build_txout_htlc_pairs
in rebuild_transaction
.
fcdacc9
to
7e3a4e1
Compare
1d7a1d8
to
262351c
Compare
262351c
to
6ba5280
Compare
🔔 1st Reminder Hey @TheBlueMatt @wpaulino! This PR has been waiting for your review. |
1 similar comment
🔔 1st Reminder Hey @TheBlueMatt @wpaulino! This PR has been waiting for your review. |
@TheBlueMatt In this last commit here I delete the |
f021734
to
1621c12
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
New commit basically LTGM.
lightning/src/ln/chan_utils.rs
Outdated
let to_broadcaster_value_sat = Amount::from_sat(to_broadcaster_value_sat); | ||
let to_countersignatory_value_sat = Amount::from_sat(to_countersignatory_value_sat); | ||
let keys = TxCreationKeys::from_channel_static_keys(per_commitment_point, channel_parameters.broadcaster_pubkeys(), channel_parameters.countersignatory_pubkeys(), secp_ctx); | ||
|
||
// Sort outputs and populate output indices while keeping track of the auxiliary data | ||
let (outputs, nondust_htlcs) = Self::internal_build_outputs(&keys, to_broadcaster_value_sat, to_countersignatory_value_sat, htlcs_with_aux, channel_parameters); | ||
let (outputs, nondust_htlcs) = Self::build_outputs_and_htlcs(&keys, to_broadcaster_value_sat, to_countersignatory_value_sat, nondust_htlcs, channel_parameters); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: No need to keep passing nondust_htlcs
down by ownership and returning it, might read a bit cleaner if you just pass a mutable reference when we're looking at internal methods.
lightning/src/ln/chan_utils.rs
Outdated
// Sort outputs in BIP-69 order (amount, scriptPubkey). Tie-breaks based on HTLC | ||
// CLTV expiration height. | ||
// | ||
// CLN uses dumb sort... so we do too. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ha, "they do it" is never a good reason to do anything. We should explain that we're okay with N^2 for N=483*2
lightning/src/ln/chan_utils.rs
Outdated
|
||
// Initialize the transaction output index; we will update it when we | ||
// add the non-htlc transaction outputs. | ||
nondust_htlcs[i].transaction_output_index = Some(i as u32); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can move out of the top loop and we can just do a pass at the end to set the output indicies to the index used as long as we're swapping both arrays together.
lightning/src/ln/chan_utils.rs
Outdated
// | ||
// CLN uses dumb sort... so we do too. | ||
for i in 0..txouts.len() { | ||
// Find the minimum element |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh come on, at least do some naive CS 101 sorting algorithm that has a better best-case.
1621c12
to
258b277
Compare
258b277
to
ee42e2a
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Basically LGTM, Probably needs another look from @wpaulino otherwise I'm happy.
/// | ||
/// This is not exported to bindings users due to the generic though we likely should expose a version without | ||
pub fn new_with_auxiliary_htlc_data<T>(commitment_number: u64, per_commitment_point: &PublicKey, to_broadcaster_value_sat: u64, to_countersignatory_value_sat: u64, feerate_per_kw: u32, htlcs_with_aux: &mut Vec<(HTLCOutputInCommitment, T)>, channel_parameters: &DirectedChannelTransactionParameters, secp_ctx: &Secp256k1<secp256k1::All>) -> CommitmentTransaction { | ||
/// All HTLCs MUST be above the dust limit for the channel.\ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
stray , I think? note that if you dont leave an extra line between paragraphs, rustdoc assumes you meant for them to be in the same paragraph and ignores newlines in the source.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lightning/src/ln/chan_utils.rs
Outdated
let to_broadcaster_value_sat = Amount::from_sat(to_broadcaster_value_sat); | ||
let to_countersignatory_value_sat = Amount::from_sat(to_countersignatory_value_sat); | ||
let keys = TxCreationKeys::from_channel_static_keys(per_commitment_point, channel_parameters.broadcaster_pubkeys(), channel_parameters.countersignatory_pubkeys(), secp_ctx); | ||
|
||
// Sort outputs and populate output indices while keeping track of the auxiliary data | ||
let (outputs, nondust_htlcs) = Self::internal_build_outputs(&keys, to_broadcaster_value_sat, to_countersignatory_value_sat, htlcs_with_aux, channel_parameters); | ||
// Build the BIP-69 ordered outputs of the transaction. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: we are not technically ordering the outputs per BIP 69, we are ordering it with additional metadata (the CLTV) and also BIP 69 is underspecified (even going so far as to mis-define lexicographical ordering!). Best to avoid mentioning it (or every implementing it).
ee42e2a
to
8bc75b9
Compare
This commit reworks how channel is told about which HTLCs were assigned which index upon the build of a `CommitmentTransaction`. Previously, `CommitmentTransaction` was given an exclusive reference to channel's HTLC-source table, and `CommitmentTransaction` populated the transaction output indices in that table via this exclusive reference. As a result, the public API of `CommitmentTransaction` included a generic parameter, and an exclusive reference. We remove both of these in preparation for the upcoming `TxBuilder` trait. This cleans up the API, and makes it more bindings-friendly. Henceforth, channel populates the HTLC-source table via a brute-force search of each htlc in `CommitmentTransaction`. This is an O(n^2) operation, but n is small enough that we ignore the performance hit. We also take this opportunity to cleanup how we build and sort the commitment transaction outputs together with the htlc output data in `CommitmentTransaction`. The goal is to keep the number of vector allocations to a minimum; we now only allocate a single vector to hold the transaction outputs, and do all the sorting in-place.
8bc75b9
to
5252437
Compare