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

[4/?] - input+lnwallet: prepare input package for funding logic, add new MusigSession abstraction #7340

Conversation

Roasbeef
Copy link
Member

@Roasbeef Roasbeef commented Jan 19, 2023

Change Description

Depends on #7333 and #7331.

Only the last 3 commits are new. We'll also want to synchronize with #6974 as both the PRs update the deps to use the latest version of musig2.

In this PR, we first do a small refactoring to extract the musig2 session logic into a new package + struct. This allows use to re-use it later in tests w/o creating the entire wallet system.

Building on this, we then do some small prep to update the chanfunding package to be ready for the new musig2 channels.

The final change in this PR adds a new struct to encapsulate the new musig2 session logic for channels. A session can be created as soon as the verification nonce for the local party is known. At any time, we'll have two sessions: one for the remote commitment and one for the local commitment. A session can be finalized once the signing nonce (sent by the remote party) is known. When generating a signature, we'll use the remote party's verification nonce (the remote session), then generate a fresh nonce to complete the session. Similarly, when accepting a new state, we'll use the remote party's signing nonce to finalize the session, then verify the incoming signature.

For our local session, we'll use a counter-based system to generate the nonces we send to the remote party. The underlying counter here is the commitment height, which is then used by the existing shachain producer to generate fresh, but deterministic randomness. This lets us not have to store the secret nonce to disk, instead we'll just re-generate the nonce and use the sig we have on disk to combine, then create the final witness to broadcast.

The next PR in this series uses this PR, and its dependents to implement the funding logic within the wallet itself (reservations).

Steps to Test

Pull Request Checklist

Testing

  • Your PR passes all CI checks.
  • Tests covering the positive and negative (error paths) are included.
  • Bug fixes contain tests triggering the bug to prevent regressions.

Code Style and Documentation

📝 Please see our Contribution Guidelines for further guidance.

Copy link
Collaborator

@ellemouton ellemouton left a comment

Choose a reason for hiding this comment

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

First pass looks good! In my next pass I will spend more time understanding the details of the last commit

@saubyk saubyk requested a review from Crypt-iQ January 31, 2023 18:06
@saubyk saubyk modified the milestones: v0.16.0, v0.16.1 Feb 14, 2023
// FromWireSig maps a wire partial sig to this internal type that we'll use to
// perform signature validation.
func (p *MusigPartialSig) FromWireSig(sig *lnwire.PartialSigWithNonce,
) *MusigPartialSig {
Copy link
Member

Choose a reason for hiding this comment

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

nit: format

Copy link
Member Author

Choose a reason for hiding this comment

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

Gotta stamp something in the formatting guide here...

@saubyk saubyk modified the milestones: v0.16.1, v0.17.0 Mar 13, 2023
Copy link
Collaborator

@Crypt-iQ Crypt-iQ left a comment

Choose a reason for hiding this comment

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

Pretty straightforward, will have to see how it fits in with the other changes

@Roasbeef Roasbeef changed the base branch from master to simple-taproot-chans-scripts April 26, 2023 23:55
@Roasbeef Roasbeef force-pushed the simple-taproot-funding branch from 73baf9c to 8b3a3d6 Compare April 27, 2023 00:01
Copy link
Member

@yyforyongyu yyforyongyu left a comment

Choose a reason for hiding this comment

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

I think we are missing unit tests here, can help with it if needed.

@Roasbeef Roasbeef force-pushed the simple-taproot-chans-scripts branch from ff278d8 to d7ccdef Compare May 12, 2023 04:51
@Roasbeef Roasbeef force-pushed the simple-taproot-funding branch from 8b3a3d6 to 6fc2387 Compare May 12, 2023 20:40
@lightninglabs-deploy
Copy link

@Roasbeef, remember to re-request review from reviewers when ready

@Roasbeef Roasbeef changed the base branch from simple-taproot-chans-scripts to simple-taproot-chans-staging June 2, 2023 00:25
@Roasbeef Roasbeef force-pushed the simple-taproot-funding branch from 6fc2387 to 8819f71 Compare June 2, 2023 00:26
@Roasbeef
Copy link
Member Author

Roasbeef commented Jun 2, 2023

Initial set of review comment addressed. Will request review again after I put up the unit tests.

@Roasbeef Roasbeef force-pushed the simple-taproot-funding branch 3 times, most recently from 2be6b53 to eecba46 Compare June 2, 2023 23:37
@Roasbeef Roasbeef force-pushed the simple-taproot-funding branch 3 times, most recently from 083af6f to a8e8d06 Compare June 3, 2023 00:17
@Roasbeef Roasbeef force-pushed the simple-taproot-funding branch from a8e8d06 to 947096b Compare June 3, 2023 01:46
@Roasbeef
Copy link
Member Author

Roasbeef commented Jun 3, 2023

Unit tests added, PTAL!

nonceOpts := []musig2.NonceGenOption{
musig2.WithPublicKey(m.localKey.PubKey),
}
if opts.customRand != nil {
Copy link
Member

Choose a reason for hiding this comment

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

I think we should enforce the check to make sure nonce is not repeated?

Copy link
Member Author

Choose a reason for hiding this comment

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

Hmm, how would we go about that? The customRand func in this case will use the new shachain root to derive nonces, also we'll start to pass in the txhash being signed into the nonce gen to further bind it.

We only set the custom rand for our local commitment, which means we only sign with this nonce when we go to broadcast.

Here's the argument I posted elsewhere for why imo the current approach is sound:

  1. we only use that verification nonce to sign when we broadcast
  2. we only ever have a single transaction valid to broadcast
  3. after we sign and broadcast, we have that saved tx to rebroadcast, this tx never changes and we can't modify it (since we have another sig)
  4. leaking the nonce needs us to sign with that key w/ two diff messages, which itself would mean we're broadcasting a revoked state

Copy link
Member

Choose a reason for hiding this comment

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

What I meant was, we'd make sure the opts is always set for m.commitType == localCommit, so maybe we can return an error if opts.customRand == nil && m.commitType == localCommit.

Copy link
Member Author

Choose a reason for hiding this comment

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

By design it's meant to be an optional value though, we maintain similar control flow, but then allow the caller to specify this. I think a better area to add additional protections would be the channel state machine itself (part 6 in this series) where this is used.

This would also break the current test that exercises the "normal" random nonce paths.

@ellemouton ellemouton self-requested a review June 6, 2023 16:47
Copy link
Collaborator

@ellemouton ellemouton left a comment

Choose a reason for hiding this comment

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

I think this is close!

@Roasbeef Roasbeef force-pushed the simple-taproot-funding branch 2 times, most recently from 691ecd9 to d22a0f9 Compare June 8, 2023 00:07
Copy link
Member

@yyforyongyu yyforyongyu left a comment

Choose a reason for hiding this comment

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

This is good to go on my end once the redundant MuSig2Cleanup is handled.

nonceOpts := []musig2.NonceGenOption{
musig2.WithPublicKey(m.localKey.PubKey),
}
if opts.customRand != nil {
Copy link
Member

Choose a reason for hiding this comment

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

What I meant was, we'd make sure the opts is always set for m.commitType == localCommit, so maybe we can return an error if opts.customRand == nil && m.commitType == localCommit.


defer func() {
err := m.signer.MuSig2Cleanup(m.session.SessionID)
if err != nil {
Copy link
Member

Choose a reason for hiding this comment

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

I think MuSig2CombineSig will clean up the session so this will always return an error because the session is not found. Maybe we shouldn't do the auto cleanup in MuSig2CombineSig, or mention it in the method name or docs since it's error-prone.

Copy link
Member Author

Choose a reason for hiding this comment

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

Ah yeah good point, removed since it isn't necessary.

Initially I wanted to try to clean up the session as soon as possible, but realized that you need the session state present in order to do combine (so you can't clean up, then try to combine later the state won't be found). What I think we should do is add a defer CleanUp() in the link itself, so this way whenever we hang up the connection we remove the active session. We then also want to do this in the state machine after a round trip is complete.

I need to revisit the force close code in the final part of this PR, I think it ends up re-creating the session so it can properly force close.

Copy link
Collaborator

@ellemouton ellemouton left a comment

Choose a reason for hiding this comment

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

LGTM pending @yyforyongyu 's comment re the session clean up 🥕 ⚡

(some linter things remain that I assume will be addressed in a final clean up commit once all the others are also in)

Roasbeef added 6 commits June 8, 2023 17:16
In this commit, we extract the musig2 session management into a new
module. This allows us to re-use the session logic elsewhere in unit
tests so we don't need to instantiate the entire wallet.
In this commit, we update the set of intents and assemblers to recognize
musig2. For this change, we use a new bool, `musig2`, then use that to
determine if we need to use the new taproot funding scripts or not.
…tment state

In this commit, we add a series of abstractions that'll allow us to
easily do funding and also state updates for the new taproot channels. A
partial session is defined by the knowledge of a verification nonce.
Once the remote party sends a signature, we learn of their signing
nonce, and can then complete a session. By using a JIT nonce approach,
we ensure that the signer can generate their nonces randomly and also
at the very last step to avoid having to maintain state.

For our local nonces, we also have an option to use a counter based
nonce derived from the shachain instead of fully random nonces. This
allows us to not have to store ay additional state. Instead, when we
need to go to broadcast, we can just regenerate the nonce then use that
to broadcast.
In this commit, we eliminate some code duplication by removing the old
`HashMutex` struct as it just duplicates all the code with a different
type (uint64 and hash). We then make the main Mutex struct take a type
param, so the key can be parametrized when the struct is instantiated.
By using the multimutex here, we'll no longer rely on a single mutex for
the entire musig session set like we used to. Instead, we can use the
session ID to key into a map of mutexes and use those directly.
@Roasbeef Roasbeef force-pushed the simple-taproot-funding branch from d22a0f9 to 7c85f02 Compare June 9, 2023 00:20
@Roasbeef
Copy link
Member Author

Roasbeef commented Jun 9, 2023

(some linter things remain that I assume will be addressed in a final clean up commit once all the others are also in

Really been fighting the linter on this one...should be ✅ now with the latest push.

Copy link
Member

@yyforyongyu yyforyongyu left a comment

Choose a reason for hiding this comment

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

Really been fighting the linter on this one...

Attack on linter series𖠆

LGTM🎉🎉🎉

@Roasbeef Roasbeef merged commit a8dff96 into lightningnetwork:simple-taproot-chans-staging Jun 10, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
No open projects
Status: Done
Development

Successfully merging this pull request may close these issues.

8 participants