-
Notifications
You must be signed in to change notification settings - Fork 419
Refactor ConstructedTransaction
to contain Transaction
#4097
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
Refactor ConstructedTransaction
to contain Transaction
#4097
Conversation
👋 Thanks for assigning @wpaulino as a reviewer! |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #4097 +/- ##
==========================================
+ Coverage 87.81% 88.71% +0.89%
==========================================
Files 176 177 +1
Lines 131770 133237 +1467
Branches 131770 133237 +1467
==========================================
+ Hits 115719 118196 +2477
+ Misses 13416 12326 -1090
- Partials 2635 2715 +80
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
lightning/src/ln/interactivetxs.rs
Outdated
fn add_local_witnesses(&mut self, witnesses: Vec<Witness>) { | ||
self.inputs | ||
self.tx | ||
.input | ||
.iter_mut() | ||
.zip(self.inputs.iter()) | ||
.enumerate() | ||
.filter(|(_, input)| input.is_local(self.holder_is_initiator)) | ||
.filter(|(_, (_, input))| input.is_local(self.holder_is_initiator)) | ||
.filter(|(index, _)| { | ||
self.shared_input_index | ||
.map(|shared_index| *index != shared_index as usize) | ||
.unwrap_or(true) | ||
}) | ||
.map(|(_, input)| &mut input.txin) | ||
.map(|(_, (txin, _))| txin) | ||
.zip(witnesses) | ||
.for_each(|(input, witness)| input.witness = witness); | ||
} |
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.
Wondering if we should have InteractiveTxSigningSession
store both local and remote signatures until finalize_funding_tx
is called. That way, ConstructedTransaction
would always contain an unsigned transaction instead of one that may be partially signed.
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.
SGTM, we already store the local ones separately
InteractiveTxConstructor::new converts inputs given in channel.rs to InputOwned. Instead of converting FundingTxInput in channel.rs to the type needed by that constructor, pass in FundingTxInput and have it converted directly to InputOwned there. This saves one conversion and Vec allocation. It also lets us use the satisfaction_weight in an upcoming refactor.
Instead of estimating the input weight, track the satisfaction_weight in InteractiveTxInput. This then can be used compute the transaction weight without storing individual weights in NegotiatedTxInput in an upcoming commit.
The weight is no longer needed once a ConstructedTransaction is created, so it doesn't need to be persisted.
Instead of defining a custom function for calculating a transaction's weight, have ConstructedTransaction hold a Transaction so that its weight method can be re-used. As a result NegotiatedTxInput no longer needs to store the transaction inputs.
f96f304
to
9eeaf52
Compare
Pushed |
🔔 1st Reminder Hey @wpaulino! This PR has been waiting for your review. |
lightning/src/ln/interactivetxs.rs
Outdated
fn add_local_witnesses(&mut self, witnesses: Vec<Witness>) { | ||
self.inputs | ||
self.tx | ||
.input | ||
.iter_mut() | ||
.zip(self.inputs.iter()) | ||
.enumerate() | ||
.filter(|(_, input)| input.is_local(self.holder_is_initiator)) | ||
.filter(|(_, (_, input))| input.is_local(self.holder_is_initiator)) | ||
.filter(|(index, _)| { | ||
self.shared_input_index | ||
.map(|shared_index| *index != shared_index as usize) | ||
.unwrap_or(true) | ||
}) | ||
.map(|(_, input)| &mut input.txin) | ||
.map(|(_, (txin, _))| txin) | ||
.zip(witnesses) | ||
.for_each(|(input, witness)| input.witness = witness); | ||
} |
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.
SGTM, we already store the local ones separately
👋 The first review has been submitted! Do you think this PR is ready for a second reviewer? If so, click here to assign a second reviewer. |
Now that NegotiatedTxInput no longer holds a TxIn, rename it accordingly.
Now that ConstructedTransaction holds the actual Transaction, there's no need to keep track of and persist the outputs separately. However, the serial IDs are still needed to later reconstruct which outputs were contributed.
9eeaf52
to
7958dd9
Compare
The output values are never used so there's no need to persist them. If needed, they can be re-computed though the shared output's local and remote amounts would be lost.
The local and remote input values are used to determine which node sends tx_signatures first. Instead of persisting these values, compute them only when needed from the input metadata. The spec states that the entire shared input value is to be included for the node sending the corresponding tx_add_input, so it isn't necessary to know the local and remote balances which the metadata does not contain.
InteractiveTxSigningSession currently persists holder witnesses directly, but persists counterparty witnesses as part of its unsigned ConstructedTransaction. This makes the ConstructedTransaction actually partially signed even though it is held in a field named unsigned_tx. Instead, persists the counterparty witnesses alongside the holder witnesses directly in InteractiveTxSigningSession, leaving the transaction it holds unsigned.
7958dd9
to
86ed012
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.
Code changes look fine to me. I'm not deep enough in the interactive negotiation world to say whether its all a good idea, but seems fine to me.
.as_ref() | ||
.map(|shared_input| SharedInputSignature { | ||
holder_signature_first: shared_input.holder_sig_first, | ||
counterparty_signature: None, |
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.
Should probably rename SharedInputSignature
since it doesn't contain a signature anymore
if let Some(shared_input_index) = self.shared_input_index { | ||
let holder_shared_input_sig = | ||
holder_tx_signatures.shared_input_signature.or_else(|| { | ||
debug_assert!(false); |
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 think it'd be better to debug_assert_eq!(shared_input_index.is_some(), holder_tx_signatures.shared_input_signature.is_some())
to catch the other possible cases as well
ConstructedTransaction
tracks the result of theInteractiveTxConstruction
and is used during anInteractiveTxSigningSession
. This PR refactors it such that it holds an actualTransaction
rather than the contributed parts, though some metadata in the form ofNegotiatedTxInput
andNegotiatedTxOutput
need to be maintained.This allows us to re-use the weight calculation provided by
Transaction
. It also facilitates reconstructing contributed inputs and outputs to produce aSpliceFailed
event in #4077.