2019-01-24 14:28:25 +01:00
|
|
|
package lnd
|
2019-02-09 04:34:40 +01:00
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"net"
|
|
|
|
|
|
|
|
"github.com/btcsuite/btcd/btcec"
|
|
|
|
"github.com/btcsuite/btcd/wire"
|
|
|
|
"github.com/lightningnetwork/lnd/chanbackup"
|
2020-02-10 11:37:44 +01:00
|
|
|
"github.com/lightningnetwork/lnd/channeldb"
|
2019-02-09 04:34:40 +01:00
|
|
|
"github.com/lightningnetwork/lnd/channelnotifier"
|
|
|
|
)
|
|
|
|
|
|
|
|
// addrSource is an interface that allow us to get the addresses for a target
|
|
|
|
// node. We'll need this in order to be able to properly proxy the
|
|
|
|
// notifications to create SCBs.
|
|
|
|
type addrSource interface {
|
|
|
|
// AddrsForNode returns all known addresses for the target node public
|
|
|
|
// key.
|
|
|
|
AddrsForNode(nodePub *btcec.PublicKey) ([]net.Addr, error)
|
|
|
|
}
|
|
|
|
|
|
|
|
// channelNotifier is an implementation of the chanbackup.ChannelNotifier
|
|
|
|
// interface using the existing channelnotifier.ChannelNotifier struct. This
|
|
|
|
// implementation allows us to satisfy all the dependencies of the
|
|
|
|
// chanbackup.SubSwapper struct.
|
|
|
|
type channelNotifier struct {
|
|
|
|
// chanNotifier is the based channel notifier that we'll proxy requests
|
|
|
|
// from.
|
|
|
|
chanNotifier *channelnotifier.ChannelNotifier
|
|
|
|
|
|
|
|
// addrs is an implementation of the addrSource interface that allows
|
|
|
|
// us to get the latest set of addresses for a given node. We'll need
|
|
|
|
// this to be able to create an SCB for new channels.
|
|
|
|
addrs addrSource
|
|
|
|
}
|
|
|
|
|
|
|
|
// SubscribeChans requests a new channel subscription relative to the initial
|
|
|
|
// set of known channels. We use the knownChans as a synchronization point to
|
|
|
|
// ensure that the chanbackup.SubSwapper does not miss any channel open or
|
|
|
|
// close events in the period between when it's created, and when it requests
|
|
|
|
// the channel subscription.
|
|
|
|
//
|
|
|
|
// NOTE: This is part of the chanbackup.ChannelNotifier interface.
|
|
|
|
func (c *channelNotifier) SubscribeChans(startingChans map[wire.OutPoint]struct{}) (
|
|
|
|
*chanbackup.ChannelSubscription, error) {
|
|
|
|
|
|
|
|
ltndLog.Infof("Channel backup proxy channel notifier starting")
|
|
|
|
|
|
|
|
// TODO(roasbeef): read existing set of chans and diff
|
|
|
|
|
|
|
|
quit := make(chan struct{})
|
|
|
|
chanUpdates := make(chan chanbackup.ChannelEvent, 1)
|
|
|
|
|
2020-02-10 11:37:44 +01:00
|
|
|
// sendChanOpenUpdate is a closure that sends a ChannelEvent to the
|
|
|
|
// chanUpdates channel to inform subscribers about new pending or
|
|
|
|
// confirmed channels.
|
|
|
|
sendChanOpenUpdate := func(newOrPendingChan *channeldb.OpenChannel) {
|
|
|
|
nodeAddrs, err := c.addrs.AddrsForNode(
|
|
|
|
newOrPendingChan.IdentityPub,
|
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
pub := newOrPendingChan.IdentityPub
|
|
|
|
ltndLog.Errorf("unable to fetch addrs for %x: %v",
|
|
|
|
pub.SerializeCompressed(), err)
|
|
|
|
}
|
|
|
|
|
|
|
|
chanEvent := chanbackup.ChannelEvent{
|
|
|
|
NewChans: []chanbackup.ChannelWithAddrs{
|
|
|
|
{
|
|
|
|
OpenChannel: newOrPendingChan,
|
|
|
|
Addrs: nodeAddrs,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
select {
|
|
|
|
case chanUpdates <- chanEvent:
|
|
|
|
case <-quit:
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-09 04:34:40 +01:00
|
|
|
// In order to adhere to the interface, we'll proxy the events from the
|
|
|
|
// channel notifier to the sub-swapper in a format it understands.
|
|
|
|
go func() {
|
|
|
|
// First, we'll subscribe to the primary channel notifier so we can
|
|
|
|
// obtain events for new opened/closed channels.
|
|
|
|
chanSubscription, err := c.chanNotifier.SubscribeChannelEvents()
|
|
|
|
if err != nil {
|
|
|
|
panic(fmt.Sprintf("unable to subscribe to chans: %v",
|
|
|
|
err))
|
|
|
|
}
|
|
|
|
|
|
|
|
defer chanSubscription.Cancel()
|
|
|
|
|
|
|
|
for {
|
|
|
|
select {
|
|
|
|
|
|
|
|
// A new event has been sent by the chanNotifier, we'll
|
|
|
|
// filter out the events we actually care about and
|
|
|
|
// send them to the sub-swapper.
|
|
|
|
case e := <-chanSubscription.Updates():
|
|
|
|
// TODO(roasbeef): batch dispatch ntnfs
|
|
|
|
|
|
|
|
switch event := e.(type) {
|
2020-02-10 11:37:44 +01:00
|
|
|
// A new channel has been opened and is still
|
|
|
|
// pending. We can still create a backup, even
|
|
|
|
// if the final channel ID is not yet available.
|
|
|
|
case channelnotifier.PendingOpenChannelEvent:
|
|
|
|
pendingChan := event.PendingChannel
|
|
|
|
sendChanOpenUpdate(pendingChan)
|
|
|
|
|
|
|
|
// A new channel has been confirmed, we'll
|
|
|
|
// obtain the node address, then send to the
|
2019-02-09 04:34:40 +01:00
|
|
|
// sub-swapper.
|
|
|
|
case channelnotifier.OpenChannelEvent:
|
2020-02-10 11:37:44 +01:00
|
|
|
sendChanOpenUpdate(event.Channel)
|
2019-02-09 04:34:40 +01:00
|
|
|
|
|
|
|
// An existing channel has been closed, we'll
|
|
|
|
// send only the chanPoint of the closed
|
|
|
|
// channel to the sub-swapper.
|
|
|
|
case channelnotifier.ClosedChannelEvent:
|
|
|
|
chanPoint := event.CloseSummary.ChanPoint
|
2021-08-09 13:55:33 +02:00
|
|
|
closeType := event.CloseSummary.CloseType
|
|
|
|
|
|
|
|
// Because we see the contract as closed
|
|
|
|
// once our local force close TX
|
|
|
|
// confirms, the channel arbitrator
|
|
|
|
// already fires on this event. But
|
|
|
|
// because our funds can be in limbo for
|
|
|
|
// up to 2 weeks worst case we don't
|
|
|
|
// want to remove the crucial info we
|
|
|
|
// need for sweeping that time locked
|
|
|
|
// output before we've actually done so.
|
|
|
|
if closeType == channeldb.LocalForceClose {
|
|
|
|
ltndLog.Debugf("Channel %v "+
|
|
|
|
"was force closed by "+
|
|
|
|
"us, not removing "+
|
|
|
|
"from channel backup "+
|
|
|
|
"until fully resolved",
|
|
|
|
chanPoint)
|
|
|
|
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2019-02-09 04:34:40 +01:00
|
|
|
chanEvent := chanbackup.ChannelEvent{
|
|
|
|
ClosedChans: []wire.OutPoint{
|
|
|
|
chanPoint,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2021-08-09 13:55:33 +02:00
|
|
|
select {
|
|
|
|
case chanUpdates <- chanEvent:
|
|
|
|
case <-quit:
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// A channel was fully resolved on chain. This
|
|
|
|
// should only really interest us if it was a
|
|
|
|
// locally force closed channel where we didn't
|
|
|
|
// remove the channel already when the close
|
|
|
|
// event was fired.
|
|
|
|
case channelnotifier.FullyResolvedChannelEvent:
|
|
|
|
chanEvent := chanbackup.ChannelEvent{
|
|
|
|
ClosedChans: []wire.OutPoint{
|
|
|
|
*event.ChannelPoint,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2019-02-09 04:34:40 +01:00
|
|
|
select {
|
|
|
|
case chanUpdates <- chanEvent:
|
|
|
|
case <-quit:
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// The cancel method has been called, signalling us to
|
|
|
|
// exit
|
|
|
|
case <-quit:
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
|
|
|
return &chanbackup.ChannelSubscription{
|
|
|
|
ChanUpdates: chanUpdates,
|
|
|
|
Cancel: func() {
|
|
|
|
close(quit)
|
|
|
|
},
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// A compile-time constraint to ensure channelNotifier implements
|
|
|
|
// chanbackup.ChannelNotifier.
|
|
|
|
var _ chanbackup.ChannelNotifier = (*channelNotifier)(nil)
|