Skip to content
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

Replace use of HolderSignedTx with HolderCommitment #3664

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

wpaulino
Copy link
Contributor

As we move to a custom commitment transactions world, we'll no longer be able to rely on HolderSignedTx and should instead track the actual commitment transaction itself. This commit does so by introducing a new HolderCommitment struct, which we'll use as a replacement to HolderSignedTx to hold all relevant holder commitment data, including the HolderCommitmentTransaction, without data duplication.

Luckily, this is a backwards and forwards compatible change due to the OnchainTxHandler tracking the latest HolderCommitmentTransactions. In the future, we aim to remove them from the OnchainTxHandler entirely and begin storing them at the ChannelMonitor level.

Aside from how the data is represented internally, there shouldn't be any functional changes within this patch.

Depends on #3663.

@ldk-reviews-bot
Copy link

ldk-reviews-bot commented Mar 12, 2025

👋 Thanks for assigning @TheBlueMatt as a reviewer!
I'll wait for their review and will help manage the review process.
Once they submit their review, I'll check if a second reviewer would be helpful.

@wpaulino wpaulino added the weekly goal Someone wants to land this this week label Mar 12, 2025
@wpaulino wpaulino requested a review from TheBlueMatt March 12, 2025 17:41
@@ -3531,23 +3531,8 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
return Err(ChannelError::close(format!("Got wrong number of HTLC signatures ({}) from remote. It must be {}", msg.htlc_signatures.len(), commitment_stats.num_nondust_htlcs)));
}

// Up to LDK 0.0.115, HTLC information was required to be duplicated in the
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, did we fuck this up? Is there no way to indicate to old LDK to decline to decode the update now that its no longer actually compatible? At a minimum we need release notes but kinda annoying that we'll just silently corrupt state if a user downgrades to 0.0.115.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah... I think we would've needed to add an optional even TLV back then that only gets set when the sources are provided separately. Release notes will have to do for now.

if let Some(source) = source_opt.take() {
nondust_htlc_sources.push(source);
} else {
debug_assert!(false, "Missing outbound HTLC source");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should probably be a hard assert, right? And also probably we should change the types to avoid it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change the types on what? The source still needs to be optional in case the HTLC is not offered by the holder.

PackageSolvingData::HolderHTLCOutput(htlc_output),
counterparty_spendable_height,
);
claim_requests.push(htlc_package);
} else {
debug_assert!(false, "Expected transaction output index for non-dust HTLC");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ugh, we really need to change the types on htlc info so that we don't have these checks everywhere...if we're gonna separate tracking of dust from non-dust we should use different types...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, unfortunately there are still areas where we track them both together in a single Vec, so I don't think we can get there quite yet as of this PR.

writer.write_all(&[1; 1])?;
prev_holder_tx.write(writer)?;
HolderSignedTx::from(prev_holder_commitment).write(writer)?;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bleh, can we just implement a write_as_legacy?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to avoid the from magic? Because we still need that further below to make sure the HolderCommitmentTransaction we got from the OnchainTxHandler maps to the HolderSignedTx we read.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In all of those cases there's no reason we need to be cloning the HTLC vecs and sources. I'd really prefer to avoid that. Plus we also panic in the conversion while trying to check if the data we read was valid, which is generally something we try to avoid.

let holder_commitment = HolderCommitment::try_from((
current_holder_commitment_tx, &current_holder_signed_tx,
)).map_err(|_| DecodeError::InvalidValue)?;
if HolderSignedTx::from(&holder_commitment) != current_holder_signed_tx {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's gonna happen here? Are we just gonna keep writing the legacy versions and converting, or should we have some upgrade path?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was planning to address this in a follow-up PR that removes them from OnchainTxHandler such that we can no longer rely on getting them from there and instead store them as a new TLV in the monitor.

@ldk-reviews-bot
Copy link

👋 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.

@TheBlueMatt
Copy link
Collaborator

This does seem like the kind of thing that might want an 👋 upgrade test 👋

Copy link

codecov bot commented Mar 12, 2025

Codecov Report

Attention: Patch coverage is 90.09901% with 30 lines in your changes missing coverage. Please review.

Project coverage is 89.20%. Comparing base (030a784) to head (a891a04).

Files with missing lines Patch % Lines
lightning/src/chain/channelmonitor.rs 90.00% 18 Missing and 11 partials ⚠️
lightning/src/ln/channel.rs 88.88% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3664      +/-   ##
==========================================
- Coverage   89.25%   89.20%   -0.06%     
==========================================
  Files         155      155              
  Lines      119959   120054      +95     
  Branches   119959   120054      +95     
==========================================
+ Hits       107069   107090      +21     
- Misses      10276    10332      +56     
- Partials     2614     2632      +18     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@wpaulino
Copy link
Contributor Author

This does seem like the kind of thing that might want an 👋 upgrade test 👋

Will need to wait for #3584 first

@wpaulino wpaulino force-pushed the deprecate-holder-signed-tx branch from 2884bad to fdc1706 Compare March 12, 2025 23:04
@dunxen
Copy link
Contributor

dunxen commented Mar 17, 2025

Needs rebase.

@wpaulino wpaulino force-pushed the deprecate-holder-signed-tx branch from fdc1706 to 73f82fb Compare March 17, 2025 16:53
@wpaulino wpaulino requested review from jkczyz and TheBlueMatt March 17, 2025 17:03
Copy link
Contributor

@tankyleo tankyleo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Didn't make it through everything, some initial comments.

I'm also unclear how this helps with custom commitment transactions in particular ? Thanks for clarifying here.

Copy link
Contributor

@jkczyz jkczyz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Made it through everything. Nothing out of the ordinary pops out aside from what other reviewers have raised.

I'm also unclear how this helps with custom commitment transactions in particular ? Thanks for clarifying here.

Will let @wpaulino confirm, but IIUC prior to this PR we were only storing parts of the commitment transaction, so anything additional in a custom one would be missing.

@wpaulino wpaulino force-pushed the deprecate-holder-signed-tx branch from 73f82fb to 24dffdb Compare March 17, 2025 23:55
@wpaulino
Copy link
Contributor Author

IIUC prior to this PR we were only storing parts of the commitment transaction, so anything additional in a custom one would be missing.

Correct. We were already tracking the actual commitment transaction at the OnchainTxHandler, so HolderSignedTx was redundant. The plan is to move the commitment transaction storage from OnchainTxHandler -> ChannelMonitor.

@tankyleo
Copy link
Contributor

tankyleo commented Mar 18, 2025

IIUC prior to this PR we were only storing parts of the commitment transaction, so anything additional in a custom one would be missing.

Correct. We were already tracking the actual commitment transaction at the OnchainTxHandler, so HolderSignedTx was redundant. The plan is to move the commitment transaction storage from OnchainTxHandler -> ChannelMonitor.

Ok! From my side here's how I've been approaching custom transactions in channel monitor. Many details I haven't worked out yet but big picture:

  • While storing the fully built holder commitment transactions is ok as we only store two, we will likely not store all the previous counterparty commitment transactions (even custom ones), as the storage cost would be too high.
  • For this problem, me and Matt have been going for a roundtrip to some signer-like object to generate the claims.
  • ie "hey signer ! here's a commitment tx that confirmed, what can we claim out of this?"
  • this could work for all the counterparty transactions (revoked and non-revoked), and I've been making it work for holder transactions too.

Experimental API currently looks like this:

	/// Returns claims on a counterparty commitment transaction
	fn generate_claims_from_counterparty_tx(&self,
		per_commitment_point: &PublicKey,
		channel_parameters: &ChannelTransactionParameters,
		tx: &Transaction,
		per_commitment_claimable_data: &Vec<(HTLCOutputInCommitment, Option<Box<HTLCSource>>)>,
		payment_preimages: &HashMap<PaymentHash, (PaymentPreimage, Vec<PaymentClaimDetails>)>,
		secp_ctx: &Secp256k1<secp256k1::All>,
	) -> (Vec<PackageTemplate>, CommitmentTxCounterpartyOutputInfo);

	/// Returns claims on a counterparty's revoked commitment transaction
	fn generate_claims_from_revoked_tx(
		&self,
		per_commitment_key: &SecretKey,
		channel_parameters: &ChannelTransactionParameters,
		tx: &Transaction,
		per_commitment_claimable_data: &Vec<(HTLCOutputInCommitment, Option<Box<HTLCSource>>)>,
		height: u32,
		secp_ctx: &Secp256k1<secp256k1::All>,
	) -> (Vec<PackageTemplate>, CommitmentTxCounterpartyOutputInfo);

	/// Returns claims on a holder's commitment transaction
	fn generate_claims_from_holder_tx(
		&self,
		holder_tx: &HolderSignedTx,
		conf_height: u32,
		channel_parameters: &ChannelTransactionParameters,
		payment_preimages: &HashMap<PaymentHash, (PaymentPreimage, Vec<PaymentClaimDetails>)>,
		secp_ctx: &Secp256k1<secp256k1::All>,
	) -> Vec<PackageTemplate>;

What's missing:

  • When we force close, we want to generate claims even though our holder commit tx hasn't confirmed yet.
  • When we learn a preimage, we want to generate claims against already confirmed outputs.
  • Generate claims on htlc transactions.

Let me know if this syncs up with what you were thinking @wpaulino happy to chat here or elsewhere.

This branch here contains this API together with an implementation that passes the test suite:

https://github.com/tankyleo/rust-lightning/tree/check

Copy link
Contributor

@jkczyz jkczyz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM aside from pending discussions. Please re-request a review once those are resolved.

@wpaulino wpaulino requested a review from jkczyz March 18, 2025 17:01
@wpaulino
Copy link
Contributor Author

@tankyleo your proposal seems fine so far. The only change as a result of this PR would be to the function argument in generate_claims_from_holder_tx, we would've probably wanted to provide the HolderCommitmentTransaction there to begin with anyway. The rest is mostly unrelated to this change, so happy to chat about this work offline.

@tankyleo
Copy link
Contributor

The only change as a result of this PR would be to the function argument in generate_claims_from_holder_tx, we would've probably wanted to provide the HolderCommitmentTransaction there to begin with anyway.

Yes agreed

The rest is mostly unrelated to this change, so happy to chat about this work offline.

Sounds good

jkczyz
jkczyz previously approved these changes Mar 18, 2025
@TheBlueMatt TheBlueMatt removed their request for review March 18, 2025 19:13
@wpaulino wpaulino requested a review from TheBlueMatt March 24, 2025 22:37
@@ -3593,7 +3577,7 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {

Ok(LatestHolderCommitmentTXInfo {
commitment_tx: holder_commitment_tx,
htlc_outputs: htlcs_and_sigs,
htlc_outputs: dust_htlcs,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we rename this now that its something different?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might still have the old meaning when we read. Would you rather change it now anyway or wait until we know for sure we'll only ever find dust_htlcs?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe mostly_dust_htlcs? :). I mean we can certainly do it later, just seems easy for a bug to slip in because of a bad name.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rather defer it. I don't think a bug could happen where non-dust HTLCs are included because we still have code to support that, and the current name already assumed dust HTLCs must be included.

writer.write_all(&[1; 1])?;
prev_holder_tx.write(writer)?;
HolderSignedTx::from(prev_holder_commitment).write(writer)?;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In all of those cases there's no reason we need to be cloning the HTLC vecs and sources. I'd really prefer to avoid that. Plus we also panic in the conversion while trying to check if the data we read was valid, which is generally something we try to avoid.

Currently, non-dust HTLCs are duplicated across the commitment
transaction itself, and the full set of HTLCs (dust & non-dust) along
with their `HTLCSource` considered in the commitment transaction. As of
v0.0.15, we've had support for providing non-dust HTLC sources
separately such that we no longer track duplicate non-dust HTLC data,
but only enabled it under testing environments. This commit enables it
such that it always happens.

Note that we still need to support reading
`ChannelMonitorUpdateStep::LatestHolderCommitmentTXInfo` updates that
did not separate the non-dust HTLC sources in case they were written in
an older version and they've yet to be processed.
@wpaulino wpaulino force-pushed the deprecate-holder-signed-tx branch from 41d9463 to 7f626c8 Compare March 25, 2025 17:03
@wpaulino
Copy link
Contributor Author

Had to rebase due to a conflict with #3606 and implemented write_as_legacy.

@wpaulino wpaulino requested a review from TheBlueMatt March 25, 2025 17:05
As we move to a custom commitment transactions world, we'll no longer be
able to rely on `HolderSignedTx` and should instead track the actual
commitment transaction itself. This commit does so by introducing a new
`HolderCommitment` struct, which we'll use as a replacement to
`HolderSignedTx` to hold all relevant holder commitment data, including
the `HolderCommitmentTransaction`, without data duplication.

Luckily, this is a backwards and forwards compatible change due to the
`OnchainTxHandler` tracking the latest `HolderCommitmentTransaction`s.
In the future, we aim to remove them from the `OnchainTxHandler`
entirely and begin storing them at the `ChannelMonitor` level.

Aside from how the data is represented internally, there shouldn't be
any functional changes within this patch.
@wpaulino wpaulino force-pushed the deprecate-holder-signed-tx branch from 7f626c8 to a891a04 Compare March 25, 2025 22:31
@wpaulino wpaulino requested a review from TheBlueMatt March 25, 2025 22:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
weekly goal Someone wants to land this this week
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants