mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-01-18 13:27:56 +01:00
funding+peer: add support for new musig2 channel funding flow
In this commit, we add support for the new musig2 channel funding flow. This flow is identical to the existing flow, but not both sides need to exchange local nonces up front, and then signatures sent are now partial signatures instead of regular signatures. The funding manager also gains some new state of the local nonces it needs to generate in order to send the funding locked message, and also process the funding locked message from the remote party. In order to allow the funding manger to generate the nonces that need to be applied to each channel, then AddNewChannel method has been modified to accept a set of options that the peer will then use to bind the nonces to a new channel.
This commit is contained in:
parent
a8416300dd
commit
15978a8691
@ -7,7 +7,6 @@ import (
|
|||||||
|
|
||||||
"github.com/btcsuite/btcd/btcec/v2"
|
"github.com/btcsuite/btcd/btcec/v2"
|
||||||
"github.com/btcsuite/btcd/wire"
|
"github.com/btcsuite/btcd/wire"
|
||||||
"github.com/lightningnetwork/lnd/channeldb"
|
|
||||||
"github.com/lightningnetwork/lnd/lnpeer"
|
"github.com/lightningnetwork/lnd/lnpeer"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
)
|
)
|
||||||
@ -42,7 +41,9 @@ func (p *mockPeer) SendMessageLazy(sync bool, msgs ...lnwire.Message) error {
|
|||||||
return p.SendMessage(sync, msgs...)
|
return p.SendMessage(sync, msgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *mockPeer) AddNewChannel(_ *channeldb.OpenChannel, _ <-chan struct{}) error {
|
func (p *mockPeer) AddNewChannel(_ *lnpeer.NewChannel,
|
||||||
|
_ <-chan struct{}) error {
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
func (p *mockPeer) WipeChannel(_ *wire.OutPoint) {}
|
func (p *mockPeer) WipeChannel(_ *wire.OutPoint) {}
|
||||||
|
@ -10,6 +10,7 @@ import (
|
|||||||
|
|
||||||
"github.com/btcsuite/btcd/btcec/v2"
|
"github.com/btcsuite/btcd/btcec/v2"
|
||||||
"github.com/btcsuite/btcd/btcec/v2/ecdsa"
|
"github.com/btcsuite/btcd/btcec/v2/ecdsa"
|
||||||
|
"github.com/btcsuite/btcd/btcec/v2/schnorr/musig2"
|
||||||
"github.com/btcsuite/btcd/btcutil"
|
"github.com/btcsuite/btcd/btcutil"
|
||||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||||
"github.com/btcsuite/btcd/txscript"
|
"github.com/btcsuite/btcd/txscript"
|
||||||
@ -574,6 +575,17 @@ type Manager struct {
|
|||||||
nonceMtx sync.RWMutex
|
nonceMtx sync.RWMutex
|
||||||
chanIDNonce uint64
|
chanIDNonce uint64
|
||||||
|
|
||||||
|
// pendingMusigNonces is used to store the musig2 nonce we generate to
|
||||||
|
// send funding locked until we receive a funding locked message from
|
||||||
|
// the remote party. We'll use this to keep track of the nonce we
|
||||||
|
// generated, so we send the local+remote nonces to the peer state
|
||||||
|
// machine.
|
||||||
|
//
|
||||||
|
// NOTE: This map is protected by the nonceMtx above.
|
||||||
|
//
|
||||||
|
// TODO(roasbeef): replace w/ generic concurrent map
|
||||||
|
pendingMusigNonces map[lnwire.ChannelID]*musig2.Nonces
|
||||||
|
|
||||||
// activeReservations is a map which houses the state of all pending
|
// activeReservations is a map which houses the state of all pending
|
||||||
// funding workflows.
|
// funding workflows.
|
||||||
activeReservations map[serializedPubKey]pendingChannels
|
activeReservations map[serializedPubKey]pendingChannels
|
||||||
@ -674,6 +686,9 @@ func NewFundingManager(cfg Config) (*Manager, error) {
|
|||||||
handleChannelReadyBarriers: &lnutils.SyncMap[
|
handleChannelReadyBarriers: &lnutils.SyncMap[
|
||||||
lnwire.ChannelID, struct{},
|
lnwire.ChannelID, struct{},
|
||||||
]{},
|
]{},
|
||||||
|
pendingMusigNonces: make(
|
||||||
|
map[lnwire.ChannelID]*musig2.Nonces,
|
||||||
|
),
|
||||||
quit: make(chan struct{}),
|
quit: make(chan struct{}),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
@ -1504,15 +1519,25 @@ func (f *Manager) handleFundingOpen(peer lnpeer.Peer,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public := msg.ChannelFlags&lnwire.FFAnnounceChannel != 0
|
||||||
|
switch {
|
||||||
// Sending the option-scid-alias channel type for a public channel is
|
// Sending the option-scid-alias channel type for a public channel is
|
||||||
// disallowed.
|
// disallowed.
|
||||||
public := msg.ChannelFlags&lnwire.FFAnnounceChannel != 0
|
case public && scid:
|
||||||
if public && scid {
|
|
||||||
err = fmt.Errorf("option-scid-alias chantype for public " +
|
err = fmt.Errorf("option-scid-alias chantype for public " +
|
||||||
"channel")
|
"channel")
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
f.failFundingFlow(peer, cid, err)
|
f.failFundingFlow(peer, cid, err)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
// The current variant of taproot channels can only be used with
|
||||||
|
// unadvertised channels for now.
|
||||||
|
case commitType.IsTaproot() && public:
|
||||||
|
err = fmt.Errorf("taproot channel type for public channel")
|
||||||
|
log.Error(err)
|
||||||
|
f.failFundingFlow(peer, cid, err)
|
||||||
|
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
req := &lnwallet.InitFundingReserveMsg{
|
req := &lnwallet.InitFundingReserveMsg{
|
||||||
@ -1749,6 +1774,22 @@ func (f *Manager) handleFundingOpen(peer lnpeer.Peer,
|
|||||||
},
|
},
|
||||||
UpfrontShutdown: msg.UpfrontShutdownScript,
|
UpfrontShutdown: msg.UpfrontShutdownScript,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if resCtx.reservation.IsTaproot() {
|
||||||
|
if msg.LocalNonce == nil {
|
||||||
|
err := fmt.Errorf("local nonce not set for taproot " +
|
||||||
|
"chan")
|
||||||
|
log.Error(err)
|
||||||
|
f.failFundingFlow(
|
||||||
|
resCtx.peer, cid, err,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
remoteContribution.LocalNonce = &musig2.Nonces{
|
||||||
|
PubNonce: *msg.LocalNonce,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
err = reservation.ProcessSingleContribution(remoteContribution)
|
err = reservation.ProcessSingleContribution(remoteContribution)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("unable to add contribution reservation: %v", err)
|
log.Errorf("unable to add contribution reservation: %v", err)
|
||||||
@ -1761,6 +1802,13 @@ func (f *Manager) handleFundingOpen(peer lnpeer.Peer,
|
|||||||
log.Debugf("Remote party accepted commitment constraints: %v",
|
log.Debugf("Remote party accepted commitment constraints: %v",
|
||||||
spew.Sdump(remoteContribution.ChannelConfig.ChannelConstraints))
|
spew.Sdump(remoteContribution.ChannelConfig.ChannelConstraints))
|
||||||
|
|
||||||
|
var localNonce *lnwire.Musig2Nonce
|
||||||
|
if commitType.IsTaproot() {
|
||||||
|
localNonce = (*lnwire.Musig2Nonce)(
|
||||||
|
&ourContribution.LocalNonce.PubNonce,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// With the initiator's contribution recorded, respond with our
|
// With the initiator's contribution recorded, respond with our
|
||||||
// contribution in the next message of the workflow.
|
// contribution in the next message of the workflow.
|
||||||
fundingAccept := lnwire.AcceptChannel{
|
fundingAccept := lnwire.AcceptChannel{
|
||||||
@ -1781,6 +1829,7 @@ func (f *Manager) handleFundingOpen(peer lnpeer.Peer,
|
|||||||
UpfrontShutdownScript: ourContribution.UpfrontShutdown,
|
UpfrontShutdownScript: ourContribution.UpfrontShutdown,
|
||||||
ChannelType: chanType,
|
ChannelType: chanType,
|
||||||
LeaseExpiry: msg.LeaseExpiry,
|
LeaseExpiry: msg.LeaseExpiry,
|
||||||
|
LocalNonce: localNonce,
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := peer.SendMessage(true, &fundingAccept); err != nil {
|
if err := peer.SendMessage(true, &fundingAccept); err != nil {
|
||||||
@ -1966,6 +2015,20 @@ func (f *Manager) handleFundingAccept(peer lnpeer.Peer,
|
|||||||
},
|
},
|
||||||
UpfrontShutdown: msg.UpfrontShutdownScript,
|
UpfrontShutdown: msg.UpfrontShutdownScript,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if resCtx.reservation.IsTaproot() {
|
||||||
|
if msg.LocalNonce == nil {
|
||||||
|
err := fmt.Errorf("local nonce not set for taproot " +
|
||||||
|
"chan")
|
||||||
|
log.Error(err)
|
||||||
|
f.failFundingFlow(resCtx.peer, cid, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
remoteContribution.LocalNonce = &musig2.Nonces{
|
||||||
|
PubNonce: *msg.LocalNonce,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
err = resCtx.reservation.ProcessContribution(remoteContribution)
|
err = resCtx.reservation.ProcessContribution(remoteContribution)
|
||||||
|
|
||||||
// The wallet has detected that a PSBT funding process was requested by
|
// The wallet has detected that a PSBT funding process was requested by
|
||||||
@ -2160,12 +2223,30 @@ func (f *Manager) continueFundingAccept(resCtx *reservationWithCtx,
|
|||||||
PendingChannelID: cid.tempChanID,
|
PendingChannelID: cid.tempChanID,
|
||||||
FundingPoint: *outPoint,
|
FundingPoint: *outPoint,
|
||||||
}
|
}
|
||||||
fundingCreated.CommitSig, err = lnwire.NewSigFromSignature(sig)
|
|
||||||
if err != nil {
|
// If this is a taproot channel, then we'll need to populate the musig2
|
||||||
log.Errorf("Unable to parse signature: %v", err)
|
// partial sig field instead of the regular commit sig field.
|
||||||
f.failFundingFlow(resCtx.peer, cid, err)
|
if resCtx.reservation.IsTaproot() {
|
||||||
return
|
partialSig, ok := sig.(*lnwallet.MusigPartialSig)
|
||||||
|
if !ok {
|
||||||
|
err := fmt.Errorf("expected musig partial sig, got %T",
|
||||||
|
sig)
|
||||||
|
log.Error(err)
|
||||||
|
f.failFundingFlow(resCtx.peer, cid, err)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fundingCreated.PartialSig = partialSig.ToWireSig()
|
||||||
|
} else {
|
||||||
|
fundingCreated.CommitSig, err = lnwire.NewSigFromSignature(sig)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Unable to parse signature: %v", err)
|
||||||
|
f.failFundingFlow(resCtx.peer, cid, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := resCtx.peer.SendMessage(true, fundingCreated); err != nil {
|
if err := resCtx.peer.SendMessage(true, fundingCreated); err != nil {
|
||||||
log.Errorf("Unable to send funding complete message: %v", err)
|
log.Errorf("Unable to send funding complete message: %v", err)
|
||||||
f.failFundingFlow(resCtx.peer, cid, err)
|
f.failFundingFlow(resCtx.peer, cid, err)
|
||||||
@ -2202,11 +2283,27 @@ func (f *Manager) handleFundingCreated(peer lnpeer.Peer,
|
|||||||
// Create the channel identifier without setting the active channel ID.
|
// Create the channel identifier without setting the active channel ID.
|
||||||
cid := newChanIdentifier(pendingChanID)
|
cid := newChanIdentifier(pendingChanID)
|
||||||
|
|
||||||
commitSig, err := msg.CommitSig.ToSignature()
|
// For taproot channels, the commit signature is actually the partial
|
||||||
if err != nil {
|
// signature. Otherwise, we can convert the ECDSA commit signature into
|
||||||
log.Errorf("unable to parse signature: %v", err)
|
// our internal input.Signature type.
|
||||||
f.failFundingFlow(peer, cid, err)
|
var commitSig input.Signature
|
||||||
return
|
if resCtx.reservation.IsTaproot() {
|
||||||
|
if msg.PartialSig == nil {
|
||||||
|
log.Errorf("partial sig not included: %v", err)
|
||||||
|
f.failFundingFlow(peer, cid, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
commitSig = new(lnwallet.MusigPartialSig).FromWireSig(
|
||||||
|
msg.PartialSig,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
commitSig, err = msg.CommitSig.ToSignature()
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("unable to parse signature: %v", err)
|
||||||
|
f.failFundingFlow(peer, cid, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// With all the necessary data available, attempt to advance the
|
// With all the necessary data available, attempt to advance the
|
||||||
@ -2266,18 +2363,33 @@ func (f *Manager) handleFundingCreated(peer lnpeer.Peer,
|
|||||||
log.Debugf("Creating chan barrier for ChanID(%v)", channelID)
|
log.Debugf("Creating chan barrier for ChanID(%v)", channelID)
|
||||||
f.newChanBarriers.Store(channelID, make(chan struct{}))
|
f.newChanBarriers.Store(channelID, make(chan struct{}))
|
||||||
|
|
||||||
log.Infof("sending FundingSigned for pending_id(%x) over "+
|
fundingSigned := &lnwire.FundingSigned{}
|
||||||
"ChannelPoint(%v)", pendingChanID[:], fundingOut)
|
|
||||||
|
|
||||||
// With their signature for our version of the commitment transaction
|
// For taproot channels, we'll need to send over a partial signature
|
||||||
// verified, we can now send over our signature to the remote peer.
|
// that includes the nonce along side the signature.
|
||||||
_, sig := resCtx.reservation.OurSignatures()
|
_, sig := resCtx.reservation.OurSignatures()
|
||||||
ourCommitSig, err := lnwire.NewSigFromSignature(sig)
|
if resCtx.reservation.IsTaproot() {
|
||||||
if err != nil {
|
partialSig, ok := sig.(*lnwallet.MusigPartialSig)
|
||||||
log.Errorf("unable to parse signature: %v", err)
|
if !ok {
|
||||||
f.failFundingFlow(peer, cid, err)
|
err := fmt.Errorf("expected musig partial sig, got %T",
|
||||||
deleteFromDatabase()
|
sig)
|
||||||
return
|
log.Error(err)
|
||||||
|
f.failFundingFlow(resCtx.peer, cid, err)
|
||||||
|
deleteFromDatabase()
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fundingSigned.PartialSig = partialSig.ToWireSig()
|
||||||
|
} else {
|
||||||
|
fundingSigned.CommitSig, err = lnwire.NewSigFromSignature(sig)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("unable to parse signature: %v", err)
|
||||||
|
f.failFundingFlow(peer, cid, err)
|
||||||
|
deleteFromDatabase()
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Before sending FundingSigned, we notify Brontide first to keep track
|
// Before sending FundingSigned, we notify Brontide first to keep track
|
||||||
@ -2293,10 +2405,13 @@ func (f *Manager) handleFundingCreated(peer lnpeer.Peer,
|
|||||||
// funding flow fails.
|
// funding flow fails.
|
||||||
cid.setChanID(channelID)
|
cid.setChanID(channelID)
|
||||||
|
|
||||||
fundingSigned := &lnwire.FundingSigned{
|
fundingSigned.ChanID = cid.chanID
|
||||||
ChanID: cid.chanID,
|
|
||||||
CommitSig: ourCommitSig,
|
log.Infof("sending FundingSigned for pending_id(%x) over "+
|
||||||
}
|
"ChannelPoint(%v)", pendingChanID[:], fundingOut)
|
||||||
|
|
||||||
|
// With their signature for our version of the commitment transaction
|
||||||
|
// verified, we can now send over our signature to the remote peer.
|
||||||
if err := peer.SendMessage(true, fundingSigned); err != nil {
|
if err := peer.SendMessage(true, fundingSigned); err != nil {
|
||||||
log.Errorf("unable to send FundingSigned message: %v", err)
|
log.Errorf("unable to send FundingSigned message: %v", err)
|
||||||
f.failFundingFlow(peer, cid, err)
|
f.failFundingFlow(peer, cid, err)
|
||||||
@ -2417,14 +2532,27 @@ func (f *Manager) handleFundingSigned(peer lnpeer.Peer,
|
|||||||
log.Errorf("Unable to store the forwarding policy: %v", err)
|
log.Errorf("Unable to store the forwarding policy: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// The remote peer has responded with a signature for our commitment
|
// For taproot channels, the commit signature is actually the partial
|
||||||
// transaction. We'll verify the signature for validity, then commit
|
// signature. Otherwise, we can convert the ECDSA commit signature into
|
||||||
// the state to disk as we can now open the channel.
|
// our internal input.Signature type.
|
||||||
commitSig, err := msg.CommitSig.ToSignature()
|
var commitSig input.Signature
|
||||||
if err != nil {
|
if resCtx.reservation.IsTaproot() {
|
||||||
log.Errorf("Unable to parse signature: %v", err)
|
if msg.PartialSig == nil {
|
||||||
f.failFundingFlow(peer, cid, err)
|
log.Errorf("partial sig not included: %v", err)
|
||||||
return
|
f.failFundingFlow(peer, cid, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
commitSig = new(lnwallet.MusigPartialSig).FromWireSig(
|
||||||
|
msg.PartialSig,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
commitSig, err = msg.CommitSig.ToSignature()
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("unable to parse signature: %v", err)
|
||||||
|
f.failFundingFlow(peer, cid, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
completeChan, err := resCtx.reservation.CompleteReservation(
|
completeChan, err := resCtx.reservation.CompleteReservation(
|
||||||
@ -2657,10 +2785,24 @@ func (f *Manager) waitForFundingWithTimeout(
|
|||||||
// makeFundingScript re-creates the funding script for the funding transaction
|
// makeFundingScript re-creates the funding script for the funding transaction
|
||||||
// of the target channel.
|
// of the target channel.
|
||||||
func makeFundingScript(channel *channeldb.OpenChannel) ([]byte, error) {
|
func makeFundingScript(channel *channeldb.OpenChannel) ([]byte, error) {
|
||||||
localKey := channel.LocalChanCfg.MultiSigKey.PubKey.SerializeCompressed()
|
localKey := channel.LocalChanCfg.MultiSigKey.PubKey
|
||||||
remoteKey := channel.RemoteChanCfg.MultiSigKey.PubKey.SerializeCompressed()
|
remoteKey := channel.RemoteChanCfg.MultiSigKey.PubKey
|
||||||
|
|
||||||
multiSigScript, err := input.GenMultiSigScript(localKey, remoteKey)
|
if channel.ChanType.IsTaproot() {
|
||||||
|
pkScript, _, err := input.GenTaprootFundingScript(
|
||||||
|
localKey, remoteKey, int64(channel.Capacity),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return pkScript, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
multiSigScript, err := input.GenMultiSigScript(
|
||||||
|
localKey.SerializeCompressed(),
|
||||||
|
remoteKey.SerializeCompressed(),
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -2956,6 +3098,38 @@ func (f *Manager) sendChannelReady(completeChan *channeldb.OpenChannel,
|
|||||||
}
|
}
|
||||||
channelReadyMsg := lnwire.NewChannelReady(chanID, nextRevocation)
|
channelReadyMsg := lnwire.NewChannelReady(chanID, nextRevocation)
|
||||||
|
|
||||||
|
// If this is a taproot channel, then we also need to send along our
|
||||||
|
// set of musig2 nonces as well.
|
||||||
|
if completeChan.ChanType.IsTaproot() {
|
||||||
|
log.Infof("ChanID(%v): generating musig2 nonces...",
|
||||||
|
chanID)
|
||||||
|
|
||||||
|
f.nonceMtx.Lock()
|
||||||
|
localNonce, ok := f.pendingMusigNonces[chanID]
|
||||||
|
if !ok {
|
||||||
|
// If we don't have any nonces generated yet for this
|
||||||
|
// first state, then we'll generate them now and stow
|
||||||
|
// them away. When we receive the funding locked
|
||||||
|
// message, we'll then pass along this same set of
|
||||||
|
// nonces.
|
||||||
|
newNonce, err := channel.GenMusigNonces()
|
||||||
|
if err != nil {
|
||||||
|
f.nonceMtx.Unlock()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now that we've generated the nonce for this channel,
|
||||||
|
// we'll store it in the set of pending nonces.
|
||||||
|
localNonce = newNonce
|
||||||
|
f.pendingMusigNonces[chanID] = localNonce
|
||||||
|
}
|
||||||
|
f.nonceMtx.Unlock()
|
||||||
|
|
||||||
|
channelReadyMsg.NextLocalNonce = (*lnwire.Musig2Nonce)(
|
||||||
|
&localNonce.PubNonce,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// If the channel negotiated the option-scid-alias feature bit, we'll
|
// If the channel negotiated the option-scid-alias feature bit, we'll
|
||||||
// send a TLV segment that includes an alias the peer can use in their
|
// send a TLV segment that includes an alias the peer can use in their
|
||||||
// invoice hop hints. We'll send the first alias we find for the
|
// invoice hop hints. We'll send the first alias we find for the
|
||||||
@ -3145,6 +3319,7 @@ func (f *Manager) addToRouterGraph(completeChan *channeldb.OpenChannel,
|
|||||||
&completeChan.LocalChanCfg.MultiSigKey,
|
&completeChan.LocalChanCfg.MultiSigKey,
|
||||||
completeChan.RemoteChanCfg.MultiSigKey.PubKey, *shortChanID,
|
completeChan.RemoteChanCfg.MultiSigKey.PubKey, *shortChanID,
|
||||||
chanID, fwdMinHTLC, fwdMaxHTLC, ourPolicy,
|
chanID, fwdMinHTLC, fwdMaxHTLC, ourPolicy,
|
||||||
|
completeChan.ChanType,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error generating channel "+
|
return fmt.Errorf("error generating channel "+
|
||||||
@ -3336,7 +3511,7 @@ func (f *Manager) annAfterSixConfs(completeChan *channeldb.OpenChannel,
|
|||||||
f.cfg.IDKey, completeChan.IdentityPub,
|
f.cfg.IDKey, completeChan.IdentityPub,
|
||||||
&completeChan.LocalChanCfg.MultiSigKey,
|
&completeChan.LocalChanCfg.MultiSigKey,
|
||||||
completeChan.RemoteChanCfg.MultiSigKey.PubKey,
|
completeChan.RemoteChanCfg.MultiSigKey.PubKey,
|
||||||
*shortChanID, chanID,
|
*shortChanID, chanID, completeChan.ChanType,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("channel announcement failed: %w",
|
return fmt.Errorf("channel announcement failed: %w",
|
||||||
@ -3440,6 +3615,35 @@ func (f *Manager) waitForZeroConfChannel(c *channeldb.OpenChannel,
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// genFirstStateMusigNonce generates a nonces for the "first" local state. This
|
||||||
|
// is the verification nonce for the state created for us after the initial
|
||||||
|
// commitment transaction signed as part of the funding flow.
|
||||||
|
func genFirstStateMusigNonce(channel *channeldb.OpenChannel,
|
||||||
|
) (*musig2.Nonces, error) {
|
||||||
|
|
||||||
|
musig2ShaChain, err := channeldb.DeriveMusig2Shachain(
|
||||||
|
channel.RevocationProducer,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("unable to generate musig channel "+
|
||||||
|
"nonces: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// We use the _next_ commitment height here as we need to generate the
|
||||||
|
// nonce for the next state the remote party will sign for us.
|
||||||
|
verNonce, err := channeldb.NewMusigVerificationNonce(
|
||||||
|
channel.LocalChanCfg.MultiSigKey.PubKey,
|
||||||
|
channel.LocalCommitment.CommitHeight+1,
|
||||||
|
musig2ShaChain,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("unable to generate musig channel "+
|
||||||
|
"nonces: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return verNonce, nil
|
||||||
|
}
|
||||||
|
|
||||||
// handleChannelReady finalizes the channel funding process and enables the
|
// handleChannelReady finalizes the channel funding process and enables the
|
||||||
// channel to enter normal operating mode.
|
// channel to enter normal operating mode.
|
||||||
func (f *Manager) handleChannelReady(peer lnpeer.Peer,
|
func (f *Manager) handleChannelReady(peer lnpeer.Peer,
|
||||||
@ -3517,6 +3721,17 @@ func (f *Manager) handleChannelReady(peer lnpeer.Peer,
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If this is a taproot channel, then we can generate the set of nonces
|
||||||
|
// the remote party needs to send the next remote commitment here.
|
||||||
|
var firstVerNonce *musig2.Nonces
|
||||||
|
if channel.ChanType.IsTaproot() {
|
||||||
|
firstVerNonce, err = genFirstStateMusigNonce(channel)
|
||||||
|
if err != nil {
|
||||||
|
log.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// We'll need to store the received TLV alias if the option_scid_alias
|
// We'll need to store the received TLV alias if the option_scid_alias
|
||||||
// feature was negotiated. This will be used to provide route hints
|
// feature was negotiated. This will be used to provide route hints
|
||||||
// during invoice creation. In the zero-conf case, it is also used to
|
// during invoice creation. In the zero-conf case, it is also used to
|
||||||
@ -3580,6 +3795,14 @@ func (f *Manager) handleChannelReady(peer lnpeer.Peer,
|
|||||||
)
|
)
|
||||||
channelReadyMsg.AliasScid = &alias
|
channelReadyMsg.AliasScid = &alias
|
||||||
|
|
||||||
|
if firstVerNonce != nil {
|
||||||
|
wireNonce := (*lnwire.Musig2Nonce)(
|
||||||
|
&firstVerNonce.PubNonce,
|
||||||
|
)
|
||||||
|
|
||||||
|
channelReadyMsg.NextLocalNonce = wireNonce
|
||||||
|
}
|
||||||
|
|
||||||
err = peer.SendMessage(true, channelReadyMsg)
|
err = peer.SendMessage(true, channelReadyMsg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("unable to send channel_ready: %v",
|
log.Errorf("unable to send channel_ready: %v",
|
||||||
@ -3604,6 +3827,38 @@ func (f *Manager) handleChannelReady(peer lnpeer.Peer,
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If this is a taproot channel, then we'll need to map the received
|
||||||
|
// nonces to a nonce pair, and also fetch our pending nonces, which are
|
||||||
|
// required in order to make the channel whole.
|
||||||
|
var chanOpts []lnwallet.ChannelOpt
|
||||||
|
if channel.ChanType.IsTaproot() {
|
||||||
|
f.nonceMtx.Lock()
|
||||||
|
localNonce, ok := f.pendingMusigNonces[chanID]
|
||||||
|
if !ok {
|
||||||
|
// If there's no pending nonce for this channel ID,
|
||||||
|
// we'll use the one generatd above.
|
||||||
|
localNonce = firstVerNonce
|
||||||
|
f.pendingMusigNonces[chanID] = firstVerNonce
|
||||||
|
}
|
||||||
|
f.nonceMtx.Unlock()
|
||||||
|
|
||||||
|
log.Infof("ChanID(%v): applying local+remote musig2 nonces",
|
||||||
|
chanID)
|
||||||
|
|
||||||
|
if msg.NextLocalNonce == nil {
|
||||||
|
log.Errorf("remote nonces are nil")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
chanOpts = append(
|
||||||
|
chanOpts,
|
||||||
|
lnwallet.WithLocalMusigNonces(localNonce),
|
||||||
|
lnwallet.WithRemoteMusigNonces(&musig2.Nonces{
|
||||||
|
PubNonce: *msg.NextLocalNonce,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// The channel_ready message contains the next commitment point we'll
|
// The channel_ready message contains the next commitment point we'll
|
||||||
// need to create the next commitment state for the remote party. So
|
// need to create the next commitment state for the remote party. So
|
||||||
// we'll insert that into the channel now before passing it along to
|
// we'll insert that into the channel now before passing it along to
|
||||||
@ -3635,7 +3890,11 @@ func (f *Manager) handleChannelReady(peer lnpeer.Peer,
|
|||||||
err)
|
err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := peer.AddNewChannel(channel, f.quit); err != nil {
|
err = peer.AddNewChannel(&lnpeer.NewChannel{
|
||||||
|
OpenChannel: channel,
|
||||||
|
ChanOpts: chanOpts,
|
||||||
|
}, f.quit)
|
||||||
|
if err != nil {
|
||||||
log.Errorf("Unable to add new channel %v with peer %x: %v",
|
log.Errorf("Unable to add new channel %v with peer %x: %v",
|
||||||
channel.FundingOutpoint,
|
channel.FundingOutpoint,
|
||||||
peer.IdentityKey().SerializeCompressed(), err,
|
peer.IdentityKey().SerializeCompressed(), err,
|
||||||
@ -3654,6 +3913,12 @@ func (f *Manager) handleChannelReadyReceived(channel *channeldb.OpenChannel,
|
|||||||
|
|
||||||
chanID := lnwire.NewChanIDFromOutPoint(&channel.FundingOutpoint)
|
chanID := lnwire.NewChanIDFromOutPoint(&channel.FundingOutpoint)
|
||||||
|
|
||||||
|
// Since we've sent+received funding locked at this point, we
|
||||||
|
// can clean up the pending musig2 nonce state.
|
||||||
|
f.nonceMtx.Lock()
|
||||||
|
delete(f.pendingMusigNonces, chanID)
|
||||||
|
f.nonceMtx.Unlock()
|
||||||
|
|
||||||
var peerAlias *lnwire.ShortChannelID
|
var peerAlias *lnwire.ShortChannelID
|
||||||
if channel.IsZeroConf() {
|
if channel.IsZeroConf() {
|
||||||
// We'll need to wait until channel_ready has been received and
|
// We'll need to wait until channel_ready has been received and
|
||||||
@ -3788,9 +4053,9 @@ type chanAnnouncement struct {
|
|||||||
func (f *Manager) newChanAnnouncement(localPubKey,
|
func (f *Manager) newChanAnnouncement(localPubKey,
|
||||||
remotePubKey *btcec.PublicKey, localFundingKey *keychain.KeyDescriptor,
|
remotePubKey *btcec.PublicKey, localFundingKey *keychain.KeyDescriptor,
|
||||||
remoteFundingKey *btcec.PublicKey, shortChanID lnwire.ShortChannelID,
|
remoteFundingKey *btcec.PublicKey, shortChanID lnwire.ShortChannelID,
|
||||||
chanID lnwire.ChannelID, fwdMinHTLC,
|
chanID lnwire.ChannelID, fwdMinHTLC, fwdMaxHTLC lnwire.MilliSatoshi,
|
||||||
fwdMaxHTLC lnwire.MilliSatoshi,
|
ourPolicy *channeldb.ChannelEdgePolicy,
|
||||||
ourPolicy *channeldb.ChannelEdgePolicy) (*chanAnnouncement, error) {
|
chanType channeldb.ChannelType) (*chanAnnouncement, error) {
|
||||||
|
|
||||||
chainHash := *f.cfg.Wallet.Cfg.NetParams.GenesisHash
|
chainHash := *f.cfg.Wallet.Cfg.NetParams.GenesisHash
|
||||||
|
|
||||||
@ -3982,7 +4247,7 @@ func (f *Manager) newChanAnnouncement(localPubKey,
|
|||||||
func (f *Manager) announceChannel(localIDKey, remoteIDKey *btcec.PublicKey,
|
func (f *Manager) announceChannel(localIDKey, remoteIDKey *btcec.PublicKey,
|
||||||
localFundingKey *keychain.KeyDescriptor,
|
localFundingKey *keychain.KeyDescriptor,
|
||||||
remoteFundingKey *btcec.PublicKey, shortChanID lnwire.ShortChannelID,
|
remoteFundingKey *btcec.PublicKey, shortChanID lnwire.ShortChannelID,
|
||||||
chanID lnwire.ChannelID) error {
|
chanID lnwire.ChannelID, chanType channeldb.ChannelType) error {
|
||||||
|
|
||||||
// First, we'll create the batch of announcements to be sent upon
|
// First, we'll create the batch of announcements to be sent upon
|
||||||
// initial channel creation. This includes the channel announcement
|
// initial channel creation. This includes the channel announcement
|
||||||
@ -3993,7 +4258,7 @@ func (f *Manager) announceChannel(localIDKey, remoteIDKey *btcec.PublicKey,
|
|||||||
// only use the channel announcement message from the returned struct.
|
// only use the channel announcement message from the returned struct.
|
||||||
ann, err := f.newChanAnnouncement(localIDKey, remoteIDKey,
|
ann, err := f.newChanAnnouncement(localIDKey, remoteIDKey,
|
||||||
localFundingKey, remoteFundingKey, shortChanID, chanID,
|
localFundingKey, remoteFundingKey, shortChanID, chanID,
|
||||||
0, 0, nil,
|
0, 0, nil, chanType,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("can't generate channel announcement: %v", err)
|
log.Errorf("can't generate channel announcement: %v", err)
|
||||||
@ -4421,6 +4686,13 @@ func (f *Manager) handleInitFundingMsg(msg *InitFundingMsg) {
|
|||||||
log.Infof("Starting funding workflow with %v for pending_id(%x), "+
|
log.Infof("Starting funding workflow with %v for pending_id(%x), "+
|
||||||
"committype=%v", msg.Peer.Address(), chanID, commitType)
|
"committype=%v", msg.Peer.Address(), chanID, commitType)
|
||||||
|
|
||||||
|
var localNonce *lnwire.Musig2Nonce
|
||||||
|
if commitType.IsTaproot() {
|
||||||
|
localNonce = (*lnwire.Musig2Nonce)(
|
||||||
|
&ourContribution.LocalNonce.PubNonce,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fundingOpen := lnwire.OpenChannel{
|
fundingOpen := lnwire.OpenChannel{
|
||||||
ChainHash: *f.cfg.Wallet.Cfg.NetParams.GenesisHash,
|
ChainHash: *f.cfg.Wallet.Cfg.NetParams.GenesisHash,
|
||||||
PendingChannelID: chanID,
|
PendingChannelID: chanID,
|
||||||
@ -4443,6 +4715,7 @@ func (f *Manager) handleInitFundingMsg(msg *InitFundingMsg) {
|
|||||||
UpfrontShutdownScript: shutdown,
|
UpfrontShutdownScript: shutdown,
|
||||||
ChannelType: chanType,
|
ChannelType: chanType,
|
||||||
LeaseExpiry: leaseExpiry,
|
LeaseExpiry: leaseExpiry,
|
||||||
|
LocalNonce: localNonce,
|
||||||
}
|
}
|
||||||
if err := msg.Peer.SendMessage(true, &fundingOpen); err != nil {
|
if err := msg.Peer.SendMessage(true, &fundingOpen); err != nil {
|
||||||
e := fmt.Errorf("unable to send funding request message: %v",
|
e := fmt.Errorf("unable to send funding request message: %v",
|
||||||
|
@ -235,7 +235,7 @@ func (m *mockZeroConfAcceptor) Accept(
|
|||||||
}
|
}
|
||||||
|
|
||||||
type newChannelMsg struct {
|
type newChannelMsg struct {
|
||||||
channel *channeldb.OpenChannel
|
channel *lnpeer.NewChannel
|
||||||
err chan error
|
err chan error
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -299,7 +299,7 @@ func (n *testNode) RemoteFeatures() *lnwire.FeatureVector {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *testNode) AddNewChannel(channel *channeldb.OpenChannel,
|
func (n *testNode) AddNewChannel(channel *lnpeer.NewChannel,
|
||||||
quit <-chan struct{}) error {
|
quit <-chan struct{}) error {
|
||||||
|
|
||||||
errChan := make(chan error)
|
errChan := make(chan error)
|
||||||
|
@ -706,7 +706,8 @@ func (l *channelLink) syncChanStates() error {
|
|||||||
// very same nonce that we sent above, as they should
|
// very same nonce that we sent above, as they should
|
||||||
// take the latest verification nonce we send.
|
// take the latest verification nonce we send.
|
||||||
if chanState.ChanType.IsTaproot() {
|
if chanState.ChanType.IsTaproot() {
|
||||||
fundingLockedMsg.NextLocalNonce = localChanSyncMsg.LocalNonce //nolint:lll
|
//nolint:lll
|
||||||
|
channelReadyMsg.NextLocalNonce = localChanSyncMsg.LocalNonce
|
||||||
}
|
}
|
||||||
|
|
||||||
// For channels that negotiated the option-scid-alias
|
// For channels that negotiated the option-scid-alias
|
||||||
|
@ -1868,7 +1868,7 @@ func (m *mockPeer) SendMessage(sync bool, msgs ...lnwire.Message) error {
|
|||||||
func (m *mockPeer) SendMessageLazy(sync bool, msgs ...lnwire.Message) error {
|
func (m *mockPeer) SendMessageLazy(sync bool, msgs ...lnwire.Message) error {
|
||||||
return m.SendMessage(sync, msgs...)
|
return m.SendMessage(sync, msgs...)
|
||||||
}
|
}
|
||||||
func (m *mockPeer) AddNewChannel(_ *channeldb.OpenChannel,
|
func (m *mockPeer) AddNewChannel(_ *lnpeer.NewChannel,
|
||||||
_ <-chan struct{}) error {
|
_ <-chan struct{}) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -666,7 +666,7 @@ func (s *mockServer) Address() net.Addr {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *mockServer) AddNewChannel(channel *channeldb.OpenChannel,
|
func (s *mockServer) AddNewChannel(channel *lnpeer.NewChannel,
|
||||||
cancel <-chan struct{}) error {
|
cancel <-chan struct{}) error {
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -5,7 +5,6 @@ import (
|
|||||||
|
|
||||||
"github.com/btcsuite/btcd/btcec/v2"
|
"github.com/btcsuite/btcd/btcec/v2"
|
||||||
"github.com/btcsuite/btcd/wire"
|
"github.com/btcsuite/btcd/wire"
|
||||||
"github.com/lightningnetwork/lnd/channeldb"
|
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
"github.com/stretchr/testify/mock"
|
"github.com/stretchr/testify/mock"
|
||||||
)
|
)
|
||||||
@ -28,7 +27,7 @@ func (m *MockPeer) SendMessageLazy(sync bool, msgs ...lnwire.Message) error {
|
|||||||
return args.Error(0)
|
return args.Error(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MockPeer) AddNewChannel(channel *channeldb.OpenChannel,
|
func (m *MockPeer) AddNewChannel(channel *NewChannel,
|
||||||
cancel <-chan struct{}) error {
|
cancel <-chan struct{}) error {
|
||||||
|
|
||||||
args := m.Called(channel, cancel)
|
args := m.Called(channel, cancel)
|
||||||
|
@ -6,9 +6,20 @@ import (
|
|||||||
"github.com/btcsuite/btcd/btcec/v2"
|
"github.com/btcsuite/btcd/btcec/v2"
|
||||||
"github.com/btcsuite/btcd/wire"
|
"github.com/btcsuite/btcd/wire"
|
||||||
"github.com/lightningnetwork/lnd/channeldb"
|
"github.com/lightningnetwork/lnd/channeldb"
|
||||||
|
"github.com/lightningnetwork/lnd/lnwallet"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// NewChannel is a newly funded channel. This struct couples a channel along
|
||||||
|
// with the set of channel options that may change how the channel is created.
|
||||||
|
// This can be used to pass along the nonce state needed for taproot channels.
|
||||||
|
type NewChannel struct {
|
||||||
|
*channeldb.OpenChannel
|
||||||
|
|
||||||
|
// ChanOpts can be used to change how the channel is created.
|
||||||
|
ChanOpts []lnwallet.ChannelOpt
|
||||||
|
}
|
||||||
|
|
||||||
// Peer is an interface which represents a remote lightning node.
|
// Peer is an interface which represents a remote lightning node.
|
||||||
type Peer interface {
|
type Peer interface {
|
||||||
// SendMessage sends a variadic number of high-priority message to
|
// SendMessage sends a variadic number of high-priority message to
|
||||||
@ -25,7 +36,7 @@ type Peer interface {
|
|||||||
|
|
||||||
// AddNewChannel adds a new channel to the peer. The channel should fail
|
// AddNewChannel adds a new channel to the peer. The channel should fail
|
||||||
// to be added if the cancel channel is closed.
|
// to be added if the cancel channel is closed.
|
||||||
AddNewChannel(channel *channeldb.OpenChannel, cancel <-chan struct{}) error
|
AddNewChannel(newChan *NewChannel, cancel <-chan struct{}) error
|
||||||
|
|
||||||
// AddPendingChannel adds a pending open channel ID to the peer. The
|
// AddPendingChannel adds a pending open channel ID to the peer. The
|
||||||
// channel should fail to be added if the cancel chan is closed.
|
// channel should fail to be added if the cancel chan is closed.
|
||||||
|
@ -90,7 +90,7 @@ type outgoingMsg struct {
|
|||||||
// completed.
|
// completed.
|
||||||
type newChannelMsg struct {
|
type newChannelMsg struct {
|
||||||
// channel is used when the pending channel becomes active.
|
// channel is used when the pending channel becomes active.
|
||||||
channel *channeldb.OpenChannel
|
channel *lnpeer.NewChannel
|
||||||
|
|
||||||
// channelID is used when there's a new pending channel.
|
// channelID is used when there's a new pending channel.
|
||||||
channelID lnwire.ChannelID
|
channelID lnwire.ChannelID
|
||||||
@ -3506,12 +3506,12 @@ func (p *Brontide) Address() net.Addr {
|
|||||||
// added if the cancel channel is closed.
|
// added if the cancel channel is closed.
|
||||||
//
|
//
|
||||||
// NOTE: Part of the lnpeer.Peer interface.
|
// NOTE: Part of the lnpeer.Peer interface.
|
||||||
func (p *Brontide) AddNewChannel(channel *channeldb.OpenChannel,
|
func (p *Brontide) AddNewChannel(newChan *lnpeer.NewChannel,
|
||||||
cancel <-chan struct{}) error {
|
cancel <-chan struct{}) error {
|
||||||
|
|
||||||
errChan := make(chan error, 1)
|
errChan := make(chan error, 1)
|
||||||
newChanMsg := &newChannelMsg{
|
newChanMsg := &newChannelMsg{
|
||||||
channel: channel,
|
channel: newChan,
|
||||||
err: errChan,
|
err: errChan,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3813,7 +3813,7 @@ func (p *Brontide) updateNextRevocation(c *channeldb.OpenChannel) error {
|
|||||||
// addActiveChannel adds a new active channel to the `activeChannels` map. It
|
// addActiveChannel adds a new active channel to the `activeChannels` map. It
|
||||||
// takes a `channeldb.OpenChannel`, creates a `lnwallet.LightningChannel` from
|
// takes a `channeldb.OpenChannel`, creates a `lnwallet.LightningChannel` from
|
||||||
// it and assembles it with a channel link.
|
// it and assembles it with a channel link.
|
||||||
func (p *Brontide) addActiveChannel(c *channeldb.OpenChannel) error {
|
func (p *Brontide) addActiveChannel(c *lnpeer.NewChannel) error {
|
||||||
chanPoint := &c.FundingOutpoint
|
chanPoint := &c.FundingOutpoint
|
||||||
chanID := lnwire.NewChanIDFromOutPoint(chanPoint)
|
chanID := lnwire.NewChanIDFromOutPoint(chanPoint)
|
||||||
|
|
||||||
@ -3821,7 +3821,8 @@ func (p *Brontide) addActiveChannel(c *channeldb.OpenChannel) error {
|
|||||||
// channels, so we can look it up later easily according to its channel
|
// channels, so we can look it up later easily according to its channel
|
||||||
// ID.
|
// ID.
|
||||||
lnChan, err := lnwallet.NewLightningChannel(
|
lnChan, err := lnwallet.NewLightningChannel(
|
||||||
p.cfg.Signer, c, p.cfg.SigPool,
|
p.cfg.Signer, c.OpenChannel,
|
||||||
|
p.cfg.SigPool, c.ChanOpts...,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to create LightningChannel: %w", err)
|
return fmt.Errorf("unable to create LightningChannel: %w", err)
|
||||||
@ -3887,7 +3888,8 @@ func (p *Brontide) handleNewActiveChannel(req *newChannelMsg) {
|
|||||||
close(req.err)
|
close(req.err)
|
||||||
|
|
||||||
// Update the next revocation point.
|
// Update the next revocation point.
|
||||||
if err := p.updateNextRevocation(newChan); err != nil {
|
err := p.updateNextRevocation(newChan.OpenChannel)
|
||||||
|
if err != nil {
|
||||||
p.log.Errorf(err.Error())
|
p.log.Errorf(err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user