mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-09-05 17:05:50 +02:00
Merge pull request #9072 from lightningnetwork/extract-part3-from-staging-branch
[custom channels 3/5]: Extract PART3 from mega staging branch
This commit is contained in:
@@ -99,7 +99,6 @@ const (
|
||||
// you and limitless channel size (apart from 21 million cap).
|
||||
MaxBtcFundingAmountWumbo = btcutil.Amount(1000000000)
|
||||
|
||||
// TODO(roasbeef): tune.
|
||||
msgBufferSize = 50
|
||||
|
||||
// MaxWaitNumBlocksFundingConf is the maximum number of blocks to wait
|
||||
@@ -549,6 +548,16 @@ type Config struct {
|
||||
// AuxLeafStore is an optional store that can be used to store auxiliary
|
||||
// leaves for certain custom channel types.
|
||||
AuxLeafStore fn.Option[lnwallet.AuxLeafStore]
|
||||
|
||||
// AuxFundingController is an optional controller that can be used to
|
||||
// modify the way we handle certain custom channel types. It's also
|
||||
// able to automatically handle new custom protocol messages related to
|
||||
// the funding process.
|
||||
AuxFundingController fn.Option[AuxFundingController]
|
||||
|
||||
// AuxSigner is an optional signer that can be used to sign auxiliary
|
||||
// leaves for certain custom channel types.
|
||||
AuxSigner fn.Option[lnwallet.AuxSigner]
|
||||
}
|
||||
|
||||
// Manager acts as an orchestrator/bridge between the wallet's
|
||||
@@ -1078,6 +1087,9 @@ func (f *Manager) advanceFundingState(channel *channeldb.OpenChannel,
|
||||
f.cfg.AuxLeafStore.WhenSome(func(s lnwallet.AuxLeafStore) {
|
||||
chanOpts = append(chanOpts, lnwallet.WithLeafStore(s))
|
||||
})
|
||||
f.cfg.AuxSigner.WhenSome(func(s lnwallet.AuxSigner) {
|
||||
chanOpts = append(chanOpts, lnwallet.WithAuxSigner(s))
|
||||
})
|
||||
|
||||
// We create the state-machine object which wraps the database state.
|
||||
lnChannel, err := lnwallet.NewLightningChannel(
|
||||
@@ -1256,8 +1268,8 @@ func (f *Manager) stateStep(channel *channeldb.OpenChannel,
|
||||
|
||||
// advancePendingChannelState waits for a pending channel's funding tx to
|
||||
// confirm, and marks it open in the database when that happens.
|
||||
func (f *Manager) advancePendingChannelState(
|
||||
channel *channeldb.OpenChannel, pendingChanID PendingChanID) error {
|
||||
func (f *Manager) advancePendingChannelState(channel *channeldb.OpenChannel,
|
||||
pendingChanID PendingChanID) error {
|
||||
|
||||
if channel.IsZeroConf() {
|
||||
// Persist the alias to the alias database.
|
||||
@@ -1626,6 +1638,23 @@ func (f *Manager) fundeeProcessOpenChannel(peer lnpeer.Peer,
|
||||
return
|
||||
}
|
||||
|
||||
// At this point, if we have an AuxFundingController active, we'll
|
||||
// check to see if we have a special tapscript root to use in our
|
||||
// MuSig funding output.
|
||||
tapscriptRoot, err := fn.MapOptionZ(
|
||||
f.cfg.AuxFundingController,
|
||||
func(c AuxFundingController) AuxTapscriptResult {
|
||||
return c.DeriveTapscriptRoot(msg.PendingChannelID)
|
||||
},
|
||||
).Unpack()
|
||||
if err != nil {
|
||||
err = fmt.Errorf("error deriving tapscript root: %w", err)
|
||||
log.Error(err)
|
||||
f.failFundingFlow(peer, cid, err)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
req := &lnwallet.InitFundingReserveMsg{
|
||||
ChainHash: &msg.ChainHash,
|
||||
PendingChanID: msg.PendingChannelID,
|
||||
@@ -1642,6 +1671,7 @@ func (f *Manager) fundeeProcessOpenChannel(peer lnpeer.Peer,
|
||||
ZeroConf: zeroConf,
|
||||
OptionScidAlias: scid,
|
||||
ScidAliasFeature: scidFeatureVal,
|
||||
TapscriptRoot: tapscriptRoot,
|
||||
}
|
||||
|
||||
reservation, err := f.cfg.Wallet.InitChannelReservation(req)
|
||||
@@ -1898,6 +1928,8 @@ func (f *Manager) fundeeProcessOpenChannel(peer lnpeer.Peer,
|
||||
log.Debugf("Remote party accepted commitment rendering params: %v",
|
||||
lnutils.SpewLogClosure(params))
|
||||
|
||||
reservation.SetState(lnwallet.SentAcceptChannel)
|
||||
|
||||
// With the initiator's contribution recorded, respond with our
|
||||
// contribution in the next message of the workflow.
|
||||
fundingAccept := lnwire.AcceptChannel{
|
||||
@@ -1958,6 +1990,10 @@ func (f *Manager) funderProcessAcceptChannel(peer lnpeer.Peer,
|
||||
// Update the timestamp once the fundingAcceptMsg has been handled.
|
||||
defer resCtx.updateTimestamp()
|
||||
|
||||
if resCtx.reservation.State() != lnwallet.SentOpenChannel {
|
||||
return
|
||||
}
|
||||
|
||||
log.Infof("Recv'd fundingResponse for pending_id(%x)",
|
||||
pendingChanID[:])
|
||||
|
||||
@@ -2261,10 +2297,34 @@ func (f *Manager) waitForPsbt(intent *chanfunding.PsbtIntent,
|
||||
return
|
||||
}
|
||||
|
||||
// At this point, we'll see if there's an AuxFundingDesc we
|
||||
// need to deliver so the funding process can continue
|
||||
// properly.
|
||||
auxFundingDesc, err := fn.MapOptionZ(
|
||||
f.cfg.AuxFundingController,
|
||||
func(c AuxFundingController) AuxFundingDescResult {
|
||||
return c.DescFromPendingChanID(
|
||||
cid.tempChanID,
|
||||
lnwallet.NewAuxChanState(
|
||||
resCtx.reservation.ChanState(),
|
||||
),
|
||||
resCtx.reservation.CommitmentKeyRings(),
|
||||
true,
|
||||
)
|
||||
},
|
||||
).Unpack()
|
||||
if err != nil {
|
||||
failFlow("error continuing PSBT flow", err)
|
||||
return
|
||||
}
|
||||
|
||||
// A non-nil error means we can continue the funding flow.
|
||||
// Notify the wallet so it can prepare everything we need to
|
||||
// continue.
|
||||
err = resCtx.reservation.ProcessPsbt()
|
||||
//
|
||||
// We'll also pass along the aux funding controller as well,
|
||||
// which may be used to help process the finalized PSBT.
|
||||
err = resCtx.reservation.ProcessPsbt(auxFundingDesc)
|
||||
if err != nil {
|
||||
failFlow("error continuing PSBT flow", err)
|
||||
return
|
||||
@@ -2359,6 +2419,8 @@ func (f *Manager) continueFundingAccept(resCtx *reservationWithCtx,
|
||||
}
|
||||
}
|
||||
|
||||
resCtx.reservation.SetState(lnwallet.SentFundingCreated)
|
||||
|
||||
if err := resCtx.peer.SendMessage(true, fundingCreated); err != nil {
|
||||
log.Errorf("Unable to send funding complete message: %v", err)
|
||||
f.failFundingFlow(resCtx.peer, cid, err)
|
||||
@@ -2390,11 +2452,14 @@ func (f *Manager) fundeeProcessFundingCreated(peer lnpeer.Peer,
|
||||
// final funding transaction, as well as a signature for our version of
|
||||
// the commitment transaction. So at this point, we can validate the
|
||||
// initiator's commitment transaction, then send our own if it's valid.
|
||||
// TODO(roasbeef): make case (p vs P) consistent throughout
|
||||
fundingOut := msg.FundingPoint
|
||||
log.Infof("completing pending_id(%x) with ChannelPoint(%v)",
|
||||
pendingChanID[:], fundingOut)
|
||||
|
||||
if resCtx.reservation.State() != lnwallet.SentAcceptChannel {
|
||||
return
|
||||
}
|
||||
|
||||
// Create the channel identifier without setting the active channel ID.
|
||||
cid := newChanIdentifier(pendingChanID)
|
||||
|
||||
@@ -2422,16 +2487,38 @@ func (f *Manager) fundeeProcessFundingCreated(peer lnpeer.Peer,
|
||||
}
|
||||
}
|
||||
|
||||
// At this point, we'll see if there's an AuxFundingDesc we need to
|
||||
// deliver so the funding process can continue properly.
|
||||
auxFundingDesc, err := fn.MapOptionZ(
|
||||
f.cfg.AuxFundingController,
|
||||
func(c AuxFundingController) AuxFundingDescResult {
|
||||
return c.DescFromPendingChanID(
|
||||
cid.tempChanID, lnwallet.NewAuxChanState(
|
||||
resCtx.reservation.ChanState(),
|
||||
), resCtx.reservation.CommitmentKeyRings(),
|
||||
true,
|
||||
)
|
||||
},
|
||||
).Unpack()
|
||||
if err != nil {
|
||||
log.Errorf("error continuing PSBT flow: %v", err)
|
||||
f.failFundingFlow(peer, cid, err)
|
||||
return
|
||||
}
|
||||
|
||||
// With all the necessary data available, attempt to advance the
|
||||
// funding workflow to the next stage. If this succeeds then the
|
||||
// funding transaction will broadcast after our next message.
|
||||
// CompleteReservationSingle will also mark the channel as 'IsPending'
|
||||
// in the database.
|
||||
//
|
||||
// We'll also directly pass in the AuxFunding controller as well,
|
||||
// which may be used by the reservation system to finalize funding our
|
||||
// side.
|
||||
completeChan, err := resCtx.reservation.CompleteReservationSingle(
|
||||
&fundingOut, commitSig,
|
||||
&fundingOut, commitSig, auxFundingDesc,
|
||||
)
|
||||
if err != nil {
|
||||
// TODO(roasbeef): better error logging: peerID, channelID, etc.
|
||||
log.Errorf("unable to complete single reservation: %v", err)
|
||||
f.failFundingFlow(peer, cid, err)
|
||||
return
|
||||
@@ -2632,6 +2719,14 @@ func (f *Manager) funderProcessFundingSigned(peer lnpeer.Peer,
|
||||
return
|
||||
}
|
||||
|
||||
if resCtx.reservation.State() != lnwallet.SentFundingCreated {
|
||||
err := fmt.Errorf("unable to find reservation for chan_id=%x",
|
||||
msg.ChanID)
|
||||
f.failFundingFlow(peer, cid, err)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Create an entry in the local discovery map so we can ensure that we
|
||||
// process the channel confirmation fully before we receive a
|
||||
// channel_ready message.
|
||||
@@ -2727,6 +2822,21 @@ func (f *Manager) funderProcessFundingSigned(peer lnpeer.Peer,
|
||||
}
|
||||
}
|
||||
|
||||
// Before we proceed, if we have a funding hook that wants a
|
||||
// notification that it's safe to broadcast the funding transaction,
|
||||
// then we'll send that now.
|
||||
err = fn.MapOptionZ(
|
||||
f.cfg.AuxFundingController,
|
||||
func(controller AuxFundingController) error {
|
||||
return controller.ChannelFinalized(cid.tempChanID)
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
log.Errorf("Failed to inform aux funding controller about "+
|
||||
"ChannelPoint(%v) being finalized: %v", fundingPoint,
|
||||
err)
|
||||
}
|
||||
|
||||
// Now that we have a finalized reservation for this funding flow,
|
||||
// we'll send the to be active channel to the ChainArbitrator so it can
|
||||
// watch for any on-chain actions before the channel has fully
|
||||
@@ -2742,9 +2852,6 @@ func (f *Manager) funderProcessFundingSigned(peer lnpeer.Peer,
|
||||
|
||||
// Send an update to the upstream client that the negotiation process
|
||||
// is over.
|
||||
//
|
||||
// TODO(roasbeef): add abstraction over updates to accommodate
|
||||
// long-polling, or SSE, etc.
|
||||
upd := &lnrpc.OpenStatusUpdate{
|
||||
Update: &lnrpc.OpenStatusUpdate_ChanPending{
|
||||
ChanPending: &lnrpc.PendingUpdate{
|
||||
@@ -3450,6 +3557,7 @@ func (f *Manager) addToGraph(completeChan *channeldb.OpenChannel,
|
||||
errChan := f.cfg.SendAnnouncement(
|
||||
ann.chanAnn, discovery.ChannelCapacity(completeChan.Capacity),
|
||||
discovery.ChannelPoint(completeChan.FundingOutpoint),
|
||||
discovery.TapscriptRoot(completeChan.TapscriptRoot),
|
||||
)
|
||||
select {
|
||||
case err := <-errChan:
|
||||
@@ -3646,7 +3754,7 @@ func (f *Manager) annAfterSixConfs(completeChan *channeldb.OpenChannel,
|
||||
|
||||
// waitForZeroConfChannel is called when the state is addedToGraph with
|
||||
// a zero-conf channel. This will wait for the real confirmation, add the
|
||||
// confirmed SCID to the graph, and then announce after six confs.
|
||||
// confirmed SCID to the router graph, and then announce after six confs.
|
||||
func (f *Manager) waitForZeroConfChannel(c *channeldb.OpenChannel) error {
|
||||
// First we'll check whether the channel is confirmed on-chain. If it
|
||||
// is already confirmed, the chainntnfs subsystem will return with the
|
||||
@@ -3977,6 +4085,26 @@ func (f *Manager) handleChannelReady(peer lnpeer.Peer, //nolint:funlen
|
||||
PubNonce: remoteNonce,
|
||||
}),
|
||||
)
|
||||
|
||||
// Inform the aux funding controller that the liquidity in the
|
||||
// custom channel is now ready to be advertised. We potentially
|
||||
// haven't sent our own channel ready message yet, but other
|
||||
// than that the channel is ready to count toward available
|
||||
// liquidity.
|
||||
err = fn.MapOptionZ(
|
||||
f.cfg.AuxFundingController,
|
||||
func(controller AuxFundingController) error {
|
||||
return controller.ChannelReady(
|
||||
lnwallet.NewAuxChanState(channel),
|
||||
)
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
cid := newChanIdentifier(msg.ChanID)
|
||||
f.sendWarning(peer, cid, err)
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// The channel_ready message contains the next commitment point we'll
|
||||
@@ -4063,6 +4191,19 @@ func (f *Manager) handleChannelReadyReceived(channel *channeldb.OpenChannel,
|
||||
log.Debugf("Channel(%v) with ShortChanID %v: successfully "+
|
||||
"added to graph", chanID, scid)
|
||||
|
||||
err = fn.MapOptionZ(
|
||||
f.cfg.AuxFundingController,
|
||||
func(controller AuxFundingController) error {
|
||||
return controller.ChannelReady(
|
||||
lnwallet.NewAuxChanState(channel),
|
||||
)
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed notifying aux funding controller "+
|
||||
"about channel ready: %w", err)
|
||||
}
|
||||
|
||||
// Give the caller a final update notifying them that the channel is
|
||||
fundingPoint := channel.FundingOutpoint
|
||||
cp := &lnrpc.ChannelPoint{
|
||||
@@ -4376,9 +4517,9 @@ func (f *Manager) announceChannel(localIDKey, remoteIDKey *btcec.PublicKey,
|
||||
//
|
||||
// We can pass in zeroes for the min and max htlc policy, because we
|
||||
// only use the channel announcement message from the returned struct.
|
||||
ann, err := f.newChanAnnouncement(localIDKey, remoteIDKey,
|
||||
localFundingKey, remoteFundingKey, shortChanID, chanID,
|
||||
0, 0, nil, chanType,
|
||||
ann, err := f.newChanAnnouncement(
|
||||
localIDKey, remoteIDKey, localFundingKey, remoteFundingKey,
|
||||
shortChanID, chanID, 0, 0, nil, chanType,
|
||||
)
|
||||
if err != nil {
|
||||
log.Errorf("can't generate channel announcement: %v", err)
|
||||
@@ -4444,7 +4585,6 @@ func (f *Manager) announceChannel(localIDKey, remoteIDKey *btcec.PublicKey,
|
||||
|
||||
// InitFundingWorkflow sends a message to the funding manager instructing it
|
||||
// to initiate a single funder workflow with the source peer.
|
||||
// TODO(roasbeef): re-visit blocking nature..
|
||||
func (f *Manager) InitFundingWorkflow(msg *InitFundingMsg) {
|
||||
f.fundingRequests <- msg
|
||||
}
|
||||
@@ -4634,6 +4774,23 @@ func (f *Manager) handleInitFundingMsg(msg *InitFundingMsg) {
|
||||
scidFeatureVal = true
|
||||
}
|
||||
|
||||
// At this point, if we have an AuxFundingController active, we'll check
|
||||
// to see if we have a special tapscript root to use in our MuSig2
|
||||
// funding output.
|
||||
tapscriptRoot, err := fn.MapOptionZ(
|
||||
f.cfg.AuxFundingController,
|
||||
func(c AuxFundingController) AuxTapscriptResult {
|
||||
return c.DeriveTapscriptRoot(chanID)
|
||||
},
|
||||
).Unpack()
|
||||
if err != nil {
|
||||
err = fmt.Errorf("error deriving tapscript root: %w", err)
|
||||
log.Error(err)
|
||||
msg.Err <- err
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
req := &lnwallet.InitFundingReserveMsg{
|
||||
ChainHash: &msg.ChainHash,
|
||||
PendingChanID: chanID,
|
||||
@@ -4673,6 +4830,7 @@ func (f *Manager) handleInitFundingMsg(msg *InitFundingMsg) {
|
||||
OptionScidAlias: scid,
|
||||
ScidAliasFeature: scidFeatureVal,
|
||||
Memo: msg.Memo,
|
||||
TapscriptRoot: tapscriptRoot,
|
||||
}
|
||||
|
||||
reservation, err := f.cfg.Wallet.InitChannelReservation(req)
|
||||
@@ -4824,6 +4982,8 @@ func (f *Manager) handleInitFundingMsg(msg *InitFundingMsg) {
|
||||
log.Infof("Starting funding workflow with %v for pending_id(%x), "+
|
||||
"committype=%v", msg.Peer.Address(), chanID, commitType)
|
||||
|
||||
reservation.SetState(lnwallet.SentOpenChannel)
|
||||
|
||||
fundingOpen := lnwire.OpenChannel{
|
||||
ChainHash: *f.cfg.Wallet.Cfg.NetParams.GenesisHash,
|
||||
PendingChannelID: chanID,
|
||||
|
Reference in New Issue
Block a user