Skip to content

Commit 8a7167a

Browse files
Roasbeefguggero
authored andcommitted
funding+lnwallet: finish hook up new aux funding flow
For the initiator, once we get the signal that the PSBT has been finalized, we'll call into the aux funder to get the funding desc. For the responder, once we receive the funding_created message, we'll do the same. We now also have local+remote aux leaves for the commitment transaction.
1 parent 078f756 commit 8a7167a

File tree

5 files changed

+220
-48
lines changed

5 files changed

+220
-48
lines changed

funding/aux_funding.go

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package funding
22

33
import (
44
"github.com/btcsuite/btcd/chaincfg/chainhash"
5+
"github.com/lightningnetwork/lnd/channeldb"
56
"github.com/lightningnetwork/lnd/fn"
67
"github.com/lightningnetwork/lnd/lnwallet"
78
"github.com/lightningnetwork/lnd/protofsm"
@@ -17,16 +18,46 @@ type AuxFundingController interface {
1718
// handle custom messages specific to the funding type.
1819
protofsm.MsgEndpoint
1920

20-
// DescPendingChanID takes a pending channel ID, that may already be
21+
// DescFromPendingChanID takes a pending channel ID, that may already be
2122
// known due to prior custom channel messages, and maybe returns an aux
2223
// funding desc which can be used to modify how a channel is funded.
23-
//
24-
// TODO(roasbeef): erorr on validation if fail due to invalid root
25-
// match?
26-
DescFromPendingChanID(PendingChanID) fn.Option[lnwallet.AuxFundingDesc]
24+
DescFromPendingChanID(pid PendingChanID,
25+
openChan *channeldb.OpenChannel,
26+
localKeyRing, remoteKeyRing lnwallet.CommitmentKeyRing,
27+
initiator bool) (fn.Option[lnwallet.AuxFundingDesc], error)
2728

2829
// DeriveTapscriptRoot takes a pending channel ID and maybe returns a
2930
// tapscript root that should be used when creating any musig2 sessions
3031
// for a channel.
31-
DeriveTapscriptRoot(PendingChanID) fn.Option[chainhash.Hash]
32+
DeriveTapscriptRoot(PendingChanID) (fn.Option[chainhash.Hash], error)
33+
}
34+
35+
// descFromPendingChanID takes a pending channel ID, that may already be
36+
// known due to prior custom channel messages, and maybe returns an aux
37+
// funding desc which can be used to modify how a channel is funded.
38+
func descFromPendingChanID(controller fn.Option[AuxFundingController],
39+
chanID PendingChanID, openChan *channeldb.OpenChannel,
40+
localKeyRing, remoteKeyRing lnwallet.CommitmentKeyRing,
41+
initiator bool) (fn.Option[lnwallet.AuxFundingDesc], error) {
42+
43+
if controller.IsNone() {
44+
return fn.None[lnwallet.AuxFundingDesc](), nil
45+
}
46+
47+
return controller.UnsafeFromSome().DescFromPendingChanID(
48+
chanID, openChan, localKeyRing, remoteKeyRing, initiator,
49+
)
50+
}
51+
52+
// deriveTapscriptRoot takes a pending channel ID and maybe returns a
53+
// tapscript root that should be used when creating any musig2 sessions
54+
// for a channel.
55+
func deriveTapscriptRoot(controller fn.Option[AuxFundingController],
56+
chanID PendingChanID) (fn.Option[chainhash.Hash], error) {
57+
58+
if controller.IsNone() {
59+
return fn.None[chainhash.Hash](), nil
60+
}
61+
62+
return controller.UnsafeFromSome().DeriveTapscriptRoot(chanID)
3263
}

funding/manager.go

Lines changed: 61 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,6 @@ const (
9999
// you and limitless channel size (apart from 21 million cap).
100100
MaxBtcFundingAmountWumbo = btcutil.Amount(1000000000)
101101

102-
// TODO(roasbeef): tune.
103102
msgBufferSize = 50
104103

105104
// MaxWaitNumBlocksFundingConf is the maximum number of blocks to wait
@@ -1622,11 +1621,14 @@ func (f *Manager) fundeeProcessOpenChannel(peer lnpeer.Peer,
16221621
// At this point, if we have an AuxFundingController active, we'll
16231622
// check to see if we have a special tapscript root to use in our
16241623
// musig2 funding output.
1625-
tapscriptRoot := fn.MapOption(
1626-
func(a AuxFundingController) fn.Option[chainhash.Hash] {
1627-
return a.DeriveTapscriptRoot(msg.PendingChannelID)
1628-
},
1629-
)(f.cfg.AuxFundingController)
1624+
tapscriptRoot, err := deriveTapscriptRoot(
1625+
f.cfg.AuxFundingController, msg.PendingChannelID,
1626+
)
1627+
if err != nil {
1628+
err = fmt.Errorf("error deriving tapscript root: %w", err)
1629+
log.Error(err)
1630+
f.failFundingFlow(peer, cid, err)
1631+
}
16301632

16311633
req := &lnwallet.InitFundingReserveMsg{
16321634
ChainHash: &msg.ChainHash,
@@ -1644,7 +1646,7 @@ func (f *Manager) fundeeProcessOpenChannel(peer lnpeer.Peer,
16441646
ZeroConf: zeroConf,
16451647
OptionScidAlias: scid,
16461648
ScidAliasFeature: scidFeatureVal,
1647-
TapscriptRoot: fn.FlattenOption(tapscriptRoot),
1649+
TapscriptRoot: tapscriptRoot,
16481650
}
16491651

16501652
reservation, err := f.cfg.Wallet.InitChannelReservation(req)
@@ -2241,10 +2243,27 @@ func (f *Manager) waitForPsbt(intent *chanfunding.PsbtIntent,
22412243
return
22422244
}
22432245

2246+
// At this point, we'll see if there's an AuxFundingDesc we
2247+
// need to deliver so the funding process can continue
2248+
// properly.
2249+
chanState := resCtx.reservation.ChanState()
2250+
localKeys, remoteKeys := resCtx.reservation.CommitmentKeyRings()
2251+
auxFundingDesc, err := descFromPendingChanID(
2252+
f.cfg.AuxFundingController, cid.tempChanID, chanState,
2253+
*localKeys, *remoteKeys, true,
2254+
)
2255+
if err != nil {
2256+
failFlow("error continuing PSBT flow", err)
2257+
return
2258+
}
2259+
22442260
// A non-nil error means we can continue the funding flow.
22452261
// Notify the wallet so it can prepare everything we need to
22462262
// continue.
2247-
err = resCtx.reservation.ProcessPsbt()
2263+
//
2264+
// We'll also pass along the aux funding controller as well,
2265+
// which may be used to help process the finalized PSBT.
2266+
err = resCtx.reservation.ProcessPsbt(auxFundingDesc)
22482267
if err != nil {
22492268
failFlow("error continuing PSBT flow", err)
22502269
return
@@ -2253,8 +2272,8 @@ func (f *Manager) waitForPsbt(intent *chanfunding.PsbtIntent,
22532272
// We are now ready to continue the funding flow.
22542273
f.continueFundingAccept(resCtx, cid)
22552274

2256-
// Handle a server shutdown as well because the reservation won't
2257-
// survive a restart as it's in memory only.
2275+
// Handle a server shutdown as well because the reservation won't
2276+
// survive a restart as it's in memory only.
22582277
case <-f.quit:
22592278
log.Errorf("Unable to handle funding accept message "+
22602279
"for peer_key=%x, pending_chan_id=%x: funding manager "+
@@ -2308,6 +2327,10 @@ func (f *Manager) continueFundingAccept(resCtx *reservationWithCtx,
23082327
// funding flow fails.
23092328
cid.setChanID(channelID)
23102329

2330+
// Now that we're ready to resume the funding flow, we'll call into the
2331+
// aux controller with the final funding details so we can obtain the
2332+
// funding descs we need.
2333+
23112334
// Send the FundingCreated msg.
23122335
fundingCreated := &lnwire.FundingCreated{
23132336
PendingChannelID: cid.tempChanID,
@@ -2370,7 +2393,6 @@ func (f *Manager) fundeeProcessFundingCreated(peer lnpeer.Peer,
23702393
// final funding transaction, as well as a signature for our version of
23712394
// the commitment transaction. So at this point, we can validate the
23722395
// initiator's commitment transaction, then send our own if it's valid.
2373-
// TODO(roasbeef): make case (p vs P) consistent throughout
23742396
fundingOut := msg.FundingPoint
23752397
log.Infof("completing pending_id(%x) with ChannelPoint(%v)",
23762398
pendingChanID[:], fundingOut)
@@ -2402,16 +2424,33 @@ func (f *Manager) fundeeProcessFundingCreated(peer lnpeer.Peer,
24022424
}
24032425
}
24042426

2427+
// At this point, we'll see if there's an AuxFundingDesc we need to
2428+
// deliver so the funding process can continue properly.
2429+
chanState := resCtx.reservation.ChanState()
2430+
localKeys, remoteKeys := resCtx.reservation.CommitmentKeyRings()
2431+
auxFundingDesc, err := descFromPendingChanID(
2432+
f.cfg.AuxFundingController, cid.tempChanID, chanState,
2433+
*localKeys, *remoteKeys, true,
2434+
)
2435+
if err != nil {
2436+
log.Errorf("error continuing PSBT flow: %v", err)
2437+
f.failFundingFlow(peer, cid, err)
2438+
return
2439+
}
2440+
24052441
// With all the necessary data available, attempt to advance the
24062442
// funding workflow to the next stage. If this succeeds then the
24072443
// funding transaction will broadcast after our next message.
24082444
// CompleteReservationSingle will also mark the channel as 'IsPending'
24092445
// in the database.
2446+
//
2447+
// We'll also directly pass in the AuxFundiner controller as well,
2448+
// which may be used by the reservation system to finalize funding our
2449+
// side.
24102450
completeChan, err := resCtx.reservation.CompleteReservationSingle(
2411-
&fundingOut, commitSig,
2451+
&fundingOut, commitSig, auxFundingDesc,
24122452
)
24132453
if err != nil {
2414-
// TODO(roasbeef): better error logging: peerID, channelID, etc.
24152454
log.Errorf("unable to complete single reservation: %v", err)
24162455
f.failFundingFlow(peer, cid, err)
24172456
return
@@ -2722,9 +2761,6 @@ func (f *Manager) funderProcessFundingSigned(peer lnpeer.Peer,
27222761

27232762
// Send an update to the upstream client that the negotiation process
27242763
// is over.
2725-
//
2726-
// TODO(roasbeef): add abstraction over updates to accommodate
2727-
// long-polling, or SSE, etc.
27282764
upd := &lnrpc.OpenStatusUpdate{
27292765
Update: &lnrpc.OpenStatusUpdate_ChanPending{
27302766
ChanPending: &lnrpc.PendingUpdate{
@@ -4429,7 +4465,6 @@ func (f *Manager) announceChannel(localIDKey, remoteIDKey *btcec.PublicKey,
44294465

44304466
// InitFundingWorkflow sends a message to the funding manager instructing it
44314467
// to initiate a single funder workflow with the source peer.
4432-
// TODO(roasbeef): re-visit blocking nature..
44334468
func (f *Manager) InitFundingWorkflow(msg *InitFundingMsg) {
44344469
f.fundingRequests <- msg
44354470
}
@@ -4622,11 +4657,14 @@ func (f *Manager) handleInitFundingMsg(msg *InitFundingMsg) {
46224657
// At this point, if we have an AuxFundingController active, we'll
46234658
// check to see if we have a special tapscript root to use in our
46244659
// musig2 funding output.
4625-
tapscriptRoot := fn.MapOption(
4626-
func(a AuxFundingController) fn.Option[chainhash.Hash] {
4627-
return a.DeriveTapscriptRoot(chanID)
4628-
},
4629-
)(f.cfg.AuxFundingController)
4660+
tapscriptRoot, err := deriveTapscriptRoot(
4661+
f.cfg.AuxFundingController, chanID,
4662+
)
4663+
if err != nil {
4664+
err = fmt.Errorf("error deriving tapscript root: %w", err)
4665+
msg.Err <- err
4666+
return
4667+
}
46304668

46314669
req := &lnwallet.InitFundingReserveMsg{
46324670
ChainHash: &msg.ChainHash,
@@ -4651,7 +4689,7 @@ func (f *Manager) handleInitFundingMsg(msg *InitFundingMsg) {
46514689
OptionScidAlias: scid,
46524690
ScidAliasFeature: scidFeatureVal,
46534691
Memo: msg.Memo,
4654-
TapscriptRoot: fn.FlattenOption(tapscriptRoot),
4692+
TapscriptRoot: tapscriptRoot,
46554693
}
46564694

46574695
reservation, err := f.cfg.Wallet.InitChannelReservation(req)

lnwallet/reservation.go

Lines changed: 48 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -218,10 +218,14 @@ type ChannelReservation struct {
218218

219219
fundingIntent chanfunding.Intent
220220

221-
// initAuxLeaves is an optional set of aux commitment leaves that'll
222-
// modify the way we construct the commitment transaction, in
221+
// localInitAuxLeaves is an optional set of aux commitment leaves
222+
// that'll modify the way we construct the commitment transaction, in
223223
// particular the tapscript leaves.
224-
initAuxLeaves fn.Option[CommitAuxLeaves]
224+
localInitAuxLeaves fn.Option[CommitAuxLeaves]
225+
226+
// remoteInitAuxLeaves is an optional set of aux commitment leaves for
227+
// the remote party.
228+
remoteInitAuxLeaves fn.Option[CommitAuxLeaves]
225229

226230
// nextRevocationKeyLoc stores the key locator information for this
227231
// channel.
@@ -608,12 +612,15 @@ func (r *ChannelReservation) IsCannedShim() bool {
608612
}
609613

610614
// ProcessPsbt continues a previously paused funding flow that involves PSBT to
611-
// construct the funding transaction. This method can be called once the PSBT is
612-
// finalized and the signed transaction is available.
613-
func (r *ChannelReservation) ProcessPsbt() error {
615+
// construct the funding transaction. This method can be called once the PSBT
616+
// is finalized and the signed transaction is available.
617+
func (r *ChannelReservation) ProcessPsbt(
618+
auxFundingDesc fn.Option[AuxFundingDesc]) error {
619+
614620
errChan := make(chan error, 1)
615621

616622
r.wallet.msgChan <- &continueContributionMsg{
623+
auxFundingDesc: auxFundingDesc,
617624
pendingFundingID: r.reservationID,
618625
err: errChan,
619626
}
@@ -715,8 +722,10 @@ func (r *ChannelReservation) CompleteReservation(fundingInputScripts []*input.Sc
715722
// available via the .OurSignatures() method. As this method should only be
716723
// called as a response to a single funder channel, only a commitment signature
717724
// will be populated.
718-
func (r *ChannelReservation) CompleteReservationSingle(fundingPoint *wire.OutPoint,
719-
commitSig input.Signature) (*channeldb.OpenChannel, error) {
725+
func (r *ChannelReservation) CompleteReservationSingle(
726+
fundingPoint *wire.OutPoint, commitSig input.Signature,
727+
auxFundingDesc fn.Option[AuxFundingDesc],
728+
) (*channeldb.OpenChannel, error) {
720729

721730
errChan := make(chan error, 1)
722731
completeChan := make(chan *channeldb.OpenChannel, 1)
@@ -726,6 +735,7 @@ func (r *ChannelReservation) CompleteReservationSingle(fundingPoint *wire.OutPoi
726735
fundingOutpoint: fundingPoint,
727736
theirCommitmentSig: commitSig,
728737
completeChan: completeChan,
738+
auxFundingDesc: auxFundingDesc,
729739
err: errChan,
730740
}
731741

@@ -811,6 +821,36 @@ func (r *ChannelReservation) Cancel() error {
811821
return <-errChan
812822
}
813823

824+
// ChanState the current open channel state.
825+
func (r *ChannelReservation) ChanState() *channeldb.OpenChannel {
826+
r.RLock()
827+
defer r.RUnlock()
828+
return r.partialState
829+
}
830+
831+
// CommitmentKeyRings returns the local+remote key ring used for the very first
832+
// commitment transaction both parties.
833+
func (r *ChannelReservation) CommitmentKeyRings() (*CommitmentKeyRing, *CommitmentKeyRing) {
834+
r.RLock()
835+
defer r.RUnlock()
836+
837+
chanType := r.partialState.ChanType
838+
ourChanCfg := r.ourContribution.ChannelConfig
839+
theirChanCfg := r.theirContribution.ChannelConfig
840+
841+
localKeys := DeriveCommitmentKeys(
842+
r.ourContribution.FirstCommitmentPoint, true, chanType,
843+
ourChanCfg, theirChanCfg,
844+
)
845+
846+
remoteKeys := DeriveCommitmentKeys(
847+
r.theirContribution.FirstCommitmentPoint, false, chanType,
848+
ourChanCfg, theirChanCfg,
849+
)
850+
851+
return localKeys, remoteKeys
852+
}
853+
814854
// VerifyConstraints is a helper function that can be used to check the sanity
815855
// of various channel constraints.
816856
func VerifyConstraints(c *channeldb.ChannelConstraints,

lnwallet/test/test_interface.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import (
3434
"github.com/lightningnetwork/lnd/chainntnfs"
3535
"github.com/lightningnetwork/lnd/chainntnfs/btcdnotify"
3636
"github.com/lightningnetwork/lnd/channeldb"
37+
"github.com/lightningnetwork/lnd/fn"
3738
"github.com/lightningnetwork/lnd/input"
3839
"github.com/lightningnetwork/lnd/keychain"
3940
"github.com/lightningnetwork/lnd/kvdb"
@@ -936,6 +937,7 @@ func testSingleFunderReservationWorkflow(miner *rpctest.Harness,
936937
fundingPoint := aliceChanReservation.FundingOutpoint()
937938
_, err = bobChanReservation.CompleteReservationSingle(
938939
fundingPoint, aliceCommitSig,
940+
fn.None[lnwallet.AuxFundingDesc](),
939941
)
940942
require.NoError(t, err, "bob unable to consume single reservation")
941943

0 commit comments

Comments
 (0)