Merge pull request #1505 from wpaulino/fundingmanager-send-peer-directly

fundingmanager: send messages directly to peers
This commit is contained in:
Olaoluwa Osuntokun 2018-07-20 17:48:14 -07:00 committed by GitHub
commit 271db7d06d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 485 additions and 346 deletions

@ -107,7 +107,9 @@ type Config struct {
// NotifyWhenOnline is a function that allows the gossiper to be // NotifyWhenOnline is a function that allows the gossiper to be
// notified when a certain peer comes online, allowing it to // notified when a certain peer comes online, allowing it to
// retry sending a peer message. // retry sending a peer message.
NotifyWhenOnline func(peer *btcec.PublicKey, connectedChan chan<- struct{}) //
// NOTE: The peerChan channel must be buffered.
NotifyWhenOnline func(peer *btcec.PublicKey, peerChan chan<- lnpeer.Peer)
// ProofMatureDelta the number of confirmations which is needed before // ProofMatureDelta the number of confirmations which is needed before
// exchange the channel announcement proofs. // exchange the channel announcement proofs.
@ -2399,13 +2401,13 @@ func (d *AuthenticatedGossiper) sendAnnSigReliably(
"to peer(%x): %v. Will retry when online.", "to peer(%x): %v. Will retry when online.",
remotePeer.SerializeCompressed(), err) remotePeer.SerializeCompressed(), err)
connected := make(chan struct{}) peerChan := make(chan lnpeer.Peer, 1)
d.cfg.NotifyWhenOnline(remotePeer, connected) d.cfg.NotifyWhenOnline(remotePeer, peerChan)
select { select {
case <-connected: case <-peerChan:
// Retry sending. // Retry sending.
log.Infof("peer %x reconnected. Retry sending"+ log.Infof("Peer %x reconnected. Retry sending"+
" AnnounceSignatures.", " AnnounceSignatures.",
remotePeer.SerializeCompressed()) remotePeer.SerializeCompressed())

@ -23,6 +23,7 @@ import (
"github.com/lightningnetwork/lnd/chainntnfs" "github.com/lightningnetwork/lnd/chainntnfs"
"github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/channeldb"
"github.com/lightningnetwork/lnd/lnpeer" "github.com/lightningnetwork/lnd/lnpeer"
"github.com/lightningnetwork/lnd/lnwallet"
"github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/routing" "github.com/lightningnetwork/lnd/routing"
"github.com/btcsuite/btcd/btcec" "github.com/btcsuite/btcd/btcec"
@ -1186,9 +1187,9 @@ func TestSignatureAnnouncementRetry(t *testing.T) {
// We expect the gossiper to register for a notification when the peer // We expect the gossiper to register for a notification when the peer
// comes back online, so keep track of the channel it wants to get // comes back online, so keep track of the channel it wants to get
// notified on. // notified on.
notifyPeers := make(chan chan<- struct{}, 1) notifyPeers := make(chan chan<- lnpeer.Peer, 1)
ctx.gossiper.cfg.NotifyWhenOnline = func(peer *btcec.PublicKey, ctx.gossiper.cfg.NotifyWhenOnline = func(peer *btcec.PublicKey,
connectedChan chan<- struct{}) { connectedChan chan<- lnpeer.Peer) {
notifyPeers <- connectedChan notifyPeers <- connectedChan
} }
@ -1207,7 +1208,7 @@ func TestSignatureAnnouncementRetry(t *testing.T) {
// Since sending this local announcement proof to the remote will fail, // Since sending this local announcement proof to the remote will fail,
// the gossiper should register for a notification when the remote is // the gossiper should register for a notification when the remote is
// online again. // online again.
var conChan chan<- struct{} var conChan chan<- lnpeer.Peer
select { select {
case conChan = <-notifyPeers: case conChan = <-notifyPeers:
case <-time.After(2 * time.Second): case <-time.After(2 * time.Second):
@ -1371,9 +1372,9 @@ func TestSignatureAnnouncementRetryAtStartup(t *testing.T) {
msg ...lnwire.Message) error { msg ...lnwire.Message) error {
return fmt.Errorf("intentional error in SendToPeer") return fmt.Errorf("intentional error in SendToPeer")
} }
notifyPeers := make(chan chan<- struct{}, 1) notifyPeers := make(chan chan<- lnpeer.Peer, 1)
ctx.gossiper.cfg.NotifyWhenOnline = func(peer *btcec.PublicKey, ctx.gossiper.cfg.NotifyWhenOnline = func(peer *btcec.PublicKey,
connectedChan chan<- struct{}) { connectedChan chan<- lnpeer.Peer) {
notifyPeers <- connectedChan notifyPeers <- connectedChan
} }
@ -1391,7 +1392,7 @@ func TestSignatureAnnouncementRetryAtStartup(t *testing.T) {
// Since sending to the remote peer will fail, the gossiper should // Since sending to the remote peer will fail, the gossiper should
// register for a notification when it comes back online. // register for a notification when it comes back online.
var conChan chan<- struct{} var conChan chan<- lnpeer.Peer
select { select {
case conChan = <-notifyPeers: case conChan = <-notifyPeers:
case <-time.After(2 * time.Second): case <-time.After(2 * time.Second):
@ -1430,7 +1431,7 @@ func TestSignatureAnnouncementRetryAtStartup(t *testing.T) {
return fmt.Errorf("intentional error in SendToPeer") return fmt.Errorf("intentional error in SendToPeer")
}, },
NotifyWhenOnline: func(peer *btcec.PublicKey, NotifyWhenOnline: func(peer *btcec.PublicKey,
connectedChan chan<- struct{}) { connectedChan chan<- lnpeer.Peer) {
notifyPeers <- connectedChan notifyPeers <- connectedChan
}, },
Router: ctx.gossiper.cfg.Router, Router: ctx.gossiper.cfg.Router,
@ -1606,9 +1607,9 @@ func TestSignatureAnnouncementFullProofWhenRemoteProof(t *testing.T) {
return nil return nil
} }
notifyPeers := make(chan chan<- struct{}, 1) notifyPeers := make(chan chan<- lnpeer.Peer, 1)
ctx.gossiper.cfg.NotifyWhenOnline = func(peer *btcec.PublicKey, ctx.gossiper.cfg.NotifyWhenOnline = func(peer *btcec.PublicKey,
connectedChan chan<- struct{}) { connectedChan chan<- lnpeer.Peer) {
notifyPeers <- connectedChan notifyPeers <- connectedChan
} }
@ -2145,6 +2146,8 @@ type mockPeer struct {
quit chan struct{} quit chan struct{}
} }
var _ lnpeer.Peer = (*mockPeer)(nil)
func (p *mockPeer) SendMessage(_ bool, msgs ...lnwire.Message) error { func (p *mockPeer) SendMessage(_ bool, msgs ...lnwire.Message) error {
if p.sentMsgs == nil && p.quit == nil { if p.sentMsgs == nil && p.quit == nil {
return nil return nil
@ -2159,6 +2162,9 @@ func (p *mockPeer) SendMessage(_ bool, msgs ...lnwire.Message) error {
return nil return nil
} }
func (p *mockPeer) AddNewChannel(_ *lnwallet.LightningChannel, _ <-chan struct{}) error {
return nil
}
func (p *mockPeer) WipeChannel(_ *wire.OutPoint) error { return nil } func (p *mockPeer) WipeChannel(_ *wire.OutPoint) error { return nil }
func (p *mockPeer) IdentityKey() *btcec.PublicKey { return p.pk } func (p *mockPeer) IdentityKey() *btcec.PublicKey { return p.pk }
func (p *mockPeer) PubKey() [33]byte { func (p *mockPeer) PubKey() [33]byte {
@ -2166,3 +2172,4 @@ func (p *mockPeer) PubKey() [33]byte {
copy(pubkey[:], p.pk.SerializeCompressed()) copy(pubkey[:], p.pk.SerializeCompressed())
return pubkey return pubkey
} }
func (p *mockPeer) Address() net.Addr { return nil }

@ -12,6 +12,10 @@ import (
"golang.org/x/crypto/salsa20" "golang.org/x/crypto/salsa20"
"github.com/btcsuite/btcd/btcec"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
"github.com/coreos/bbolt" "github.com/coreos/bbolt"
"github.com/davecgh/go-spew/spew" "github.com/davecgh/go-spew/spew"
"github.com/go-errors/errors" "github.com/go-errors/errors"
@ -19,14 +23,11 @@ import (
"github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/channeldb"
"github.com/lightningnetwork/lnd/htlcswitch" "github.com/lightningnetwork/lnd/htlcswitch"
"github.com/lightningnetwork/lnd/keychain" "github.com/lightningnetwork/lnd/keychain"
"github.com/lightningnetwork/lnd/lnpeer"
"github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lnwallet" "github.com/lightningnetwork/lnd/lnwallet"
"github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/routing" "github.com/lightningnetwork/lnd/routing"
"github.com/btcsuite/btcd/btcec"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
) )
const ( const (
@ -85,6 +86,12 @@ var (
// //
// TODO(roasbeef): add command line param to modify // TODO(roasbeef): add command line param to modify
maxFundingAmount = maxBtcFundingAmount maxFundingAmount = maxBtcFundingAmount
// ErrFundingManagerShuttingDown is an error returned when attempting to
// process a funding request/message but the funding manager has already
// been signaled to shut down.
ErrFundingManagerShuttingDown = errors.New("funding manager shutting " +
"down")
) )
// reservationWithCtx encapsulates a pending channel reservation. This wrapper // reservationWithCtx encapsulates a pending channel reservation. This wrapper
@ -98,7 +105,7 @@ var (
// * deadlines, etc. // * deadlines, etc.
type reservationWithCtx struct { type reservationWithCtx struct {
reservation *lnwallet.ChannelReservation reservation *lnwallet.ChannelReservation
peerAddress *lnwire.NetAddress peer lnpeer.Peer
chanAmt btcutil.Amount chanAmt btcutil.Amount
@ -145,7 +152,7 @@ func (r *reservationWithCtx) updateTimestamp() {
// embedded within this message giving the funding manager full context w.r.t // embedded within this message giving the funding manager full context w.r.t
// the workflow. // the workflow.
type initFundingMsg struct { type initFundingMsg struct {
peerAddress *lnwire.NetAddress peer lnpeer.Peer
*openChanReq *openChanReq
} }
@ -153,47 +160,47 @@ type initFundingMsg struct {
// the message. This allows the funding manager to queue a response directly to // the message. This allows the funding manager to queue a response directly to
// the peer, progressing the funding workflow. // the peer, progressing the funding workflow.
type fundingOpenMsg struct { type fundingOpenMsg struct {
msg *lnwire.OpenChannel msg *lnwire.OpenChannel
peerAddress *lnwire.NetAddress peer lnpeer.Peer
} }
// fundingAcceptMsg couples an lnwire.AcceptChannel message with the peer who // fundingAcceptMsg couples an lnwire.AcceptChannel message with the peer who
// sent the message. This allows the funding manager to queue a response // sent the message. This allows the funding manager to queue a response
// directly to the peer, progressing the funding workflow. // directly to the peer, progressing the funding workflow.
type fundingAcceptMsg struct { type fundingAcceptMsg struct {
msg *lnwire.AcceptChannel msg *lnwire.AcceptChannel
peerAddress *lnwire.NetAddress peer lnpeer.Peer
} }
// fundingCreatedMsg couples an lnwire.FundingCreated message with the peer who // fundingCreatedMsg couples an lnwire.FundingCreated message with the peer who
// sent the message. This allows the funding manager to queue a response // sent the message. This allows the funding manager to queue a response
// directly to the peer, progressing the funding workflow. // directly to the peer, progressing the funding workflow.
type fundingCreatedMsg struct { type fundingCreatedMsg struct {
msg *lnwire.FundingCreated msg *lnwire.FundingCreated
peerAddress *lnwire.NetAddress peer lnpeer.Peer
} }
// fundingSignedMsg couples an lnwire.FundingSigned message with the peer who // fundingSignedMsg couples an lnwire.FundingSigned message with the peer who
// sent the message. This allows the funding manager to queue a response // sent the message. This allows the funding manager to queue a response
// directly to the peer, progressing the funding workflow. // directly to the peer, progressing the funding workflow.
type fundingSignedMsg struct { type fundingSignedMsg struct {
msg *lnwire.FundingSigned msg *lnwire.FundingSigned
peerAddress *lnwire.NetAddress peer lnpeer.Peer
} }
// fundingLockedMsg couples an lnwire.FundingLocked message with the peer who // fundingLockedMsg couples an lnwire.FundingLocked message with the peer who
// sent the message. This allows the funding manager to finalize the funding // sent the message. This allows the funding manager to finalize the funding
// process and announce the existence of the new channel. // process and announce the existence of the new channel.
type fundingLockedMsg struct { type fundingLockedMsg struct {
msg *lnwire.FundingLocked msg *lnwire.FundingLocked
peerAddress *lnwire.NetAddress peer lnpeer.Peer
} }
// fundingErrorMsg couples an lnwire.Error message with the peer who sent the // fundingErrorMsg couples an lnwire.Error message with the peer who sent the
// message. This allows the funding manager to properly process the error. // message. This allows the funding manager to properly process the error.
type fundingErrorMsg struct { type fundingErrorMsg struct {
err *lnwire.Error err *lnwire.Error
peerAddress *lnwire.NetAddress peerKey *btcec.PublicKey
} }
// pendingChannels is a map instantiated per-peer which tracks all active // pendingChannels is a map instantiated per-peer which tracks all active
@ -257,21 +264,13 @@ type fundingConfig struct {
// to the greater network. // to the greater network.
SendAnnouncement func(msg lnwire.Message) error SendAnnouncement func(msg lnwire.Message) error
// SendToPeer allows the FundingManager to send messages to the peer
// node during the multiple steps involved in the creation of the
// channel's funding transaction and initial commitment transaction.
SendToPeer func(target *btcec.PublicKey, msgs ...lnwire.Message) error
// NotifyWhenOnline allows the FundingManager to register with a // NotifyWhenOnline allows the FundingManager to register with a
// subsystem that will notify it when the peer comes online. // subsystem that will notify it when the peer comes online. This is
// This is used when sending the fundingLocked message, since it MUST be // used when sending the fundingLocked message, since it MUST be
// delivered after the funding transaction is confirmed. // delivered after the funding transaction is confirmed.
NotifyWhenOnline func(peer *btcec.PublicKey, connectedChan chan<- struct{}) //
// NOTE: The peerChan channel must be buffered.
// FindPeer searches the list of peers connected to the node so that NotifyWhenOnline func(peer *btcec.PublicKey, peerChan chan<- lnpeer.Peer)
// the FundingManager can notify other daemon subsystems as necessary
// during the funding process.
FindPeer func(peerKey *btcec.PublicKey) (*peer, error)
// FindChannel queries the database for the channel with the given // FindChannel queries the database for the channel with the given
// channel ID. // channel ID.
@ -318,9 +317,9 @@ type fundingConfig struct {
// WatchNewChannel is to be called once a new channel enters the final // WatchNewChannel is to be called once a new channel enters the final
// funding stage: waiting for on-chain confirmation. This method sends // funding stage: waiting for on-chain confirmation. This method sends
// the channel to the ChainArbitrator so it can watch for any on-chain // the channel to the ChainArbitrator so it can watch for any on-chain
// events related to the channel. We also provide the address of the // events related to the channel. We also provide the public key of the
// node we're establishing a channel with for reconnection purposes. // node we're establishing a channel with for reconnection purposes.
WatchNewChannel func(*channeldb.OpenChannel, *lnwire.NetAddress) error WatchNewChannel func(*channeldb.OpenChannel, *btcec.PublicKey) error
// ReportShortChanID allows the funding manager to report the newly // ReportShortChanID allows the funding manager to report the newly
// discovered short channel ID of a formerly pending channel to outside // discovered short channel ID of a formerly pending channel to outside
@ -547,16 +546,29 @@ func (f *fundingManager) Start() error {
// resume wait on startup. // resume wait on startup.
case shortChanID, ok := <-confChan: case shortChanID, ok := <-confChan:
if !ok { if !ok {
fndgLog.Errorf("waiting for funding" + fndgLog.Errorf("Waiting for funding" +
"confirmation failed") "confirmation failed")
return return
} }
// Success, funding transaction was confirmed. // The funding transaction has confirmed, so
err := f.handleFundingConfirmation(ch, shortChanID) // we'll attempt to retrieve the remote peer
// to complete the rest of the funding flow.
peerChan := make(chan lnpeer.Peer, 1)
f.cfg.NotifyWhenOnline(ch.IdentityPub, peerChan)
var peer lnpeer.Peer
select {
case peer = <-peerChan:
case <-f.quit:
return
}
err := f.handleFundingConfirmation(
peer, ch, shortChanID,
)
if err != nil { if err != nil {
fndgLog.Errorf("failed to handle funding"+ fndgLog.Errorf("Failed to handle "+
"confirmation: %v", err) "funding confirmation: %v", err)
return return
} }
} }
@ -614,10 +626,21 @@ func (f *fundingManager) Start() error {
go func(dbChan *channeldb.OpenChannel) { go func(dbChan *channeldb.OpenChannel) {
defer f.wg.Done() defer f.wg.Done()
err := f.handleFundingConfirmation(dbChan, shortChanID) peerChan := make(chan lnpeer.Peer, 1)
f.cfg.NotifyWhenOnline(dbChan.IdentityPub, peerChan)
var peer lnpeer.Peer
select {
case peer = <-peerChan:
case <-f.quit:
return
}
err := f.handleFundingConfirmation(
peer, dbChan, shortChanID,
)
if err != nil { if err != nil {
fndgLog.Errorf("failed to handle funding"+ fndgLog.Errorf("Failed to handle "+
"confirmation: %v", err) "funding confirmation: %v", err)
return return
} }
}(channel) }(channel)
@ -740,7 +763,7 @@ func (f *fundingManager) PendingChannels() ([]*pendingChannel, error) {
select { select {
case f.queries <- req: case f.queries <- req:
case <-f.quit: case <-f.quit:
return nil, fmt.Errorf("fundingmanager shutting down") return nil, ErrFundingManagerShuttingDown
} }
select { select {
@ -749,7 +772,7 @@ func (f *fundingManager) PendingChannels() ([]*pendingChannel, error) {
case err := <-errChan: case err := <-errChan:
return nil, err return nil, err
case <-f.quit: case <-f.quit:
return nil, fmt.Errorf("fundingmanager shutting down") return nil, ErrFundingManagerShuttingDown
} }
} }
@ -796,13 +819,13 @@ func (f *fundingManager) CancelPeerReservations(nodePub [33]byte) {
// //
// TODO(roasbeef): if peer disconnects, and haven't yet broadcast funding // TODO(roasbeef): if peer disconnects, and haven't yet broadcast funding
// transaction, then all reservations should be cleared. // transaction, then all reservations should be cleared.
func (f *fundingManager) failFundingFlow(peer *btcec.PublicKey, func (f *fundingManager) failFundingFlow(peer lnpeer.Peer, tempChanID [32]byte,
tempChanID [32]byte, fundingErr error) { fundingErr error) {
fndgLog.Debugf("Failing funding flow for pendingID=%x: %v", fndgLog.Debugf("Failing funding flow for pendingID=%x: %v",
tempChanID, fundingErr) tempChanID, fundingErr)
ctx, err := f.cancelReservationCtx(peer, tempChanID) ctx, err := f.cancelReservationCtx(peer.IdentityKey(), tempChanID)
if err != nil { if err != nil {
fndgLog.Errorf("unable to cancel reservation: %v", err) fndgLog.Errorf("unable to cancel reservation: %v", err)
} }
@ -837,8 +860,8 @@ func (f *fundingManager) failFundingFlow(peer *btcec.PublicKey,
} }
fndgLog.Debugf("Sending funding error to peer (%x): %v", fndgLog.Debugf("Sending funding error to peer (%x): %v",
peer.SerializeCompressed(), spew.Sdump(errMsg)) peer.IdentityKey().SerializeCompressed(), spew.Sdump(errMsg))
if err := f.cfg.SendToPeer(peer, errMsg); err != nil { if err := peer.SendMessage(false, errMsg); err != nil {
fndgLog.Errorf("unable to send error message to peer %v", err) fndgLog.Errorf("unable to send error message to peer %v", err)
} }
} }
@ -919,10 +942,10 @@ func (f *fundingManager) handlePendingChannels(msg *pendingChansReq) {
// processFundingOpen sends a message to the fundingManager allowing it to // processFundingOpen sends a message to the fundingManager allowing it to
// initiate the new funding workflow with the source peer. // initiate the new funding workflow with the source peer.
func (f *fundingManager) processFundingOpen(msg *lnwire.OpenChannel, func (f *fundingManager) processFundingOpen(msg *lnwire.OpenChannel,
peerAddress *lnwire.NetAddress) { peer lnpeer.Peer) {
select { select {
case f.fundingMsgs <- &fundingOpenMsg{msg, peerAddress}: case f.fundingMsgs <- &fundingOpenMsg{msg, peer}:
case <-f.quit: case <-f.quit:
return return
} }
@ -938,7 +961,7 @@ func (f *fundingManager) handleFundingOpen(fmsg *fundingOpenMsg) {
// Check number of pending channels to be smaller than maximum allowed // Check number of pending channels to be smaller than maximum allowed
// number and send ErrorGeneric to remote peer if condition is // number and send ErrorGeneric to remote peer if condition is
// violated. // violated.
peerIDKey := newSerializedKey(fmsg.peerAddress.IdentityKey) peerIDKey := newSerializedKey(fmsg.peer.IdentityKey())
msg := fmsg.msg msg := fmsg.msg
amt := msg.FundingAmount amt := msg.FundingAmount
@ -949,8 +972,9 @@ func (f *fundingManager) handleFundingOpen(fmsg *fundingOpenMsg) {
if len(f.activeReservations[peerIDKey]) >= cfg.MaxPendingChannels { if len(f.activeReservations[peerIDKey]) >= cfg.MaxPendingChannels {
f.resMtx.RUnlock() f.resMtx.RUnlock()
f.failFundingFlow( f.failFundingFlow(
fmsg.peerAddress.IdentityKey, fmsg.msg.PendingChannelID, fmsg.peer, fmsg.msg.PendingChannelID,
lnwire.ErrMaxPendingChannels) lnwire.ErrMaxPendingChannels,
)
return return
} }
f.resMtx.RUnlock() f.resMtx.RUnlock()
@ -964,8 +988,9 @@ func (f *fundingManager) handleFundingOpen(fmsg *fundingOpenMsg) {
fndgLog.Errorf("unable to query wallet: %v", err) fndgLog.Errorf("unable to query wallet: %v", err)
} }
f.failFundingFlow( f.failFundingFlow(
fmsg.peerAddress.IdentityKey, fmsg.msg.PendingChannelID, fmsg.peer, fmsg.msg.PendingChannelID,
lnwire.ErrSynchronizingChain) lnwire.ErrSynchronizingChain,
)
return return
} }
@ -973,7 +998,7 @@ func (f *fundingManager) handleFundingOpen(fmsg *fundingOpenMsg) {
// current soft-limit for channel size. // current soft-limit for channel size.
if msg.FundingAmount > maxFundingAmount { if msg.FundingAmount > maxFundingAmount {
f.failFundingFlow( f.failFundingFlow(
fmsg.peerAddress.IdentityKey, fmsg.msg.PendingChannelID, fmsg.peer, fmsg.msg.PendingChannelID,
lnwire.ErrChanTooLarge, lnwire.ErrChanTooLarge,
) )
return return
@ -983,7 +1008,7 @@ func (f *fundingManager) handleFundingOpen(fmsg *fundingOpenMsg) {
// a channel that's below our current min channel size. // a channel that's below our current min channel size.
if amt < f.cfg.MinChanSize { if amt < f.cfg.MinChanSize {
f.failFundingFlow( f.failFundingFlow(
fmsg.peerAddress.IdentityKey, fmsg.msg.PendingChannelID, fmsg.peer, fmsg.msg.PendingChannelID,
lnwallet.ErrChanTooSmall(amt, btcutil.Amount(f.cfg.MinChanSize)), lnwallet.ErrChanTooSmall(amt, btcutil.Amount(f.cfg.MinChanSize)),
) )
return return
@ -992,7 +1017,7 @@ func (f *fundingManager) handleFundingOpen(fmsg *fundingOpenMsg) {
fndgLog.Infof("Recv'd fundingRequest(amt=%v, push=%v, delay=%v, "+ fndgLog.Infof("Recv'd fundingRequest(amt=%v, push=%v, delay=%v, "+
"pendingId=%x) from peer(%x)", amt, msg.PushAmount, "pendingId=%x) from peer(%x)", amt, msg.PushAmount,
msg.CsvDelay, msg.PendingChannelID, msg.CsvDelay, msg.PendingChannelID,
fmsg.peerAddress.IdentityKey.SerializeCompressed()) fmsg.peer.IdentityKey().SerializeCompressed())
// Attempt to initialize a reservation within the wallet. If the wallet // Attempt to initialize a reservation within the wallet. If the wallet
// has insufficient resources to create the channel, then the // has insufficient resources to create the channel, then the
@ -1003,13 +1028,12 @@ func (f *fundingManager) handleFundingOpen(fmsg *fundingOpenMsg) {
reservation, err := f.cfg.Wallet.InitChannelReservation( reservation, err := f.cfg.Wallet.InitChannelReservation(
amt, 0, msg.PushAmount, amt, 0, msg.PushAmount,
lnwallet.SatPerKWeight(msg.FeePerKiloWeight), 0, lnwallet.SatPerKWeight(msg.FeePerKiloWeight), 0,
fmsg.peerAddress.IdentityKey, fmsg.peerAddress.Address, fmsg.peer.IdentityKey(), fmsg.peer.Address(),
&chainHash, msg.ChannelFlags, &chainHash, msg.ChannelFlags,
) )
if err != nil { if err != nil {
fndgLog.Errorf("Unable to initialize reservation: %v", err) fndgLog.Errorf("Unable to initialize reservation: %v", err)
f.failFundingFlow(fmsg.peerAddress.IdentityKey, f.failFundingFlow(fmsg.peer, msg.PendingChannelID, err)
msg.PendingChannelID, err)
return return
} }
@ -1029,9 +1053,7 @@ func (f *fundingManager) handleFundingOpen(fmsg *fundingOpenMsg) {
) )
if err != nil { if err != nil {
fndgLog.Errorf("Unacceptable channel constraints: %v", err) fndgLog.Errorf("Unacceptable channel constraints: %v", err)
f.failFundingFlow(fmsg.peerAddress.IdentityKey, f.failFundingFlow(fmsg.peer, fmsg.msg.PendingChannelID, err)
fmsg.msg.PendingChannelID, err,
)
return return
} }
@ -1059,7 +1081,7 @@ func (f *fundingManager) handleFundingOpen(fmsg *fundingOpenMsg) {
remoteCsvDelay: remoteCsvDelay, remoteCsvDelay: remoteCsvDelay,
remoteMinHtlc: minHtlc, remoteMinHtlc: minHtlc,
err: make(chan error, 1), err: make(chan error, 1),
peerAddress: fmsg.peerAddress, peer: fmsg.peer,
} }
f.activeReservations[peerIDKey][msg.PendingChannelID] = resCtx f.activeReservations[peerIDKey][msg.PendingChannelID] = resCtx
f.resMtx.Unlock() f.resMtx.Unlock()
@ -1101,8 +1123,7 @@ func (f *fundingManager) handleFundingOpen(fmsg *fundingOpenMsg) {
err = reservation.ProcessSingleContribution(remoteContribution) err = reservation.ProcessSingleContribution(remoteContribution)
if err != nil { if err != nil {
fndgLog.Errorf("unable to add contribution reservation: %v", err) fndgLog.Errorf("unable to add contribution reservation: %v", err)
f.failFundingFlow(fmsg.peerAddress.IdentityKey, f.failFundingFlow(fmsg.peer, msg.PendingChannelID, err)
msg.PendingChannelID, err)
return return
} }
@ -1130,11 +1151,9 @@ func (f *fundingManager) handleFundingOpen(fmsg *fundingOpenMsg) {
HtlcPoint: ourContribution.HtlcBasePoint.PubKey, HtlcPoint: ourContribution.HtlcBasePoint.PubKey,
FirstCommitmentPoint: ourContribution.FirstCommitmentPoint, FirstCommitmentPoint: ourContribution.FirstCommitmentPoint,
} }
err = f.cfg.SendToPeer(fmsg.peerAddress.IdentityKey, &fundingAccept) if err := fmsg.peer.SendMessage(false, &fundingAccept); err != nil {
if err != nil {
fndgLog.Errorf("unable to send funding response to peer: %v", err) fndgLog.Errorf("unable to send funding response to peer: %v", err)
f.failFundingFlow(fmsg.peerAddress.IdentityKey, f.failFundingFlow(fmsg.peer, msg.PendingChannelID, err)
msg.PendingChannelID, err)
return return
} }
} }
@ -1142,10 +1161,10 @@ func (f *fundingManager) handleFundingOpen(fmsg *fundingOpenMsg) {
// processFundingAccept sends a message to the fundingManager allowing it to // processFundingAccept sends a message to the fundingManager allowing it to
// continue the second phase of a funding workflow with the target peer. // continue the second phase of a funding workflow with the target peer.
func (f *fundingManager) processFundingAccept(msg *lnwire.AcceptChannel, func (f *fundingManager) processFundingAccept(msg *lnwire.AcceptChannel,
peerAddress *lnwire.NetAddress) { peer lnpeer.Peer) {
select { select {
case f.fundingMsgs <- &fundingAcceptMsg{msg, peerAddress}: case f.fundingMsgs <- &fundingAcceptMsg{msg, peer}:
case <-f.quit: case <-f.quit:
return return
} }
@ -1157,7 +1176,7 @@ func (f *fundingManager) processFundingAccept(msg *lnwire.AcceptChannel,
func (f *fundingManager) handleFundingAccept(fmsg *fundingAcceptMsg) { func (f *fundingManager) handleFundingAccept(fmsg *fundingAcceptMsg) {
msg := fmsg.msg msg := fmsg.msg
pendingChanID := fmsg.msg.PendingChannelID pendingChanID := fmsg.msg.PendingChannelID
peerKey := fmsg.peerAddress.IdentityKey peerKey := fmsg.peer.IdentityKey()
resCtx, err := f.getReservationCtx(peerKey, pendingChanID) resCtx, err := f.getReservationCtx(peerKey, pendingChanID)
if err != nil { if err != nil {
@ -1181,8 +1200,7 @@ func (f *fundingManager) handleFundingAccept(fmsg *fundingAcceptMsg) {
) )
if err != nil { if err != nil {
fndgLog.Warnf("Unacceptable channel constraints: %v", err) fndgLog.Warnf("Unacceptable channel constraints: %v", err)
f.failFundingFlow(fmsg.peerAddress.IdentityKey, f.failFundingFlow(fmsg.peer, fmsg.msg.PendingChannelID, err)
fmsg.msg.PendingChannelID, err)
return return
} }
@ -1228,9 +1246,8 @@ func (f *fundingManager) handleFundingAccept(fmsg *fundingAcceptMsg) {
err = resCtx.reservation.ProcessContribution(remoteContribution) err = resCtx.reservation.ProcessContribution(remoteContribution)
if err != nil { if err != nil {
fndgLog.Errorf("Unable to process contribution from %v: %v", fndgLog.Errorf("Unable to process contribution from %v: %v",
fmsg.peerAddress.IdentityKey, err) peerKey, err)
f.failFundingFlow(fmsg.peerAddress.IdentityKey, f.failFundingFlow(fmsg.peer, msg.PendingChannelID, err)
msg.PendingChannelID, err)
return return
} }
@ -1273,15 +1290,12 @@ func (f *fundingManager) handleFundingAccept(fmsg *fundingAcceptMsg) {
fundingCreated.CommitSig, err = lnwire.NewSigFromRawSignature(sig) fundingCreated.CommitSig, err = lnwire.NewSigFromRawSignature(sig)
if err != nil { if err != nil {
fndgLog.Errorf("Unable to parse signature: %v", err) fndgLog.Errorf("Unable to parse signature: %v", err)
f.failFundingFlow(fmsg.peerAddress.IdentityKey, f.failFundingFlow(fmsg.peer, msg.PendingChannelID, err)
msg.PendingChannelID, err)
return return
} }
err = f.cfg.SendToPeer(fmsg.peerAddress.IdentityKey, fundingCreated) if err := fmsg.peer.SendMessage(false, fundingCreated); err != nil {
if err != nil {
fndgLog.Errorf("Unable to send funding complete message: %v", err) fndgLog.Errorf("Unable to send funding complete message: %v", err)
f.failFundingFlow(fmsg.peerAddress.IdentityKey, f.failFundingFlow(fmsg.peer, msg.PendingChannelID, err)
msg.PendingChannelID, err)
return return
} }
} }
@ -1289,10 +1303,10 @@ func (f *fundingManager) handleFundingAccept(fmsg *fundingAcceptMsg) {
// processFundingCreated queues a funding complete message coupled with the // processFundingCreated queues a funding complete message coupled with the
// source peer to the fundingManager. // source peer to the fundingManager.
func (f *fundingManager) processFundingCreated(msg *lnwire.FundingCreated, func (f *fundingManager) processFundingCreated(msg *lnwire.FundingCreated,
peerAddress *lnwire.NetAddress) { peer lnpeer.Peer) {
select { select {
case f.fundingMsgs <- &fundingCreatedMsg{msg, peerAddress}: case f.fundingMsgs <- &fundingCreatedMsg{msg, peer}:
case <-f.quit: case <-f.quit:
return return
} }
@ -1303,7 +1317,7 @@ func (f *fundingManager) processFundingCreated(msg *lnwire.FundingCreated,
// processed, a signature is sent to the remote peer allowing it to broadcast // processed, a signature is sent to the remote peer allowing it to broadcast
// the funding transaction, progressing the workflow into the final stage. // the funding transaction, progressing the workflow into the final stage.
func (f *fundingManager) handleFundingCreated(fmsg *fundingCreatedMsg) { func (f *fundingManager) handleFundingCreated(fmsg *fundingCreatedMsg) {
peerKey := fmsg.peerAddress.IdentityKey peerKey := fmsg.peer.IdentityKey()
pendingChanID := fmsg.msg.PendingChannelID pendingChanID := fmsg.msg.PendingChannelID
resCtx, err := f.getReservationCtx(peerKey, pendingChanID) resCtx, err := f.getReservationCtx(peerKey, pendingChanID)
@ -1333,8 +1347,7 @@ func (f *fundingManager) handleFundingCreated(fmsg *fundingCreatedMsg) {
if err != nil { if err != nil {
// TODO(roasbeef): better error logging: peerID, channelID, etc. // TODO(roasbeef): better error logging: peerID, channelID, etc.
fndgLog.Errorf("unable to complete single reservation: %v", err) fndgLog.Errorf("unable to complete single reservation: %v", err)
f.failFundingFlow(fmsg.peerAddress.IdentityKey, f.failFundingFlow(fmsg.peer, pendingChanID, err)
pendingChanID, err)
return return
} }
@ -1374,8 +1387,7 @@ func (f *fundingManager) handleFundingCreated(fmsg *fundingCreatedMsg) {
ourCommitSig, err := lnwire.NewSigFromRawSignature(sig) ourCommitSig, err := lnwire.NewSigFromRawSignature(sig)
if err != nil { if err != nil {
fndgLog.Errorf("unable to parse signature: %v", err) fndgLog.Errorf("unable to parse signature: %v", err)
f.failFundingFlow(fmsg.peerAddress.IdentityKey, f.failFundingFlow(fmsg.peer, pendingChanID, err)
pendingChanID, err)
deleteFromDatabase() deleteFromDatabase()
return return
} }
@ -1384,10 +1396,9 @@ func (f *fundingManager) handleFundingCreated(fmsg *fundingCreatedMsg) {
ChanID: channelID, ChanID: channelID,
CommitSig: ourCommitSig, CommitSig: ourCommitSig,
} }
if err := f.cfg.SendToPeer(peerKey, fundingSigned); err != nil { if err := fmsg.peer.SendMessage(false, fundingSigned); err != nil {
fndgLog.Errorf("unable to send FundingSigned message: %v", err) fndgLog.Errorf("unable to send FundingSigned message: %v", err)
f.failFundingFlow(fmsg.peerAddress.IdentityKey, f.failFundingFlow(fmsg.peer, pendingChanID, err)
pendingChanID, err)
deleteFromDatabase() deleteFromDatabase()
return return
} }
@ -1395,8 +1406,7 @@ func (f *fundingManager) handleFundingCreated(fmsg *fundingCreatedMsg) {
// Now that we've sent over our final signature for this channel, we'll // Now that we've sent over our final signature for this channel, we'll
// send it to the ChainArbitrator so it can watch for any on-chain // send it to the ChainArbitrator so it can watch for any on-chain
// actions during this final confirmation stage. // actions during this final confirmation stage.
peerAddr := resCtx.peerAddress if err := f.cfg.WatchNewChannel(completeChan, peerKey); err != nil {
if err := f.cfg.WatchNewChannel(completeChan, peerAddr); err != nil {
fndgLog.Errorf("Unable to send new ChannelPoint(%v) for "+ fndgLog.Errorf("Unable to send new ChannelPoint(%v) for "+
"arbitration: %v", fundingOut, err) "arbitration: %v", fundingOut, err)
} }
@ -1446,8 +1456,7 @@ func (f *fundingManager) handleFundingCreated(fmsg *fundingCreatedMsg) {
err := fmt.Errorf("timeout waiting for funding tx "+ err := fmt.Errorf("timeout waiting for funding tx "+
"(%v) to confirm", completeChan.FundingOutpoint) "(%v) to confirm", completeChan.FundingOutpoint)
fndgLog.Warnf(err.Error()) fndgLog.Warnf(err.Error())
f.failFundingFlow(fmsg.peerAddress.IdentityKey, f.failFundingFlow(fmsg.peer, pendingChanID, err)
pendingChanID, err)
deleteFromDatabase() deleteFromDatabase()
return return
case <-f.quit: case <-f.quit:
@ -1466,8 +1475,9 @@ func (f *fundingManager) handleFundingCreated(fmsg *fundingCreatedMsg) {
// Success, funding transaction was confirmed. // Success, funding transaction was confirmed.
f.deleteReservationCtx(peerKey, fmsg.msg.PendingChannelID) f.deleteReservationCtx(peerKey, fmsg.msg.PendingChannelID)
err := f.handleFundingConfirmation(completeChan, err := f.handleFundingConfirmation(
shortChanID) fmsg.peer, completeChan, shortChanID,
)
if err != nil { if err != nil {
fndgLog.Errorf("failed to handle funding"+ fndgLog.Errorf("failed to handle funding"+
"confirmation: %v", err) "confirmation: %v", err)
@ -1479,10 +1489,10 @@ func (f *fundingManager) handleFundingCreated(fmsg *fundingCreatedMsg) {
// processFundingSigned sends a single funding sign complete message along with // processFundingSigned sends a single funding sign complete message along with
// the source peer to the funding manager. // the source peer to the funding manager.
func (f *fundingManager) processFundingSigned(msg *lnwire.FundingSigned, func (f *fundingManager) processFundingSigned(msg *lnwire.FundingSigned,
peerAddress *lnwire.NetAddress) { peer lnpeer.Peer) {
select { select {
case f.fundingMsgs <- &fundingSignedMsg{msg, peerAddress}: case f.fundingMsgs <- &fundingSignedMsg{msg, peer}:
case <-f.quit: case <-f.quit:
return return
} }
@ -1505,20 +1515,17 @@ func (f *fundingManager) handleFundingSigned(fmsg *fundingSignedMsg) {
err := fmt.Errorf("Unable to find signed reservation for "+ err := fmt.Errorf("Unable to find signed reservation for "+
"chan_id=%x", fmsg.msg.ChanID) "chan_id=%x", fmsg.msg.ChanID)
fndgLog.Warnf(err.Error()) fndgLog.Warnf(err.Error())
f.failFundingFlow(fmsg.peerAddress.IdentityKey, f.failFundingFlow(fmsg.peer, fmsg.msg.ChanID, err)
fmsg.msg.ChanID, err)
return return
} }
peerKey := fmsg.peerAddress.IdentityKey peerKey := fmsg.peer.IdentityKey()
resCtx, err := f.getReservationCtx(fmsg.peerAddress.IdentityKey, resCtx, err := f.getReservationCtx(peerKey, pendingChanID)
pendingChanID)
if err != nil { if err != nil {
fndgLog.Warnf("Unable to find reservation (peerID:%v, chanID:%x)", fndgLog.Warnf("Unable to find reservation (peerID:%v, chanID:%x)",
peerKey, pendingChanID[:]) peerKey, pendingChanID[:])
// TODO: add ErrChanNotFound? // TODO: add ErrChanNotFound?
f.failFundingFlow(fmsg.peerAddress.IdentityKey, f.failFundingFlow(fmsg.peer, pendingChanID, err)
pendingChanID, err)
return return
} }
@ -1538,8 +1545,7 @@ func (f *fundingManager) handleFundingSigned(fmsg *fundingSignedMsg) {
completeChan, err := resCtx.reservation.CompleteReservation(nil, commitSig) completeChan, err := resCtx.reservation.CompleteReservation(nil, commitSig)
if err != nil { if err != nil {
fndgLog.Errorf("Unable to complete reservation sign complete: %v", err) fndgLog.Errorf("Unable to complete reservation sign complete: %v", err)
f.failFundingFlow(fmsg.peerAddress.IdentityKey, f.failFundingFlow(fmsg.peer, pendingChanID, err)
pendingChanID, err)
return return
} }
@ -1547,14 +1553,14 @@ func (f *fundingManager) handleFundingSigned(fmsg *fundingSignedMsg) {
// we'll send the to be active channel to the ChainArbitrator so it can // we'll send the to be active channel to the ChainArbitrator so it can
// watch for any on-chin actions before the channel has fully // watch for any on-chin actions before the channel has fully
// confirmed. // confirmed.
peerAddr := resCtx.peerAddress if err := f.cfg.WatchNewChannel(completeChan, peerKey); err != nil {
if err := f.cfg.WatchNewChannel(completeChan, peerAddr); err != nil {
fndgLog.Errorf("Unable to send new ChannelPoint(%v) for "+ fndgLog.Errorf("Unable to send new ChannelPoint(%v) for "+
"arbitration: %v", fundingPoint, err) "arbitration: %v", fundingPoint, err)
} }
fndgLog.Infof("Finalizing pendingID(%x) over ChannelPoint(%v), "+ fndgLog.Infof("Finalizing pendingID(%x) over ChannelPoint(%v), "+
"waiting for channel open on-chain", pendingChanID[:], fundingPoint) "waiting for channel open on-chain", pendingChanID[:],
fundingPoint)
// Send an update to the upstream client that the negotiation process // Send an update to the upstream client that the negotiation process
// is over. // is over.
@ -1619,7 +1625,9 @@ func (f *fundingManager) handleFundingSigned(fmsg *fundingSignedMsg) {
} }
defer lnChannel.Stop() defer lnChannel.Stop()
err = f.sendFundingLocked(completeChan, lnChannel, shortChanID) err = f.sendFundingLocked(
fmsg.peer, completeChan, lnChannel, shortChanID,
)
if err != nil { if err != nil {
fndgLog.Errorf("failed sending fundingLocked: %v", err) fndgLog.Errorf("failed sending fundingLocked: %v", err)
return return
@ -1865,10 +1873,11 @@ func (f *fundingManager) waitForFundingConfirmation(completeChan *channeldb.Open
} }
// handleFundingConfirmation is a wrapper method for creating a new // handleFundingConfirmation is a wrapper method for creating a new
// lnwallet.LightningChannel object, calling sendFundingLocked, addToRouterGraph, // lnwallet.LightningChannel object, calling sendFundingLocked,
// and annAfterSixConfs. This is called after the funding transaction is // addToRouterGraph, and annAfterSixConfs. This is called after the funding
// confirmed. // transaction is confirmed.
func (f *fundingManager) handleFundingConfirmation(completeChan *channeldb.OpenChannel, func (f *fundingManager) handleFundingConfirmation(peer lnpeer.Peer,
completeChan *channeldb.OpenChannel,
shortChanID *lnwire.ShortChannelID) error { shortChanID *lnwire.ShortChannelID) error {
// We create the state-machine object which wraps the database state. // We create the state-machine object which wraps the database state.
@ -1884,7 +1893,7 @@ func (f *fundingManager) handleFundingConfirmation(completeChan *channeldb.OpenC
fndgLog.Debugf("ChannelID(%v) is now fully confirmed!", chanID) fndgLog.Debugf("ChannelID(%v) is now fully confirmed!", chanID)
err = f.sendFundingLocked(completeChan, lnChannel, shortChanID) err = f.sendFundingLocked(peer, completeChan, lnChannel, shortChanID)
if err != nil { if err != nil {
return fmt.Errorf("failed sending fundingLocked: %v", err) return fmt.Errorf("failed sending fundingLocked: %v", err)
} }
@ -1904,11 +1913,12 @@ func (f *fundingManager) handleFundingConfirmation(completeChan *channeldb.OpenC
// sendFundingLocked creates and sends the fundingLocked message. // sendFundingLocked creates and sends the fundingLocked message.
// This should be called after the funding transaction has been confirmed, // This should be called after the funding transaction has been confirmed,
// and the channelState is 'markedOpen'. // and the channelState is 'markedOpen'.
func (f *fundingManager) sendFundingLocked(completeChan *channeldb.OpenChannel, func (f *fundingManager) sendFundingLocked(peer lnpeer.Peer,
channel *lnwallet.LightningChannel, completeChan *channeldb.OpenChannel, channel *lnwallet.LightningChannel,
shortChanID *lnwire.ShortChannelID) error { shortChanID *lnwire.ShortChannelID) error {
chanID := lnwire.NewChanIDFromOutPoint(&completeChan.FundingOutpoint) chanID := lnwire.NewChanIDFromOutPoint(&completeChan.FundingOutpoint)
peerKey := completeChan.IdentityPub
// Next, we'll send over the funding locked message which marks that we // Next, we'll send over the funding locked message which marks that we
// consider the channel open by presenting the remote party with our // consider the channel open by presenting the remote party with our
@ -1933,33 +1943,30 @@ func (f *fundingManager) sendFundingLocked(completeChan *channeldb.OpenChannel,
// down. // down.
for { for {
fndgLog.Debugf("Sending FundingLocked for ChannelID(%v) to "+ fndgLog.Debugf("Sending FundingLocked for ChannelID(%v) to "+
"peer %x", chanID, "peer %x", chanID, peerKey.SerializeCompressed())
completeChan.IdentityPub.SerializeCompressed())
err = f.cfg.SendToPeer(completeChan.IdentityPub, if err := peer.SendMessage(false, fundingLockedMsg); err == nil {
fundingLockedMsg) // Sending succeeded, we can break out and continue the
if err == nil { // funding flow.
// Sending succeeded, we can break out and continue
// the funding flow.
break break
} }
fndgLog.Warnf("unable to send fundingLocked to peer %x: "+ fndgLog.Warnf("Unable to send fundingLocked to peer %x: %v. "+
"%v. Will retry when online", "Will retry when online", peerKey.SerializeCompressed(),
completeChan.IdentityPub.SerializeCompressed(), err) err)
connected := make(chan struct{}) connected := make(chan lnpeer.Peer, 1)
f.cfg.NotifyWhenOnline(completeChan.IdentityPub, connected) f.cfg.NotifyWhenOnline(completeChan.IdentityPub, connected)
select { select {
case <-connected: case <-connected:
fndgLog.Infof("Peer(%x) came back online, will retry "+ fndgLog.Infof("Peer(%x) came back online, will retry "+
"sending FundingLocked for ChannelID(%v)", "sending FundingLocked for ChannelID(%v)",
completeChan.IdentityPub.SerializeCompressed(), peerKey.SerializeCompressed(), chanID)
chanID)
// Retry sending. // Retry sending.
case <-f.quit: case <-f.quit:
return fmt.Errorf("shutting down unable to send") return ErrFundingManagerShuttingDown
} }
} }
@ -2069,24 +2076,28 @@ func (f *fundingManager) annAfterSixConfs(completeChan *channeldb.OpenChannel,
confNtfn, err := f.cfg.Notifier.RegisterConfirmationsNtfn(&txid, confNtfn, err := f.cfg.Notifier.RegisterConfirmationsNtfn(&txid,
numConfs, completeChan.FundingBroadcastHeight) numConfs, completeChan.FundingBroadcastHeight)
if err != nil { if err != nil {
return fmt.Errorf("Unable to register for confirmation of "+ return fmt.Errorf("Unable to register for "+
"ChannelPoint(%v): %v", completeChan.FundingOutpoint, err) "confirmation of ChannelPoint(%v): %v",
completeChan.FundingOutpoint, err)
} }
// Wait until 6 confirmations has been reached or the wallet signals // Wait until 6 confirmations has been reached or the wallet
// a shutdown. // signals a shutdown.
select { select {
case _, ok := <-confNtfn.Confirmed: case _, ok := <-confNtfn.Confirmed:
if !ok { if !ok {
return fmt.Errorf("ChainNotifier shutting down, cannot "+ return fmt.Errorf("ChainNotifier shutting "+
"complete funding flow for ChannelPoint(%v)", "down, cannot complete funding flow "+
"for ChannelPoint(%v)",
completeChan.FundingOutpoint) completeChan.FundingOutpoint)
} }
// Fallthrough. // Fallthrough.
case <-f.quit: case <-f.quit:
return fmt.Errorf("fundingManager shutting down, stopping funding "+ return fmt.Errorf("%v, stopping funding flow for "+
"flow for ChannelPoint(%v)", completeChan.FundingOutpoint) "ChannelPoint(%v)",
ErrFundingManagerShuttingDown,
completeChan.FundingOutpoint)
} }
fundingPoint := completeChan.FundingOutpoint fundingPoint := completeChan.FundingOutpoint
@ -2095,9 +2106,10 @@ func (f *fundingManager) annAfterSixConfs(completeChan *channeldb.OpenChannel,
fndgLog.Infof("Announcing ChannelPoint(%v), short_chan_id=%v", fndgLog.Infof("Announcing ChannelPoint(%v), short_chan_id=%v",
&fundingPoint, spew.Sdump(shortChanID)) &fundingPoint, spew.Sdump(shortChanID))
// We'll obtain their min HTLC as we'll use this value within our // We'll obtain their min HTLC as we'll use this value within
// ChannelUpdate. We use this value isn't of ours, as the remote party // our ChannelUpdate. We use this value isn't of ours, as the
// will be the one that's carrying the HTLC towards us. // remote party will be the one that's carrying the HTLC towards
// us.
remoteMinHTLC := completeChan.RemoteChanCfg.MinHTLC remoteMinHTLC := completeChan.RemoteChanCfg.MinHTLC
// Create and broadcast the proofs required to make this channel // Create and broadcast the proofs required to make this channel
@ -2131,10 +2143,10 @@ func (f *fundingManager) annAfterSixConfs(completeChan *channeldb.OpenChannel,
// processFundingLocked sends a message to the fundingManager allowing it to // processFundingLocked sends a message to the fundingManager allowing it to
// finish the funding workflow. // finish the funding workflow.
func (f *fundingManager) processFundingLocked(msg *lnwire.FundingLocked, func (f *fundingManager) processFundingLocked(msg *lnwire.FundingLocked,
peerAddress *lnwire.NetAddress) { peer lnpeer.Peer) {
select { select {
case f.fundingMsgs <- &fundingLockedMsg{msg, peerAddress}: case f.fundingMsgs <- &fundingLockedMsg{msg, peer}:
case <-f.quit: case <-f.quit:
return return
} }
@ -2146,7 +2158,7 @@ func (f *fundingManager) handleFundingLocked(fmsg *fundingLockedMsg) {
defer f.wg.Done() defer f.wg.Done()
fndgLog.Debugf("Received FundingLocked for ChannelID(%v) from "+ fndgLog.Debugf("Received FundingLocked for ChannelID(%v) from "+
"peer %x", fmsg.msg.ChanID, "peer %x", fmsg.msg.ChanID,
fmsg.peerAddress.IdentityKey.SerializeCompressed()) fmsg.peer.IdentityKey().SerializeCompressed())
// If we are currently in the process of handling a funding locked // If we are currently in the process of handling a funding locked
// message for this channel, ignore. // message for this channel, ignore.
@ -2242,32 +2254,11 @@ func (f *fundingManager) handleFundingLocked(fmsg *fundingLockedMsg) {
f.barrierMtx.Unlock() f.barrierMtx.Unlock()
}() }()
// Finally, we'll find the peer that sent us this message so we can if err := fmsg.peer.AddNewChannel(channel, f.quit); err != nil {
// provide it with the fully initialized channel state. fndgLog.Errorf("Unable to add new channel %v with peer %x: %v",
peer, err := f.cfg.FindPeer(fmsg.peerAddress.IdentityKey) fmsg.peer.IdentityKey().SerializeCompressed(),
if err != nil { *channel.ChanPoint, err)
fndgLog.Errorf("Unable to find peer: %v", err)
channel.Stop() channel.Stop()
return
}
newChanDone := make(chan struct{})
newChanMsg := &newChannelMsg{
channel: channel,
done: newChanDone,
}
select {
case peer.newChannels <- newChanMsg:
case <-f.quit:
return
}
// We pause here to wait for the peer to recognize the new channel
// before we close the channel barrier corresponding to the channel.
select {
case <-f.quit:
return
case <-newChanDone: // Fallthrough if we're not quitting.
} }
} }
@ -2486,11 +2477,9 @@ func (f *fundingManager) announceChannel(localIDKey, remoteIDKey, localFundingKe
// initFundingWorkflow sends a message to the funding manager instructing it // initFundingWorkflow sends a message to the funding manager instructing it
// to initiate a single funder workflow with the source peer. // to initiate a single funder workflow with the source peer.
// TODO(roasbeef): re-visit blocking nature.. // TODO(roasbeef): re-visit blocking nature..
func (f *fundingManager) initFundingWorkflow(peerAddress *lnwire.NetAddress, func (f *fundingManager) initFundingWorkflow(peer lnpeer.Peer, req *openChanReq) {
req *openChanReq) {
f.fundingRequests <- &initFundingMsg{ f.fundingRequests <- &initFundingMsg{
peerAddress: peerAddress, peer: peer,
openChanReq: req, openChanReq: req,
} }
} }
@ -2500,7 +2489,7 @@ func (f *fundingManager) initFundingWorkflow(peerAddress *lnwire.NetAddress,
// funding workflow. // funding workflow.
func (f *fundingManager) handleInitFundingMsg(msg *initFundingMsg) { func (f *fundingManager) handleInitFundingMsg(msg *initFundingMsg) {
var ( var (
peerKey = msg.peerAddress.IdentityKey peerKey = msg.peer.IdentityKey()
localAmt = msg.localFundingAmt localAmt = msg.localFundingAmt
remoteAmt = msg.remoteFundingAmt remoteAmt = msg.remoteFundingAmt
capacity = localAmt + remoteAmt capacity = localAmt + remoteAmt
@ -2519,8 +2508,7 @@ func (f *fundingManager) handleInitFundingMsg(msg *initFundingMsg) {
fndgLog.Infof("Initiating fundingRequest(localAmt=%v, remoteAmt=%v, "+ fndgLog.Infof("Initiating fundingRequest(localAmt=%v, remoteAmt=%v, "+
"capacity=%v, chainhash=%v, addr=%v, dustLimit=%v)", localAmt, "capacity=%v, chainhash=%v, addr=%v, dustLimit=%v)", localAmt,
msg.pushAmt, capacity, msg.chainHash, msg.peerAddress.Address, msg.pushAmt, capacity, msg.chainHash, peerKey, ourDustLimit)
ourDustLimit)
// First, we'll query the fee estimator for a fee that should get the // First, we'll query the fee estimator for a fee that should get the
// commitment transaction confirmed by the next few blocks (conf target // commitment transaction confirmed by the next few blocks (conf target
@ -2556,7 +2544,7 @@ func (f *fundingManager) handleInitFundingMsg(msg *initFundingMsg) {
// request will fail, and be aborted. // request will fail, and be aborted.
reservation, err := f.cfg.Wallet.InitChannelReservation( reservation, err := f.cfg.Wallet.InitChannelReservation(
capacity, localAmt, msg.pushAmt, commitFeePerKw, capacity, localAmt, msg.pushAmt, commitFeePerKw,
msg.fundingFeePerVSize, peerKey, msg.peerAddress.Address, msg.fundingFeePerVSize, peerKey, msg.peer.Address(),
&msg.chainHash, channelFlags, &msg.chainHash, channelFlags,
) )
if err != nil { if err != nil {
@ -2597,7 +2585,7 @@ func (f *fundingManager) handleInitFundingMsg(msg *initFundingMsg) {
remoteCsvDelay: remoteCsvDelay, remoteCsvDelay: remoteCsvDelay,
remoteMinHtlc: minHtlc, remoteMinHtlc: minHtlc,
reservation: reservation, reservation: reservation,
peerAddress: msg.peerAddress, peer: msg.peer,
updates: msg.updates, updates: msg.updates,
err: msg.err, err: msg.err,
} }
@ -2619,7 +2607,7 @@ func (f *fundingManager) handleInitFundingMsg(msg *initFundingMsg) {
maxHtlcs := f.cfg.RequiredRemoteMaxHTLCs(capacity) maxHtlcs := f.cfg.RequiredRemoteMaxHTLCs(capacity)
fndgLog.Infof("Starting funding workflow with %v for pendingID(%x)", fndgLog.Infof("Starting funding workflow with %v for pendingID(%x)",
msg.peerAddress.Address, chanID) msg.peer.Address(), chanID)
fundingOpen := lnwire.OpenChannel{ fundingOpen := lnwire.OpenChannel{
ChainHash: *f.cfg.Wallet.Cfg.NetParams.GenesisHash, ChainHash: *f.cfg.Wallet.Cfg.NetParams.GenesisHash,
@ -2641,7 +2629,7 @@ func (f *fundingManager) handleInitFundingMsg(msg *initFundingMsg) {
FirstCommitmentPoint: ourContribution.FirstCommitmentPoint, FirstCommitmentPoint: ourContribution.FirstCommitmentPoint,
ChannelFlags: channelFlags, ChannelFlags: channelFlags,
} }
if err := f.cfg.SendToPeer(peerKey, &fundingOpen); err != nil { if err := msg.peer.SendMessage(false, &fundingOpen); err != nil {
e := fmt.Errorf("Unable to send funding request message: %v", e := fmt.Errorf("Unable to send funding request message: %v",
err) err)
fndgLog.Errorf(e.Error()) fndgLog.Errorf(e.Error())
@ -2681,10 +2669,10 @@ func (f *fundingManager) waitUntilChannelOpen(targetChan lnwire.ChannelID) {
// processFundingError sends a message to the fundingManager allowing it to // processFundingError sends a message to the fundingManager allowing it to
// process the occurred generic error. // process the occurred generic error.
func (f *fundingManager) processFundingError(err *lnwire.Error, func (f *fundingManager) processFundingError(err *lnwire.Error,
peerAddress *lnwire.NetAddress) { peerKey *btcec.PublicKey) {
select { select {
case f.fundingMsgs <- &fundingErrorMsg{err, peerAddress}: case f.fundingMsgs <- &fundingErrorMsg{err, peerKey}:
case <-f.quit: case <-f.quit:
return return
} }
@ -2696,13 +2684,12 @@ func (f *fundingManager) processFundingError(err *lnwire.Error,
func (f *fundingManager) handleErrorMsg(fmsg *fundingErrorMsg) { func (f *fundingManager) handleErrorMsg(fmsg *fundingErrorMsg) {
protocolErr := fmsg.err protocolErr := fmsg.err
peerKey := fmsg.peerAddress.IdentityKey
chanID := fmsg.err.ChanID chanID := fmsg.err.ChanID
// First, we'll attempt to retrieve and cancel the funding workflow // First, we'll attempt to retrieve and cancel the funding workflow
// that this error was tied to. If we're unable to do so, then we'll // that this error was tied to. If we're unable to do so, then we'll
// exit early as this was an unwarranted error. // exit early as this was an unwarranted error.
resCtx, err := f.cancelReservationCtx(peerKey, chanID) resCtx, err := f.cancelReservationCtx(fmsg.peerKey, chanID)
if err != nil { if err != nil {
fndgLog.Warnf("Received error for non-existent funding "+ fndgLog.Warnf("Received error for non-existent funding "+
"flow: %v (%v)", err, spew.Sdump(protocolErr)) "flow: %v (%v)", err, spew.Sdump(protocolErr))
@ -2713,7 +2700,7 @@ func (f *fundingManager) handleErrorMsg(fmsg *fundingErrorMsg) {
// error back to the caller (if any), and cancel the workflow itself. // error back to the caller (if any), and cancel the workflow itself.
lnErr := lnwire.ErrorCode(protocolErr.Data[0]) lnErr := lnwire.ErrorCode(protocolErr.Data[0])
fndgLog.Errorf("Received funding error from %x: %v", fndgLog.Errorf("Received funding error from %x: %v",
peerKey.SerializeCompressed(), string(protocolErr.Data), fmsg.peerKey.SerializeCompressed(), string(protocolErr.Data),
) )
// If this isn't a simple error code, then we'll display the entire // If this isn't a simple error code, then we'll display the entire
@ -2753,10 +2740,11 @@ func (f *fundingManager) pruneZombieReservations() {
f.resMtx.RUnlock() f.resMtx.RUnlock()
for pendingChanID, resCtx := range zombieReservations { for pendingChanID, resCtx := range zombieReservations {
err := fmt.Errorf("reservation timed out waiting for peer (peerID:%v, "+ err := fmt.Errorf("reservation timed out waiting for peer "+
"chanID:%x)", resCtx.peerAddress.IdentityKey, pendingChanID[:]) "(peerID:%v, chanID:%x)", resCtx.peer.IdentityKey(),
pendingChanID[:])
fndgLog.Warnf(err.Error()) fndgLog.Warnf(err.Error())
f.failFundingFlow(resCtx.peerAddress.IdentityKey, pendingChanID, err) f.failFundingFlow(resCtx.peer, pendingChanID, err)
} }
} }
@ -2849,9 +2837,9 @@ func (f *fundingManager) getReservationCtx(peerKey *btcec.PublicKey,
// channel will receive a new, permanent channel ID, and will no longer be // channel will receive a new, permanent channel ID, and will no longer be
// considered pending. // considered pending.
func (f *fundingManager) IsPendingChannel(pendingChanID [32]byte, func (f *fundingManager) IsPendingChannel(pendingChanID [32]byte,
peerAddress *lnwire.NetAddress) bool { peerKey *btcec.PublicKey) bool {
peerIDKey := newSerializedKey(peerAddress.IdentityKey) peerIDKey := newSerializedKey(peerKey)
f.resMtx.RLock() f.resMtx.RLock()
_, ok := f.activeReservations[peerIDKey][pendingChanID] _, ok := f.activeReservations[peerIDKey][pendingChanID]
f.resMtx.RUnlock() f.resMtx.RUnlock()

@ -3,6 +3,7 @@
package main package main
import ( import (
"errors"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"math/big" "math/big"
@ -12,22 +13,22 @@ import (
"testing" "testing"
"time" "time"
"github.com/btcsuite/btcd/btcec"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btclog" "github.com/btcsuite/btclog"
"github.com/btcsuite/btcutil"
_ "github.com/btcsuite/btcwallet/walletdb/bdb"
"github.com/lightningnetwork/lnd/chainntnfs" "github.com/lightningnetwork/lnd/chainntnfs"
"github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/channeldb"
"github.com/lightningnetwork/lnd/contractcourt" "github.com/lightningnetwork/lnd/contractcourt"
"github.com/lightningnetwork/lnd/htlcswitch" "github.com/lightningnetwork/lnd/htlcswitch"
"github.com/lightningnetwork/lnd/keychain" "github.com/lightningnetwork/lnd/keychain"
"github.com/lightningnetwork/lnd/lnpeer"
"github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lnwallet" "github.com/lightningnetwork/lnd/lnwallet"
"github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/lnwire"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash"
_ "github.com/btcsuite/btcwallet/walletdb/bdb"
"github.com/btcsuite/btcd/btcec"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
) )
const ( const (
@ -134,14 +135,64 @@ func (m *mockNotifier) RegisterSpendNtfn(outpoint *wire.OutPoint,
type testNode struct { type testNode struct {
privKey *btcec.PrivateKey privKey *btcec.PrivateKey
addr *lnwire.NetAddress
msgChan chan lnwire.Message msgChan chan lnwire.Message
announceChan chan lnwire.Message announceChan chan lnwire.Message
publTxChan chan *wire.MsgTx publTxChan chan *wire.MsgTx
fundingMgr *fundingManager fundingMgr *fundingManager
peer *peer newChannels chan *newChannelMsg
mockNotifier *mockNotifier mockNotifier *mockNotifier
testDir string testDir string
shutdownChannel chan struct{} shutdownChannel chan struct{}
remotePeer *testNode
sendMessage func(lnwire.Message) error
}
var _ lnpeer.Peer = (*testNode)(nil)
func (n *testNode) IdentityKey() *btcec.PublicKey {
return n.addr.IdentityKey
}
func (n *testNode) Address() net.Addr {
return n.addr.Address
}
func (n *testNode) PubKey() [33]byte {
return newSerializedKey(n.addr.IdentityKey)
}
func (n *testNode) SendMessage(_ bool, msg ...lnwire.Message) error {
return n.sendMessage(msg[0])
}
func (n *testNode) WipeChannel(_ *wire.OutPoint) error {
return nil
}
func (n *testNode) AddNewChannel(channel *lnwallet.LightningChannel,
quit <-chan struct{}) error {
done := make(chan struct{})
msg := &newChannelMsg{
channel: channel,
done: done,
}
select {
case n.newChannels <- msg:
case <-quit:
return ErrFundingManagerShuttingDown
}
select {
case <-done:
case <-quit:
return ErrFundingManagerShuttingDown
}
return nil
} }
func init() { func init() {
@ -180,7 +231,7 @@ func createTestWallet(cdb *channeldb.DB, netParams *chaincfg.Params,
} }
func createTestFundingManager(t *testing.T, privKey *btcec.PrivateKey, func createTestFundingManager(t *testing.T, privKey *btcec.PrivateKey,
tempTestDir string) (*testNode, error) { addr *lnwire.NetAddress, tempTestDir string) (*testNode, error) {
netParams := activeNetParams.Params netParams := activeNetParams.Params
estimator := lnwallet.StaticFeeEstimator{FeeRate: 250} estimator := lnwallet.StaticFeeEstimator{FeeRate: 250}
@ -191,11 +242,6 @@ func createTestFundingManager(t *testing.T, privKey *btcec.PrivateKey,
epochChan: make(chan *chainntnfs.BlockEpoch, 1), epochChan: make(chan *chainntnfs.BlockEpoch, 1),
} }
newChannelsChan := make(chan *newChannelMsg)
p := &peer{
newChannels: newChannelsChan,
}
sentMessages := make(chan lnwire.Message) sentMessages := make(chan lnwire.Message)
sentAnnouncements := make(chan lnwire.Message) sentAnnouncements := make(chan lnwire.Message)
publTxChan := make(chan *wire.MsgTx, 1) publTxChan := make(chan *wire.MsgTx, 1)
@ -249,20 +295,6 @@ func createTestFundingManager(t *testing.T, privKey *btcec.PrivateKey,
CurrentNodeAnnouncement: func() (lnwire.NodeAnnouncement, error) { CurrentNodeAnnouncement: func() (lnwire.NodeAnnouncement, error) {
return lnwire.NodeAnnouncement{}, nil return lnwire.NodeAnnouncement{}, nil
}, },
SendToPeer: func(target *btcec.PublicKey, msgs ...lnwire.Message) error {
select {
case sentMessages <- msgs[0]:
case <-shutdownChan:
return fmt.Errorf("shutting down")
}
return nil
},
NotifyWhenOnline: func(peer *btcec.PublicKey, connectedChan chan<- struct{}) {
t.Fatalf("did not expect fundingManager to call NotifyWhenOnline")
},
FindPeer: func(peerKey *btcec.PublicKey) (*peer, error) {
return p, nil
},
TempChanIDSeed: chanIDSeed, TempChanIDSeed: chanIDSeed,
FindChannel: func(chanID lnwire.ChannelID) (*lnwallet.LightningChannel, error) { FindChannel: func(chanID lnwire.ChannelID) (*lnwallet.LightningChannel, error) {
dbChannels, err := cdb.FetchAllChannels() dbChannels, err := cdb.FetchAllChannels()
@ -311,7 +343,7 @@ func createTestFundingManager(t *testing.T, privKey *btcec.PrivateKey,
RequiredRemoteMaxHTLCs: func(chanAmt btcutil.Amount) uint16 { RequiredRemoteMaxHTLCs: func(chanAmt btcutil.Amount) uint16 {
return uint16(lnwallet.MaxHTLCNumber / 2) return uint16(lnwallet.MaxHTLCNumber / 2)
}, },
WatchNewChannel: func(*channeldb.OpenChannel, *lnwire.NetAddress) error { WatchNewChannel: func(*channeldb.OpenChannel, *btcec.PublicKey) error {
return nil return nil
}, },
ReportShortChanID: func(wire.OutPoint) error { ReportShortChanID: func(wire.OutPoint) error {
@ -323,22 +355,30 @@ func createTestFundingManager(t *testing.T, privKey *btcec.PrivateKey,
if err != nil { if err != nil {
t.Fatalf("failed creating fundingManager: %v", err) t.Fatalf("failed creating fundingManager: %v", err)
} }
if err = f.Start(); err != nil { if err = f.Start(); err != nil {
t.Fatalf("failed starting fundingManager: %v", err) t.Fatalf("failed starting fundingManager: %v", err)
} }
return &testNode{ testNode := &testNode{
privKey: privKey, privKey: privKey,
msgChan: sentMessages, msgChan: sentMessages,
newChannels: make(chan *newChannelMsg),
announceChan: sentAnnouncements, announceChan: sentAnnouncements,
publTxChan: publTxChan, publTxChan: publTxChan,
fundingMgr: f, fundingMgr: f,
peer: p,
mockNotifier: chainNotifier, mockNotifier: chainNotifier,
testDir: tempTestDir, testDir: tempTestDir,
shutdownChannel: shutdownChan, shutdownChannel: shutdownChan,
}, nil addr: addr,
}
f.cfg.NotifyWhenOnline = func(peer *btcec.PublicKey,
connectedChan chan<- lnpeer.Peer) {
connectedChan <- testNode
}
return testNode, nil
} }
func recreateAliceFundingManager(t *testing.T, alice *testNode) { func recreateAliceFundingManager(t *testing.T, alice *testNode) {
@ -375,19 +415,11 @@ func recreateAliceFundingManager(t *testing.T, alice *testNode) {
CurrentNodeAnnouncement: func() (lnwire.NodeAnnouncement, error) { CurrentNodeAnnouncement: func() (lnwire.NodeAnnouncement, error) {
return lnwire.NodeAnnouncement{}, nil return lnwire.NodeAnnouncement{}, nil
}, },
SendToPeer: func(target *btcec.PublicKey, NotifyWhenOnline: func(peer *btcec.PublicKey,
msgs ...lnwire.Message) error { connectedChan chan<- lnpeer.Peer) {
select {
case aliceMsgChan <- msgs[0]: connectedChan <- alice.remotePeer
case <-shutdownChan:
return fmt.Errorf("shutting down")
}
return nil
}, },
NotifyWhenOnline: func(peer *btcec.PublicKey, connectedChan chan<- struct{}) {
t.Fatalf("did not expect fundingManager to call NotifyWhenOnline")
},
FindPeer: oldCfg.FindPeer,
TempChanIDSeed: oldCfg.TempChanIDSeed, TempChanIDSeed: oldCfg.TempChanIDSeed,
FindChannel: oldCfg.FindChannel, FindChannel: oldCfg.FindChannel,
PublishTransaction: func(txn *wire.MsgTx) error { PublishTransaction: func(txn *wire.MsgTx) error {
@ -424,7 +456,9 @@ func setupFundingManagers(t *testing.T) (*testNode, *testNode) {
t.Fatalf("unable to create temp directory: %v", err) t.Fatalf("unable to create temp directory: %v", err)
} }
alice, err := createTestFundingManager(t, alicePrivKey, aliceTestDir) alice, err := createTestFundingManager(
t, alicePrivKey, aliceAddr, aliceTestDir,
)
if err != nil { if err != nil {
t.Fatalf("failed creating fundingManager: %v", err) t.Fatalf("failed creating fundingManager: %v", err)
} }
@ -434,11 +468,37 @@ func setupFundingManagers(t *testing.T) (*testNode, *testNode) {
t.Fatalf("unable to create temp directory: %v", err) t.Fatalf("unable to create temp directory: %v", err)
} }
bob, err := createTestFundingManager(t, bobPrivKey, bobTestDir) bob, err := createTestFundingManager(t, bobPrivKey, bobAddr, bobTestDir)
if err != nil { if err != nil {
t.Fatalf("failed creating fundingManager: %v", err) t.Fatalf("failed creating fundingManager: %v", err)
} }
// With the funding manager's created, we'll now attempt to mimic a
// connection pipe between them. In order to intercept the messages
// within it, we'll redirect all messages back to the msgChan of the
// sender. Since the fundingManager now has a reference to peers itself,
// alice.sendMessage will be triggered when Bob's funding manager
// attempts to send a message to Alice and vice versa.
alice.remotePeer = bob
alice.sendMessage = func(msg lnwire.Message) error {
select {
case alice.remotePeer.msgChan <- msg:
case <-alice.shutdownChannel:
return errors.New("shutting down")
}
return nil
}
bob.remotePeer = alice
bob.sendMessage = func(msg lnwire.Message) error {
select {
case bob.remotePeer.msgChan <- msg:
case <-bob.shutdownChannel:
return errors.New("shutting down")
}
return nil
}
return alice, bob return alice, bob
} }
@ -473,7 +533,7 @@ func openChannel(t *testing.T, alice, bob *testNode, localFundingAmt,
err: errChan, err: errChan,
} }
alice.fundingMgr.initFundingWorkflow(bobAddr, initReq) alice.fundingMgr.initFundingWorkflow(bob, initReq)
// Alice should have sent the OpenChannel message to Bob. // Alice should have sent the OpenChannel message to Bob.
var aliceMsg lnwire.Message var aliceMsg lnwire.Message
@ -498,7 +558,7 @@ func openChannel(t *testing.T, alice, bob *testNode, localFundingAmt,
} }
// Let Bob handle the init message. // Let Bob handle the init message.
bob.fundingMgr.processFundingOpen(openChannelReq, aliceAddr) bob.fundingMgr.processFundingOpen(openChannelReq, alice)
// Bob should answer with an AcceptChannel message. // Bob should answer with an AcceptChannel message.
acceptChannelResponse := assertFundingMsgSent( acceptChannelResponse := assertFundingMsgSent(
@ -506,7 +566,7 @@ func openChannel(t *testing.T, alice, bob *testNode, localFundingAmt,
).(*lnwire.AcceptChannel) ).(*lnwire.AcceptChannel)
// Forward the response to Alice. // Forward the response to Alice.
alice.fundingMgr.processFundingAccept(acceptChannelResponse, bobAddr) alice.fundingMgr.processFundingAccept(acceptChannelResponse, bob)
// Alice responds with a FundingCreated message. // Alice responds with a FundingCreated message.
fundingCreated := assertFundingMsgSent( fundingCreated := assertFundingMsgSent(
@ -514,7 +574,7 @@ func openChannel(t *testing.T, alice, bob *testNode, localFundingAmt,
).(*lnwire.FundingCreated) ).(*lnwire.FundingCreated)
// Give the message to Bob. // Give the message to Bob.
bob.fundingMgr.processFundingCreated(fundingCreated, aliceAddr) bob.fundingMgr.processFundingCreated(fundingCreated, alice)
// Finally, Bob should send the FundingSigned message. // Finally, Bob should send the FundingSigned message.
fundingSigned := assertFundingMsgSent( fundingSigned := assertFundingMsgSent(
@ -522,7 +582,7 @@ func openChannel(t *testing.T, alice, bob *testNode, localFundingAmt,
).(*lnwire.FundingSigned) ).(*lnwire.FundingSigned)
// Forward the signature to Alice. // Forward the signature to Alice.
alice.fundingMgr.processFundingSigned(fundingSigned, bobAddr) alice.fundingMgr.processFundingSigned(fundingSigned, bob)
// After Alice processes the singleFundingSignComplete message, she will // After Alice processes the singleFundingSignComplete message, she will
// broadcast the funding transaction to the network. We expect to get a // broadcast the funding transaction to the network. We expect to get a
@ -861,14 +921,14 @@ func assertErrChannelNotFound(t *testing.T, node *testNode,
func assertHandleFundingLocked(t *testing.T, alice, bob *testNode) { func assertHandleFundingLocked(t *testing.T, alice, bob *testNode) {
// They should both send the new channel state to their peer. // They should both send the new channel state to their peer.
select { select {
case c := <-alice.peer.newChannels: case c := <-alice.newChannels:
close(c.done) close(c.done)
case <-time.After(time.Second * 15): case <-time.After(time.Second * 15):
t.Fatalf("alice did not send new channel to peer") t.Fatalf("alice did not send new channel to peer")
} }
select { select {
case c := <-bob.peer.newChannels: case c := <-bob.newChannels:
close(c.done) close(c.done)
case <-time.After(time.Second * 15): case <-time.After(time.Second * 15):
t.Fatalf("bob did not send new channel to peer") t.Fatalf("bob did not send new channel to peer")
@ -935,8 +995,8 @@ func TestFundingManagerNormalWorkflow(t *testing.T) {
waitForOpenUpdate(t, updateChan) waitForOpenUpdate(t, updateChan)
// Exchange the fundingLocked messages. // Exchange the fundingLocked messages.
alice.fundingMgr.processFundingLocked(fundingLockedBob, bobAddr) alice.fundingMgr.processFundingLocked(fundingLockedBob, bob)
bob.fundingMgr.processFundingLocked(fundingLockedAlice, aliceAddr) bob.fundingMgr.processFundingLocked(fundingLockedAlice, alice)
// Check that they notify the breach arbiter and peer about the new // Check that they notify the breach arbiter and peer about the new
// channel. // channel.
@ -970,12 +1030,15 @@ func TestFundingManagerRestartBehavior(t *testing.T) {
// sending it on restart. We mimic this behavior by letting the // sending it on restart. We mimic this behavior by letting the
// SendToPeer method return an error, as if the message was not // SendToPeer method return an error, as if the message was not
// successfully sent. We then recreate the fundingManager and make sure // successfully sent. We then recreate the fundingManager and make sure
// it continues the process as expected. // it continues the process as expected. We'll save the current
alice.fundingMgr.cfg.SendToPeer = func(target *btcec.PublicKey, // implementation of sendMessage to restore the original behavior later
msgs ...lnwire.Message) error { // on.
workingSendMessage := bob.sendMessage
bob.sendMessage = func(msg lnwire.Message) error {
return fmt.Errorf("intentional error in SendToPeer") return fmt.Errorf("intentional error in SendToPeer")
} }
alice.fundingMgr.cfg.NotifyWhenOnline = func(peer *btcec.PublicKey, con chan<- struct{}) { alice.fundingMgr.cfg.NotifyWhenOnline = func(peer *btcec.PublicKey,
con chan<- lnpeer.Peer) {
// Intentionally empty. // Intentionally empty.
} }
@ -1010,8 +1073,14 @@ func TestFundingManagerRestartBehavior(t *testing.T) {
// While Bob successfully sent fundingLocked. // While Bob successfully sent fundingLocked.
assertDatabaseState(t, bob, fundingOutPoint, fundingLockedSent) assertDatabaseState(t, bob, fundingOutPoint, fundingLockedSent)
// We now recreate Alice's fundingManager, and expect it to retry // We now recreate Alice's fundingManager with the correct sendMessage
// sending the fundingLocked message. // implementation, and expect it to retry sending the fundingLocked
// message. We'll explicitly shut down Alice's funding manager to
// prevent a race when overriding the sendMessage implementation.
if err := alice.fundingMgr.Stop(); err != nil {
t.Fatalf("unable to stop alice's funding manager: %v", err)
}
bob.sendMessage = workingSendMessage
recreateAliceFundingManager(t, alice) recreateAliceFundingManager(t, alice)
// Intentionally make the channel announcements fail // Intentionally make the channel announcements fail
@ -1036,8 +1105,8 @@ func TestFundingManagerRestartBehavior(t *testing.T) {
} }
// Exchange the fundingLocked messages. // Exchange the fundingLocked messages.
alice.fundingMgr.processFundingLocked(fundingLockedBob, bobAddr) alice.fundingMgr.processFundingLocked(fundingLockedBob, bob)
bob.fundingMgr.processFundingLocked(fundingLockedAlice, aliceAddr) bob.fundingMgr.processFundingLocked(fundingLockedAlice, alice)
// Check that they notify the breach arbiter and peer about the new // Check that they notify the breach arbiter and peer about the new
// channel. // channel.
@ -1090,13 +1159,17 @@ func TestFundingManagerOfflinePeer(t *testing.T) {
// fundingLocked message to the other peer. If the funding node fails // fundingLocked message to the other peer. If the funding node fails
// to send the fundingLocked message to the peer, it should wait for // to send the fundingLocked message to the peer, it should wait for
// the server to notify it that the peer is back online, and try again. // the server to notify it that the peer is back online, and try again.
alice.fundingMgr.cfg.SendToPeer = func(target *btcec.PublicKey, // We'll save the current implementation of sendMessage to restore the
msgs ...lnwire.Message) error { // original behavior later on.
workingSendMessage := bob.sendMessage
bob.sendMessage = func(msg lnwire.Message) error {
return fmt.Errorf("intentional error in SendToPeer") return fmt.Errorf("intentional error in SendToPeer")
} }
peerChan := make(chan *btcec.PublicKey, 1) peerChan := make(chan *btcec.PublicKey, 1)
conChan := make(chan chan<- struct{}, 1) conChan := make(chan chan<- lnpeer.Peer, 1)
alice.fundingMgr.cfg.NotifyWhenOnline = func(peer *btcec.PublicKey, connected chan<- struct{}) { alice.fundingMgr.cfg.NotifyWhenOnline = func(peer *btcec.PublicKey,
connected chan<- lnpeer.Peer) {
peerChan <- peer peerChan <- peer
conChan <- connected conChan <- connected
} }
@ -1132,9 +1205,10 @@ func TestFundingManagerOfflinePeer(t *testing.T) {
// While Bob successfully sent fundingLocked. // While Bob successfully sent fundingLocked.
assertDatabaseState(t, bob, fundingOutPoint, fundingLockedSent) assertDatabaseState(t, bob, fundingOutPoint, fundingLockedSent)
// Alice should be waiting for the server to notify when Bob comes back online. // Alice should be waiting for the server to notify when Bob comes back
// online.
var peer *btcec.PublicKey var peer *btcec.PublicKey
var con chan<- struct{} var con chan<- lnpeer.Peer
select { select {
case peer = <-peerChan: case peer = <-peerChan:
// Expected // Expected
@ -1154,17 +1228,10 @@ func TestFundingManagerOfflinePeer(t *testing.T) {
bobPubKey, peer) bobPubKey, peer)
} }
// Fix Alice's SendToPeer, and notify that Bob is back online. // Restore the correct sendMessage implementation, and notify that Bob
alice.fundingMgr.cfg.SendToPeer = func(target *btcec.PublicKey, // is back online.
msgs ...lnwire.Message) error { bob.sendMessage = workingSendMessage
select { con <- bob
case alice.msgChan <- msgs[0]:
case <-alice.shutdownChannel:
return fmt.Errorf("shutting down")
}
return nil
}
close(con)
// This should make Alice send the fundingLocked. // This should make Alice send the fundingLocked.
fundingLockedAlice := assertFundingMsgSent( fundingLockedAlice := assertFundingMsgSent(
@ -1186,8 +1253,8 @@ func TestFundingManagerOfflinePeer(t *testing.T) {
waitForOpenUpdate(t, updateChan) waitForOpenUpdate(t, updateChan)
// Exchange the fundingLocked messages. // Exchange the fundingLocked messages.
alice.fundingMgr.processFundingLocked(fundingLockedBob, bobAddr) alice.fundingMgr.processFundingLocked(fundingLockedBob, bob)
bob.fundingMgr.processFundingLocked(fundingLockedAlice, aliceAddr) bob.fundingMgr.processFundingLocked(fundingLockedAlice, alice)
// Check that they notify the breach arbiter and peer about the new // Check that they notify the breach arbiter and peer about the new
// channel. // channel.
@ -1228,7 +1295,7 @@ func TestFundingManagerPeerTimeoutAfterInitFunding(t *testing.T) {
err: errChan, err: errChan,
} }
alice.fundingMgr.initFundingWorkflow(bobAddr, initReq) alice.fundingMgr.initFundingWorkflow(bob, initReq)
// Alice should have sent the OpenChannel message to Bob. // Alice should have sent the OpenChannel message to Bob.
var aliceMsg lnwire.Message var aliceMsg lnwire.Message
@ -1288,7 +1355,7 @@ func TestFundingManagerPeerTimeoutAfterFundingOpen(t *testing.T) {
err: errChan, err: errChan,
} }
alice.fundingMgr.initFundingWorkflow(bobAddr, initReq) alice.fundingMgr.initFundingWorkflow(bob, initReq)
// Alice should have sent the OpenChannel message to Bob. // Alice should have sent the OpenChannel message to Bob.
var aliceMsg lnwire.Message var aliceMsg lnwire.Message
@ -1316,7 +1383,7 @@ func TestFundingManagerPeerTimeoutAfterFundingOpen(t *testing.T) {
assertNumPendingReservations(t, alice, bobPubKey, 1) assertNumPendingReservations(t, alice, bobPubKey, 1)
// Let Bob handle the init message. // Let Bob handle the init message.
bob.fundingMgr.processFundingOpen(openChannelReq, aliceAddr) bob.fundingMgr.processFundingOpen(openChannelReq, alice)
// Bob should answer with an AcceptChannel. // Bob should answer with an AcceptChannel.
assertFundingMsgSent(t, bob.msgChan, "AcceptChannel") assertFundingMsgSent(t, bob.msgChan, "AcceptChannel")
@ -1357,7 +1424,7 @@ func TestFundingManagerPeerTimeoutAfterFundingAccept(t *testing.T) {
err: errChan, err: errChan,
} }
alice.fundingMgr.initFundingWorkflow(bobAddr, initReq) alice.fundingMgr.initFundingWorkflow(bob, initReq)
// Alice should have sent the OpenChannel message to Bob. // Alice should have sent the OpenChannel message to Bob.
var aliceMsg lnwire.Message var aliceMsg lnwire.Message
@ -1385,7 +1452,7 @@ func TestFundingManagerPeerTimeoutAfterFundingAccept(t *testing.T) {
assertNumPendingReservations(t, alice, bobPubKey, 1) assertNumPendingReservations(t, alice, bobPubKey, 1)
// Let Bob handle the init message. // Let Bob handle the init message.
bob.fundingMgr.processFundingOpen(openChannelReq, aliceAddr) bob.fundingMgr.processFundingOpen(openChannelReq, alice)
// Bob should answer with an AcceptChannel. // Bob should answer with an AcceptChannel.
acceptChannelResponse := assertFundingMsgSent( acceptChannelResponse := assertFundingMsgSent(
@ -1396,7 +1463,7 @@ func TestFundingManagerPeerTimeoutAfterFundingAccept(t *testing.T) {
assertNumPendingReservations(t, bob, alicePubKey, 1) assertNumPendingReservations(t, bob, alicePubKey, 1)
// Forward the response to Alice. // Forward the response to Alice.
alice.fundingMgr.processFundingAccept(acceptChannelResponse, bobAddr) alice.fundingMgr.processFundingAccept(acceptChannelResponse, bob)
// Alice responds with a FundingCreated messages. // Alice responds with a FundingCreated messages.
assertFundingMsgSent(t, alice.msgChan, "FundingCreated") assertFundingMsgSent(t, alice.msgChan, "FundingCreated")
@ -1571,9 +1638,9 @@ func TestFundingManagerReceiveFundingLockedTwice(t *testing.T) {
waitForOpenUpdate(t, updateChan) waitForOpenUpdate(t, updateChan)
// Send the fundingLocked message twice to Alice, and once to Bob. // Send the fundingLocked message twice to Alice, and once to Bob.
alice.fundingMgr.processFundingLocked(fundingLockedBob, bobAddr) alice.fundingMgr.processFundingLocked(fundingLockedBob, bob)
alice.fundingMgr.processFundingLocked(fundingLockedBob, bobAddr) alice.fundingMgr.processFundingLocked(fundingLockedBob, bob)
bob.fundingMgr.processFundingLocked(fundingLockedAlice, aliceAddr) bob.fundingMgr.processFundingLocked(fundingLockedAlice, alice)
// Check that they notify the breach arbiter and peer about the new // Check that they notify the breach arbiter and peer about the new
// channel. // channel.
@ -1582,7 +1649,7 @@ func TestFundingManagerReceiveFundingLockedTwice(t *testing.T) {
// Alice should not send the channel state the second time, as the // Alice should not send the channel state the second time, as the
// second funding locked should just be ignored. // second funding locked should just be ignored.
select { select {
case <-alice.peer.newChannels: case <-alice.newChannels:
t.Fatalf("alice sent new channel to peer a second time") t.Fatalf("alice sent new channel to peer a second time")
case <-time.After(time.Millisecond * 300): case <-time.After(time.Millisecond * 300):
// Expected // Expected
@ -1590,9 +1657,9 @@ func TestFundingManagerReceiveFundingLockedTwice(t *testing.T) {
// Another fundingLocked should also be ignored, since Alice should // Another fundingLocked should also be ignored, since Alice should
// have updated her database at this point. // have updated her database at this point.
alice.fundingMgr.processFundingLocked(fundingLockedBob, bobAddr) alice.fundingMgr.processFundingLocked(fundingLockedBob, bob)
select { select {
case <-alice.peer.newChannels: case <-alice.newChannels:
t.Fatalf("alice sent new channel to peer a second time") t.Fatalf("alice sent new channel to peer a second time")
case <-time.After(time.Millisecond * 300): case <-time.After(time.Millisecond * 300):
// Expected // Expected
@ -1665,8 +1732,8 @@ func TestFundingManagerRestartAfterChanAnn(t *testing.T) {
recreateAliceFundingManager(t, alice) recreateAliceFundingManager(t, alice)
// Exchange the fundingLocked messages. // Exchange the fundingLocked messages.
alice.fundingMgr.processFundingLocked(fundingLockedBob, bobAddr) alice.fundingMgr.processFundingLocked(fundingLockedBob, bob)
bob.fundingMgr.processFundingLocked(fundingLockedAlice, aliceAddr) bob.fundingMgr.processFundingLocked(fundingLockedAlice, alice)
// Check that they notify the breach arbiter and peer about the new // Check that they notify the breach arbiter and peer about the new
// channel. // channel.
@ -1723,10 +1790,10 @@ func TestFundingManagerRestartAfterReceivingFundingLocked(t *testing.T) {
assertFundingLockedSent(t, alice, bob, fundingOutPoint) assertFundingLockedSent(t, alice, bob, fundingOutPoint)
// Let Alice immediately get the fundingLocked message. // Let Alice immediately get the fundingLocked message.
alice.fundingMgr.processFundingLocked(fundingLockedBob, bobAddr) alice.fundingMgr.processFundingLocked(fundingLockedBob, bob)
// Also let Bob get the fundingLocked message. // Also let Bob get the fundingLocked message.
bob.fundingMgr.processFundingLocked(fundingLockedAlice, aliceAddr) bob.fundingMgr.processFundingLocked(fundingLockedAlice, alice)
// Check that they notify the breach arbiter and peer about the new // Check that they notify the breach arbiter and peer about the new
// channel. // channel.
@ -1801,8 +1868,8 @@ func TestFundingManagerPrivateChannel(t *testing.T) {
waitForOpenUpdate(t, updateChan) waitForOpenUpdate(t, updateChan)
// Exchange the fundingLocked messages. // Exchange the fundingLocked messages.
alice.fundingMgr.processFundingLocked(fundingLockedBob, bobAddr) alice.fundingMgr.processFundingLocked(fundingLockedBob, bob)
bob.fundingMgr.processFundingLocked(fundingLockedAlice, aliceAddr) bob.fundingMgr.processFundingLocked(fundingLockedAlice, alice)
// Check that they notify the breach arbiter and peer about the new // Check that they notify the breach arbiter and peer about the new
// channel. // channel.
@ -1886,8 +1953,8 @@ func TestFundingManagerPrivateRestart(t *testing.T) {
waitForOpenUpdate(t, updateChan) waitForOpenUpdate(t, updateChan)
// Exchange the fundingLocked messages. // Exchange the fundingLocked messages.
alice.fundingMgr.processFundingLocked(fundingLockedBob, bobAddr) alice.fundingMgr.processFundingLocked(fundingLockedBob, bob)
bob.fundingMgr.processFundingLocked(fundingLockedAlice, aliceAddr) bob.fundingMgr.processFundingLocked(fundingLockedAlice, alice)
// Check that they notify the breach arbiter and peer about the new // Check that they notify the breach arbiter and peer about the new
// channel. // channel.
@ -1954,7 +2021,7 @@ func TestFundingManagerCustomChannelParameters(t *testing.T) {
err: errChan, err: errChan,
} }
alice.fundingMgr.initFundingWorkflow(bobAddr, initReq) alice.fundingMgr.initFundingWorkflow(bob, initReq)
// Alice should have sent the OpenChannel message to Bob. // Alice should have sent the OpenChannel message to Bob.
var aliceMsg lnwire.Message var aliceMsg lnwire.Message
@ -1993,7 +2060,7 @@ func TestFundingManagerCustomChannelParameters(t *testing.T) {
chanID := openChannelReq.PendingChannelID chanID := openChannelReq.PendingChannelID
// Let Bob handle the init message. // Let Bob handle the init message.
bob.fundingMgr.processFundingOpen(openChannelReq, aliceAddr) bob.fundingMgr.processFundingOpen(openChannelReq, alice)
// Bob should answer with an AcceptChannel message. // Bob should answer with an AcceptChannel message.
acceptChannelResponse := assertFundingMsgSent( acceptChannelResponse := assertFundingMsgSent(
@ -2013,7 +2080,7 @@ func TestFundingManagerCustomChannelParameters(t *testing.T) {
} }
// Forward the response to Alice. // Forward the response to Alice.
alice.fundingMgr.processFundingAccept(acceptChannelResponse, bobAddr) alice.fundingMgr.processFundingAccept(acceptChannelResponse, bob)
// Alice responds with a FundingCreated message. // Alice responds with a FundingCreated message.
fundingCreated := assertFundingMsgSent( fundingCreated := assertFundingMsgSent(
@ -2021,7 +2088,7 @@ func TestFundingManagerCustomChannelParameters(t *testing.T) {
).(*lnwire.FundingCreated) ).(*lnwire.FundingCreated)
// Give the message to Bob. // Give the message to Bob.
bob.fundingMgr.processFundingCreated(fundingCreated, aliceAddr) bob.fundingMgr.processFundingCreated(fundingCreated, alice)
// Finally, Bob should send the FundingSigned message. // Finally, Bob should send the FundingSigned message.
fundingSigned := assertFundingMsgSent( fundingSigned := assertFundingMsgSent(
@ -2029,7 +2096,7 @@ func TestFundingManagerCustomChannelParameters(t *testing.T) {
).(*lnwire.FundingSigned) ).(*lnwire.FundingSigned)
// Forward the signature to Alice. // Forward the signature to Alice.
alice.fundingMgr.processFundingSigned(fundingSigned, bobAddr) alice.fundingMgr.processFundingSigned(fundingSigned, bob)
// After Alice processes the singleFundingSignComplete message, she will // After Alice processes the singleFundingSignComplete message, she will
// broadcast the funding transaction to the network. We expect to get a // broadcast the funding transaction to the network. We expect to get a

@ -7,6 +7,7 @@ import (
"fmt" "fmt"
"io" "io"
"math" "math"
"net"
"reflect" "reflect"
"runtime" "runtime"
"strings" "strings"
@ -1411,6 +1412,9 @@ func (m *mockPeer) SendMessage(sync bool, msgs ...lnwire.Message) error {
} }
return nil return nil
} }
func (m *mockPeer) AddNewChannel(_ *lnwallet.LightningChannel, _ <-chan struct{}) error {
return nil
}
func (m *mockPeer) WipeChannel(*wire.OutPoint) error { func (m *mockPeer) WipeChannel(*wire.OutPoint) error {
return nil return nil
} }
@ -1420,8 +1424,9 @@ func (m *mockPeer) PubKey() [33]byte {
func (m *mockPeer) IdentityKey() *btcec.PublicKey { func (m *mockPeer) IdentityKey() *btcec.PublicKey {
return nil return nil
} }
func (m *mockPeer) Address() net.Addr {
var _ lnpeer.Peer = (*mockPeer)(nil) return nil
}
func newSingleLinkTestHarness(chanAmt, chanReserve btcutil.Amount) ( func newSingleLinkTestHarness(chanAmt, chanReserve btcutil.Amount) (
ChannelLink, *lnwallet.LightningChannel, chan time.Time, func() error, ChannelLink, *lnwallet.LightningChannel, chan time.Time, func() error,

@ -7,6 +7,7 @@ import (
"fmt" "fmt"
"io" "io"
"io/ioutil" "io/ioutil"
"net"
"sync" "sync"
"sync/atomic" "sync/atomic"
"testing" "testing"
@ -517,6 +518,16 @@ func (s *mockServer) IdentityKey() *btcec.PublicKey {
return pubkey return pubkey
} }
func (s *mockServer) Address() net.Addr {
return nil
}
func (s *mockServer) AddNewChannel(channel *lnwallet.LightningChannel,
cancel <-chan struct{}) error {
return nil
}
func (s *mockServer) WipeChannel(*wire.OutPoint) error { func (s *mockServer) WipeChannel(*wire.OutPoint) error {
return nil return nil
} }

6
lnd.go

@ -360,9 +360,7 @@ func lndMain() error {
idPrivKey.PubKey()) idPrivKey.PubKey())
return <-errChan return <-errChan
}, },
SendToPeer: server.SendToPeer,
NotifyWhenOnline: server.NotifyWhenOnline, NotifyWhenOnline: server.NotifyWhenOnline,
FindPeer: server.FindPeer,
TempChanIDSeed: chanIDSeed, TempChanIDSeed: chanIDSeed,
FindChannel: func(chanID lnwire.ChannelID) (*lnwallet.LightningChannel, error) { FindChannel: func(chanID lnwire.ChannelID) (*lnwallet.LightningChannel, error) {
dbChannels, err := chanDB.FetchAllChannels() dbChannels, err := chanDB.FetchAllChannels()
@ -450,12 +448,12 @@ func lndMain() error {
return delay return delay
}, },
WatchNewChannel: func(channel *channeldb.OpenChannel, WatchNewChannel: func(channel *channeldb.OpenChannel,
addr *lnwire.NetAddress) error { peerKey *btcec.PublicKey) error {
// First, we'll mark this new peer as a persistent peer // First, we'll mark this new peer as a persistent peer
// for re-connection purposes. // for re-connection purposes.
server.mu.Lock() server.mu.Lock()
pubStr := string(addr.IdentityKey.SerializeCompressed()) pubStr := string(peerKey.SerializeCompressed())
server.persistentPeers[pubStr] = struct{}{} server.persistentPeers[pubStr] = struct{}{}
server.mu.Unlock() server.mu.Unlock()

@ -1,8 +1,11 @@
package lnpeer package lnpeer
import ( import (
"net"
"github.com/btcsuite/btcd/btcec" "github.com/btcsuite/btcd/btcec"
"github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcd/wire"
"github.com/lightningnetwork/lnd/lnwallet"
"github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/lnwire"
) )
@ -14,6 +17,10 @@ type Peer interface {
// has been sent to the remote peer. // has been sent to the remote peer.
SendMessage(sync bool, msg ...lnwire.Message) error SendMessage(sync bool, msg ...lnwire.Message) error
// AddNewChannel adds a new channel to the peer. The channel should fail
// to be added if the cancel channel is closed.
AddNewChannel(channel *lnwallet.LightningChannel, cancel <-chan struct{}) error
// WipeChannel removes the channel uniquely identified by its channel // WipeChannel removes the channel uniquely identified by its channel
// point from all indexes associated with the peer. // point from all indexes associated with the peer.
WipeChannel(*wire.OutPoint) error WipeChannel(*wire.OutPoint) error
@ -23,4 +30,7 @@ type Peer interface {
// IdentityKey returns the public key of the remote peer. // IdentityKey returns the public key of the remote peer.
IdentityKey() *btcec.PublicKey IdentityKey() *btcec.PublicKey
// Address returns the network address of the remote peer.
Address() net.Addr
} }

56
peer.go

@ -21,6 +21,7 @@ import (
"github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/channeldb"
"github.com/lightningnetwork/lnd/contractcourt" "github.com/lightningnetwork/lnd/contractcourt"
"github.com/lightningnetwork/lnd/htlcswitch" "github.com/lightningnetwork/lnd/htlcswitch"
"github.com/lightningnetwork/lnd/lnpeer"
"github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lnwallet" "github.com/lightningnetwork/lnd/lnwallet"
"github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/lnwire"
@ -185,6 +186,9 @@ type peer struct {
wg sync.WaitGroup wg sync.WaitGroup
} }
// A compile-time check to ensure that peer satisfies the lnpeer.Peer interface.
var _ lnpeer.Peer = (*peer)(nil)
// newPeer creates a new peer from an establish connection object, and a // newPeer creates a new peer from an establish connection object, and a
// pointer to the main server. // pointer to the main server.
func newPeer(conn net.Conn, connReq *connmgr.ConnReq, server *server, func newPeer(conn net.Conn, connReq *connmgr.ConnReq, server *server,
@ -907,15 +911,15 @@ out:
p.queueMsg(lnwire.NewPong(pongBytes), nil) p.queueMsg(lnwire.NewPong(pongBytes), nil)
case *lnwire.OpenChannel: case *lnwire.OpenChannel:
p.server.fundingMgr.processFundingOpen(msg, p.addr) p.server.fundingMgr.processFundingOpen(msg, p)
case *lnwire.AcceptChannel: case *lnwire.AcceptChannel:
p.server.fundingMgr.processFundingAccept(msg, p.addr) p.server.fundingMgr.processFundingAccept(msg, p)
case *lnwire.FundingCreated: case *lnwire.FundingCreated:
p.server.fundingMgr.processFundingCreated(msg, p.addr) p.server.fundingMgr.processFundingCreated(msg, p)
case *lnwire.FundingSigned: case *lnwire.FundingSigned:
p.server.fundingMgr.processFundingSigned(msg, p.addr) p.server.fundingMgr.processFundingSigned(msg, p)
case *lnwire.FundingLocked: case *lnwire.FundingLocked:
p.server.fundingMgr.processFundingLocked(msg, p.addr) p.server.fundingMgr.processFundingLocked(msg, p)
case *lnwire.Shutdown: case *lnwire.Shutdown:
select { select {
@ -931,8 +935,9 @@ out:
} }
case *lnwire.Error: case *lnwire.Error:
switch { key := p.addr.IdentityKey
switch {
// In the case of an all-zero channel ID we want to // In the case of an all-zero channel ID we want to
// forward the error to all channels with this peer. // forward the error to all channels with this peer.
case msg.ChanID == lnwire.ConnectionWideID: case msg.ChanID == lnwire.ConnectionWideID:
@ -948,8 +953,8 @@ out:
// If the channel ID for the error message corresponds // If the channel ID for the error message corresponds
// to a pending channel, then the funding manager will // to a pending channel, then the funding manager will
// handle the error. // handle the error.
case p.server.fundingMgr.IsPendingChannel(msg.ChanID, p.addr): case p.server.fundingMgr.IsPendingChannel(msg.ChanID, key):
p.server.fundingMgr.processFundingError(msg, p.addr) p.server.fundingMgr.processFundingError(msg, key)
// If not we hand the error to the channel link for // If not we hand the error to the channel link for
// this channel. // this channel.
@ -1999,6 +2004,41 @@ func (p *peer) IdentityKey() *btcec.PublicKey {
return p.addr.IdentityKey return p.addr.IdentityKey
} }
// Address returns the network address of the remote peer.
func (p *peer) Address() net.Addr {
return p.addr.Address
}
// AddNewChannel adds a new channel to the peer. The channel should fail to be
// added if the cancel channel is closed.
func (p *peer) AddNewChannel(channel *lnwallet.LightningChannel,
cancel <-chan struct{}) error {
newChanDone := make(chan struct{})
newChanMsg := &newChannelMsg{
channel: channel,
done: newChanDone,
}
select {
case p.newChannels <- newChanMsg:
case <-cancel:
return errors.New("canceled adding new channel")
case <-p.quit:
return ErrPeerExiting
}
// We pause here to wait for the peer to recognize the new channel
// before we close the channel barrier corresponding to the channel.
select {
case <-newChanDone:
case <-p.quit:
return ErrPeerExiting
}
return nil
}
// TODO(roasbeef): make all start/stop mutexes a CAS // TODO(roasbeef): make all start/stop mutexes a CAS
// fetchLastChanUpdate returns a function which is able to retrieve the last // fetchLastChanUpdate returns a function which is able to retrieve the last

@ -110,7 +110,7 @@ type server struct {
inboundPeers map[string]*peer inboundPeers map[string]*peer
outboundPeers map[string]*peer outboundPeers map[string]*peer
peerConnectedListeners map[string][]chan<- struct{} peerConnectedListeners map[string][]chan<- lnpeer.Peer
persistentPeers map[string]struct{} persistentPeers map[string]struct{}
persistentPeersBackoff map[string]time.Duration persistentPeersBackoff map[string]time.Duration
@ -264,7 +264,7 @@ func newServer(listenAddrs []net.Addr, chanDB *channeldb.DB, cc *chainControl,
peersByPub: make(map[string]*peer), peersByPub: make(map[string]*peer),
inboundPeers: make(map[string]*peer), inboundPeers: make(map[string]*peer),
outboundPeers: make(map[string]*peer), outboundPeers: make(map[string]*peer),
peerConnectedListeners: make(map[string][]chan<- struct{}), peerConnectedListeners: make(map[string][]chan<- lnpeer.Peer),
globalFeatures: lnwire.NewFeatureVector(globalFeatures, globalFeatures: lnwire.NewFeatureVector(globalFeatures,
lnwire.GlobalFeatures), lnwire.GlobalFeatures),
@ -1568,31 +1568,38 @@ func (s *server) SendToPeer(target *btcec.PublicKey,
} }
// NotifyWhenOnline can be called by other subsystems to get notified when a // NotifyWhenOnline can be called by other subsystems to get notified when a
// particular peer comes online. // particular peer comes online. The peer itself is sent across the peerChan.
// //
// NOTE: This function is safe for concurrent access. // NOTE: This function is safe for concurrent access.
func (s *server) NotifyWhenOnline(peer *btcec.PublicKey, func (s *server) NotifyWhenOnline(peerKey *btcec.PublicKey,
connectedChan chan<- struct{}) { peerChan chan<- lnpeer.Peer) {
s.mu.Lock() s.mu.Lock()
defer s.mu.Unlock() defer s.mu.Unlock()
// Compute the target peer's identifier. // Compute the target peer's identifier.
pubStr := string(peer.SerializeCompressed()) pubStr := string(peerKey.SerializeCompressed())
// Check if peer is connected. // Check if peer is connected.
_, ok := s.peersByPub[pubStr] peer, ok := s.peersByPub[pubStr]
if ok { if ok {
// Connected, can return early. // Connected, can return early.
srvrLog.Debugf("Notifying that peer %x is online", srvrLog.Debugf("Notifying that peer %x is online",
peer.SerializeCompressed()) peerKey.SerializeCompressed())
close(connectedChan)
select {
case peerChan <- peer:
case <-s.quit:
}
return return
} }
// Not connected, store this listener such that it can be notified when // Not connected, store this listener such that it can be notified when
// the peer comes online. // the peer comes online.
s.peerConnectedListeners[pubStr] = append( s.peerConnectedListeners[pubStr] = append(
s.peerConnectedListeners[pubStr], connectedChan) s.peerConnectedListeners[pubStr], peerChan,
)
} }
// sendPeerMessages enqueues a list of messages into the outgoingQueue of the // sendPeerMessages enqueues a list of messages into the outgoingQueue of the
@ -2240,8 +2247,12 @@ func (s *server) addPeer(p *peer) {
} }
// Check if there are listeners waiting for this peer to come online. // Check if there are listeners waiting for this peer to come online.
for _, con := range s.peerConnectedListeners[pubStr] { for _, peerChan := range s.peerConnectedListeners[pubStr] {
close(con) select {
case peerChan <- p:
case <-s.quit:
return
}
} }
delete(s.peerConnectedListeners, pubStr) delete(s.peerConnectedListeners, pubStr)
} }
@ -2509,7 +2520,7 @@ func (s *server) OpenChannel(nodeKey *btcec.PublicKey,
// TODO(roasbeef): pass in chan that's closed if/when funding succeeds // TODO(roasbeef): pass in chan that's closed if/when funding succeeds
// so can track as persistent peer? // so can track as persistent peer?
go s.fundingMgr.initFundingWorkflow(targetPeer.addr, req) go s.fundingMgr.initFundingWorkflow(targetPeer, req)
return updateChan, errChan return updateChan, errChan
} }