-
Notifications
You must be signed in to change notification settings - Fork 418
[Splicing] Tx negotiation during splicing #3736
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
👋 Thanks for assigning @wpaulino as a reviewer! |
7f6dfbd
to
c3778bc
Compare
1 similar comment
1 similar comment
1 similar comment
1 similar comment
1 similar comment
1 similar comment
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.
Sorry about the late review. We were traveling to an off site last week. Just a high-level pass on the first four commits. Will need to take a closer look at the last one.
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #3736 +/- ##
==========================================
+ Coverage 89.73% 90.28% +0.55%
==========================================
Files 159 160 +1
Lines 128910 132032 +3122
Branches 128910 132032 +3122
==========================================
+ Hits 115676 119207 +3531
+ Misses 10536 10172 -364
+ Partials 2698 2653 -45 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
88d2e83
to
866368d
Compare
Ready for a new round of review. I have addressed the comments, applied most of them. There is still one to-do (update channel reserve values), that I will do, but the rest is ready for review. |
Ready for a new round of review. All pending and newly raised comments addressed. |
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.
Could you squash the fixups with their relevant commits?
))); | ||
} | ||
|
||
self.context.assert_no_commitment_advancement(self.holder_commitment_transaction_number, "initial commitment_signed"); | ||
let commitment_signed = self.context.get_initial_commitment_signed(&self.funding, logger); |
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.
Hmm... I think this is referring to:
rust-lightning/lightning/src/ln/channel.rs
Line 8458 in 257ebad
let commitment_signed = self.context.get_initial_commitment_signed(&self.funding, logger)?; |
This is an FYI to me, so you shouldn't need to address anything.
lightning/src/ln/channel.rs
Outdated
let pre_channel_value = self.funding.get_value_satoshis(); | ||
let their_funding_contribution = msg.funding_contribution_satoshis; | ||
|
||
let post_channel_value = PendingSplice::compute_post_value( | ||
pre_channel_value, | ||
our_funding_contribution, | ||
their_funding_contribution, | ||
); | ||
|
||
let (our_funding_satoshis, their_funding_satoshis) = calculate_total_funding_contribution( | ||
pre_channel_value, | ||
our_funding_contribution, | ||
msg.funding_contribution_satoshis, | ||
false, // is_outbound | ||
)?; |
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.
Could any of this be moved into FundingScope::for_splice
? It would be nice if we could avoid the debug_assert
in there.
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.
Not really. The debug assert in FundingScope::for_splice
says that we cannot splice out more than our balance. The reserve check should implicitly guard against this as well: we cannot splice out more than our balance plus the minimum reserve. (#3641).
The calculate_total_funding_contribution
does not deal with current balances, so that's a different check.
b88a866
to
74d4a14
Compare
Fixes applied to commits, new comments addressed. Ready for review. |
lightning/src/ln/channel.rs
Outdated
fn begin_interactive_funding_tx_construction<ES: Deref>( | ||
&mut self, signer_provider: &SP, entropy_source: &ES, holder_node_id: PublicKey, | ||
change_destination_opt: Option<ScriptBuf>, | ||
is_initiator: bool, change_destination_opt: Option<ScriptBuf>, |
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.
Really calculate_change_output_value
doesn't belong in interactivetxs.rs
, the protocol is not concerned with change outputs.
pub our_funding_contribution: i64, | ||
funding: Option<FundingScope>, | ||
funding_negotiation_context: FundingNegotiationContext, |
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.
Looks like we shouldn't need our_funding_contribution
above anymore
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.
Unfortunately these are not the same:
PendingSplice.our_funding_contribution
: the contribution to the splice, relative to the current channel value, signed.FundingNegotiationContext.
: our share from the total spliced funding tx; the previous channel value plus the aboce, unsigned.
#[cfg(splicing)] | ||
fn as_renegotiating_channel(&mut self) -> Result<NegotiatingChannelView<SP>, &'static str> { | ||
if let Some(ref mut pending_splice) = &mut self.pending_splice { | ||
if let Some(ref mut funding) = &mut pending_splice.funding { |
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.
On second thought, I think checking for the interactive_tx_constructor
instead is more correct, as that's what we're mainly using whenever as_renegotiating_channel
gets called.
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 we need the FundingScope
and PendingSplice
to initialize NegotiatingChannelView
, right?
ClosureReason::HolderForceClosed { broadcasted_latest_txn: Some(false) }, | ||
))), chan_entry) | ||
Err(err) => { | ||
try_channel_entry!(self, peer_state, Err(err), chan_entry) |
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 we can just send a warning here, as we do with the other tx_*
messages
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.
Currently as_negotiating_channel
returns only ChanelError::Warn
interactive_tx_constructor: &'a mut Option<InteractiveTxConstructor>, | ||
interactive_tx_signing_session: &'a mut Option<InteractiveTxSigningSession>, |
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 don't think we need to track interactive_tx_signing_session
at all here, as long as we separately set the session in funding_tx_constructed
.
interactive_tx_constructor
also shouldn't be an Option
, but it seems to be that way right now because of begin_interactive_funding_tx_construction
and funding_tx_constructed
.
For begin_interactive_funding_tx_construction
, maybe it makes more sense to make it a standalone function (no longer a member on NegotiatingChannelView
) that simply returns an InteractiveTxConstructor
that we can set on the channel separately.
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 don't think we need to track
interactive_tx_signing_session
at all here, as long as we separately set the session infunding_tx_constructed
.
This is called from Channel::funding_tx_constructed
, so we wouldn't know where to set it on without
interactive_tx_constructor
also shouldn't be anOption
, but it seems to be that way right now because ofbegin_interactive_funding_tx_construction
andfunding_tx_constructed
.For
begin_interactive_funding_tx_construction
, maybe it makes more sense to make it a standalone function (no longer a member onNegotiatingChannelView
) that simply returns anInteractiveTxConstructor
that we can set on the channel separately.
We need it in the next commit when calling tx_add_input
, et al.
return Err(ChannelError::Warn(format!("Channel is not in pending splice"))); | ||
}; | ||
|
||
// TODO(splicing): Add check that we are the splice (quiescence) initiator | ||
|
||
if pending_splice.funding.is_some() || pending_splice.interactive_tx_constructor.is_some() { |
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.
Once we have #3911, funding
will move into negotiated_candidates
after exchanging tx_signatures
, so we'll also need to check that negotiated_candidates
is not empty before proceeding.
msg.funding_pubkey, | ||
)?; | ||
|
||
let (our_funding_satoshis, their_funding_satoshis) = calculate_total_funding_contribution( |
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'm a bit lost with the goal here, why are we mixing past contributions with new ones? When we say we're contributing 50k sats to a splice, we're adding 50k sats to the channel value. We shouldn't consider the past channel value as part of our contribution.
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.
In the splice_*
messages we use the 'extra' contributions to the splice, eg. 50k. But from the point of view of InteractiveTxNegotiatior
the previous funding is an input, so the total contribution of the initiator is the previous funding plus the extra contribution.
This is a simple rename, DualFundingContext to FundingNegotiationContext, to suggest that this is use not only in dual-funded channel open. Also rename the field dual_funding_context to funding_negotiation_context.
The begin_interactive_funding_tx_construction() method is extended with `is_initiator` parameter (splice initiator), and `prev_funding_input` optional parameter, containing the previous funding transaction, which will be added to the negotiation as an input by the initiator.
d9314a2
to
37b01c0
Compare
Rebased to pre- #3842 main |
37b01c0
to
6cb8084
Compare
Rebased to current main, including the relevant #3842 . |
Introduce struct NegotiatingChannelView to perform transaction negotiation logic, on top of either PendingV2Channel (dual-funded channel open) or FundedChannel (splicing).
Fill the logic for including transaction negotiation during splicing, implement the functions: splice_channel, splice_init, splice_ack, funding_tx_constructed. Also extend the test case test_v1_splice_in with the steps for funding negotiation during splicing.
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/channel.rs
Outdated
fn begin_interactive_funding_tx_construction<ES: Deref>( | ||
&mut self, signer_provider: &SP, entropy_source: &ES, holder_node_id: PublicKey, | ||
change_destination_opt: Option<ScriptBuf>, | ||
is_initiator: bool, change_destination_opt: Option<ScriptBuf>, |
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.
Updated to take FundingNegotiationContext
with an added is_initiator
field. Left it in interactivetxs.rs
for the time being given it's tested there, too. Can move it at the end of the review.
lightning/src/ln/channel.rs
Outdated
fn begin_interactive_funding_tx_construction<ES: Deref>( | ||
&mut self, signer_provider: &SP, entropy_source: &ES, holder_node_id: PublicKey, | ||
change_destination_opt: Option<ScriptBuf>, | ||
is_initiator: bool, change_destination_opt: Option<ScriptBuf>, | ||
prev_funding_input: Option<(TxIn, TransactionU16LenLimited)>, |
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.
Rebased. Now prev_funding_input
is shared_funding_input
passed as Option<SharedOwnedInput>
.
lightning/src/ln/channel.rs
Outdated
|
||
// TODO(splicing): Add prev funding tx as input, must be provided as a parameter | ||
if is_initiator { | ||
if let Some(prev_funding_input) = prev_funding_input { |
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.
Added a fixup for the shared input.
#[cfg(splicing)] | ||
fn as_renegotiating_channel(&mut self) -> Result<NegotiatingChannelView<SP>, &'static str> { | ||
if let Some(ref mut pending_splice) = &mut self.pending_splice { | ||
if let Some(ref mut funding) = &mut pending_splice.funding { |
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 we need the FundingScope
and PendingSplice
to initialize NegotiatingChannelView
, right?
Err(tx_msg_str) => return Err(MsgHandleErrInternal::from_chan_no_close(ChannelError::Warn( | ||
format!("Got a {tx_msg_str} message with no interactive transaction construction expected or in-progress") | ||
), channel_id)), | ||
Err(err) => return Err(MsgHandleErrInternal::from_chan_no_close(err, channel_id)), |
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.
We can't add it here. Instead, we would need to do it at each call site of as_negotiating_channel
s (i.e. within each HandleTxMsgFn
passed here and wherever else it is called).
interactive_tx_constructor: &'a mut Option<InteractiveTxConstructor>, | ||
interactive_tx_signing_session: &'a mut Option<InteractiveTxSigningSession>, |
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 don't think we need to track
interactive_tx_signing_session
at all here, as long as we separately set the session infunding_tx_constructed
.
This is called from Channel::funding_tx_constructed
, so we wouldn't know where to set it on without
interactive_tx_constructor
also shouldn't be anOption
, but it seems to be that way right now because ofbegin_interactive_funding_tx_construction
andfunding_tx_constructed
.For
begin_interactive_funding_tx_construction
, maybe it makes more sense to make it a standalone function (no longer a member onNegotiatingChannelView
) that simply returns anInteractiveTxConstructor
that we can set on the channel separately.
We need it in the next commit when calling tx_add_input
, et al.
) -> Result<Option<InteractiveTxMessageSend>, AbortReason> | ||
where ES::Target: EntropySource | ||
{ | ||
debug_assert!(matches!(self.context.channel_state, ChannelState::NegotiatingFunding(_))); | ||
if self.is_splice { | ||
debug_assert!(matches!(self.context.channel_state, ChannelState::ChannelReady(_))); |
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.
Was there any resolution on this?
I rebased, but still haven't actually used the shared input. I can see that's now done in |
&shared_funding_output.script_pubkey, &funding_outputs, | ||
self.dual_funding_context.funding_feerate_sat_per_1000_weight, | ||
&self.funding_negotiation_context, | ||
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.
This None
needs to be the local_owned part of the shared input.
script_sig: ScriptBuf::new(), | ||
sequence: Sequence::ZERO, | ||
witness: Witness::new(), |
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.
Can just use ..Default::default()
here?
The splicing test fails, but when properly setting the parameters for |
Implementation of transaction negotiation during splicing.
Builds on 3407 and 3443.
No new phase,Funded(FundedChannel)
is used throughout splicingFundedChannel
andPendingV2Channel
can act as a transaction constructorPendingV2Channel
logic is put behind a trait --FundingTxConstructorV2
RenegotiatingScope
is used to store extra state during splicingFundingChannel
can act as aFundingTxConstructorV2
, using the state fromRenegotiatingScope
(if present)Since bothFundedChannel
andFundingTxConstructor
has context(), context accessors are extracted into a common base trait,ChannelContextProvider
(it is also shared byInitialRemoteCommitmentReceiver
).(Also relevant: #3444)