lnd: add async updates for [open|close]channel RPC's

This commit modifies the internal workflow for opening or closing a
channel in order to create a path in which RPC clients can receive
updates. Updates are now communicated via channels from the goroutines
spawned by the RPC server to process the request, and the sub-system
within the daemon that actually executes the request.

With this change clients can now receive updates that the request is
pending (final message has been sent to the target client), or that the
request has been completed. Confirmation related updates have not yet
been implemented as that will require some changes to the ChainNotifier
interface.
This commit is contained in:
Olaoluwa Osuntokun 2016-08-30 16:52:53 -07:00
parent 05ac8d3c47
commit 832fd248cd
No known key found for this signature in database
GPG Key ID: 9CC5B105D03521A2
6 changed files with 160 additions and 115 deletions

@ -4,6 +4,7 @@ import (
"sync" "sync"
"sync/atomic" "sync/atomic"
"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/roasbeef/btcd/btcec" "github.com/roasbeef/btcd/btcec"
@ -32,7 +33,7 @@ type reservationWithCtx struct {
reservation *lnwallet.ChannelReservation reservation *lnwallet.ChannelReservation
peer *peer peer *peer
resp chan *wire.OutPoint updates chan *lnrpc.OpenStatusUpdate
err chan error err chan error
} }
@ -43,9 +44,6 @@ type reservationWithCtx struct {
// the workflow. // the workflow.
type initFundingMsg struct { type initFundingMsg struct {
peer *peer peer *peer
err chan error
resp chan *wire.OutPoint
*openChanReq *openChanReq
} }
@ -397,6 +395,7 @@ func (f *fundingManager) handleFundingResponse(fmsg *fundingResponseMsg) {
_, addrs, _, err := txscript.ExtractPkScriptAddrs(msg.DeliveryPkScript, activeNetParams.Params) _, addrs, _, err := txscript.ExtractPkScriptAddrs(msg.DeliveryPkScript, activeNetParams.Params)
if err != nil { if err != nil {
fndgLog.Errorf("Unable to extract addresses from script: %v", err) fndgLog.Errorf("Unable to extract addresses from script: %v", err)
resCtx.err <- err
return return
} }
contribution := &lnwallet.ChannelContribution{ contribution := &lnwallet.ChannelContribution{
@ -411,6 +410,7 @@ func (f *fundingManager) handleFundingResponse(fmsg *fundingResponseMsg) {
fndgLog.Errorf("Unable to process contribution from %v: %v", fndgLog.Errorf("Unable to process contribution from %v: %v",
sourcePeer, err) sourcePeer, err)
fmsg.peer.Disconnect() fmsg.peer.Disconnect()
resCtx.err <- err
return return
} }
@ -422,6 +422,7 @@ func (f *fundingManager) handleFundingResponse(fmsg *fundingResponseMsg) {
commitSig, err := btcec.ParseSignature(sig, btcec.S256()) commitSig, err := btcec.ParseSignature(sig, btcec.S256())
if err != nil { if err != nil {
fndgLog.Errorf("Unable to parse signature: %v", err) fndgLog.Errorf("Unable to parse signature: %v", err)
resCtx.err <- err
return return
} }
@ -524,6 +525,7 @@ func (f *fundingManager) handleFundingSignComplete(fmsg *fundingSignCompleteMsg)
if err := resCtx.reservation.CompleteReservation(nil, commitSig); err != nil { if err := resCtx.reservation.CompleteReservation(nil, commitSig); err != nil {
fndgLog.Errorf("unable to complete reservation sign complete: %v", err) fndgLog.Errorf("unable to complete reservation sign complete: %v", err)
fmsg.peer.Disconnect() fmsg.peer.Disconnect()
resCtx.err <- err
return return
} }
@ -531,16 +533,27 @@ func (f *fundingManager) handleFundingSignComplete(fmsg *fundingSignCompleteMsg)
fndgLog.Infof("Finalizing pendingID(%v) over ChannelPoint(%v), "+ fndgLog.Infof("Finalizing pendingID(%v) over ChannelPoint(%v), "+
"waiting for channel open on-chain", chanID, fundingPoint) "waiting for channel open on-chain", chanID, fundingPoint)
// Send an update to the upstream client that the negotiation process
// is over.
// TODO(roasbeef): add abstraction over updates to accomdate
// long-polling, or SSE, etc.
resCtx.updates <- &lnrpc.OpenStatusUpdate{
Update: &lnrpc.OpenStatusUpdate_ChanPending{
ChanPending: &lnrpc.PendingUpdate{
Txid: fundingPoint.Hash[:],
},
},
}
// Spawn a goroutine which will send the newly open channel to the // Spawn a goroutine which will send the newly open channel to the
// source peer once the channel is open. A channel is considered "open" // source peer once the channel is open. A channel is considered "open"
// once it reaches a sufficient number of confirmations. // once it reaches a sufficient number of confirmations.
go func() {
// TODO(roasbeef): semaphore to limit active chan open goroutines // TODO(roasbeef): semaphore to limit active chan open goroutines
go func() {
select { select {
// TODO(roasbeef): need to persist pending broadcast channels, // TODO(roasbeef): need to persist pending broadcast channels,
// send chan open proof during scan of blocks mined while down. // send chan open proof during scan of blocks mined while down.
case openChan := <-resCtx.reservation.DispatchChan(): case openChan := <-resCtx.reservation.DispatchChan():
// This reservation is no longer pending as the funding // This reservation is no longer pending as the funding
// transaction has been fully confirmed. // transaction has been fully confirmed.
f.resMtx.Lock() f.resMtx.Lock()
@ -567,9 +580,33 @@ func (f *fundingManager) handleFundingSignComplete(fmsg *fundingSignCompleteMsg)
fundingOpen := lnwire.NewSingleFundingOpenProof(chanID, spvProof) fundingOpen := lnwire.NewSingleFundingOpenProof(chanID, spvProof)
fmsg.peer.queueMsg(fundingOpen, nil) fmsg.peer.queueMsg(fundingOpen, nil)
// Finally, respond to the original caller (if any). // Register the new link wtith the L3 routing manager
resCtx.err <- nil // so this new channel can be utilized during path
resCtx.resp <- resCtx.reservation.FundingOutpoint() // finding.
chanInfo := openChan.StateSnapshot()
capacity := float64(chanInfo.Capacity)
fmsg.peer.server.routingMgr.AddChannel(
graph.NewID(fmsg.peer.server.lightningID),
graph.NewID(chanInfo.RemoteID),
graph.NewEdgeID(fundingPoint.Hash.String()),
&rt.ChannelInfo{
Cpt: capacity,
},
)
// Finally give the caller a final update notifying
// them that the channel is now open.
// TODO(roasbeef): helper funcs for proto construction
resCtx.updates <- &lnrpc.OpenStatusUpdate{
Update: &lnrpc.OpenStatusUpdate_ChanOpen{
ChanOpen: &lnrpc.ChannelOpenUpdate{
ChannelPoint: &lnrpc.ChannelPoint{
FundingTxid: fundingPoint.Hash[:],
OutputIndex: fundingPoint.Index,
},
},
},
}
return return
case <-f.quit: case <-f.quit:
return return
@ -617,6 +654,7 @@ func (f *fundingManager) handleFundingOpen(fmsg *fundingOpenMsg) {
fndgLog.Infof("FundingOpen: ChannelPoint(%v) with peerID(%v) is now open", fndgLog.Infof("FundingOpen: ChannelPoint(%v) with peerID(%v) is now open",
resCtx.reservation.FundingOutpoint, fmsg.peer.id) resCtx.reservation.FundingOutpoint, fmsg.peer.id)
// Notify the L3 routing manager of the newly active channel link.
capacity := float64(resCtx.reservation.OurContribution().FundingAmount + capacity := float64(resCtx.reservation.OurContribution().FundingAmount +
resCtx.reservation.TheirContribution().FundingAmount) resCtx.reservation.TheirContribution().FundingAmount)
fmsg.peer.server.routingMgr.AddChannel( fmsg.peer.server.routingMgr.AddChannel(
@ -627,23 +665,19 @@ func (f *fundingManager) handleFundingOpen(fmsg *fundingOpenMsg) {
Cpt: capacity, Cpt: capacity,
}, },
) )
// Finally, notify the target peer of the newly open channel.
fmsg.peer.newChannels <- openChan fmsg.peer.newChannels <- openChan
} }
// 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(targetPeer *peer, req *openChanReq) (*wire.OutPoint, error) { func (f *fundingManager) initFundingWorkflow(targetPeer *peer, req *openChanReq) {
errChan := make(chan error, 1)
respChan := make(chan *wire.OutPoint, 1)
f.fundingRequests <- &initFundingMsg{ f.fundingRequests <- &initFundingMsg{
peer: targetPeer, peer: targetPeer,
resp: respChan,
err: errChan,
openChanReq: req, openChanReq: req,
} }
return <-respChan, <-errChan
} }
// handleInitFundingMsg creates a channel reservation within the daemon's // handleInitFundingMsg creates a channel reservation within the daemon's
@ -667,7 +701,6 @@ func (f *fundingManager) handleInitFundingMsg(msg *initFundingMsg) {
reservation, err := f.wallet.InitChannelReservation(capacity, localAmt, reservation, err := f.wallet.InitChannelReservation(capacity, localAmt,
nodeID, uint16(numConfs), 4) nodeID, uint16(numConfs), 4)
if err != nil { if err != nil {
msg.resp <- nil
msg.err <- err msg.err <- err
return return
} }
@ -689,8 +722,8 @@ func (f *fundingManager) handleInitFundingMsg(msg *initFundingMsg) {
f.activeReservations[msg.peer.id][chanID] = &reservationWithCtx{ f.activeReservations[msg.peer.id][chanID] = &reservationWithCtx{
reservation: reservation, reservation: reservation,
peer: msg.peer, peer: msg.peer,
updates: msg.updates,
err: msg.err, err: msg.err,
resp: msg.resp,
} }
f.resMtx.Unlock() f.resMtx.Unlock()
@ -700,7 +733,6 @@ func (f *fundingManager) handleInitFundingMsg(msg *initFundingMsg) {
deliveryScript, err := txscript.PayToAddrScript(contribution.DeliveryAddress) deliveryScript, err := txscript.PayToAddrScript(contribution.DeliveryAddress)
if err != nil { if err != nil {
fndgLog.Errorf("Unable to convert address to pkscript: %v", err) fndgLog.Errorf("Unable to convert address to pkscript: %v", err)
msg.resp <- nil
msg.err <- err msg.err <- err
return return
} }

@ -8,6 +8,7 @@ import (
"time" "time"
"github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/channeldb"
"github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/lnwire"
"github.com/roasbeef/btcd/wire" "github.com/roasbeef/btcd/wire"
"github.com/roasbeef/btcutil" "github.com/roasbeef/btcutil"
@ -325,7 +326,6 @@ func (h *htlcSwitch) handleUnregisterLink(req *unregisterLinkMsg) {
func (h *htlcSwitch) handleCloseLink(req *closeLinkReq) { func (h *htlcSwitch) handleCloseLink(req *closeLinkReq) {
targetLink, ok := h.chanIndex[*req.chanPoint] targetLink, ok := h.chanIndex[*req.chanPoint]
if !ok { if !ok {
req.resp <- nil
req.err <- fmt.Errorf("channel point %v not found", req.chanPoint) req.err <- fmt.Errorf("channel point %v not found", req.chanPoint)
return return
} }
@ -396,27 +396,20 @@ func (h *htlcSwitch) UnregisterLink(chanInterface [32]byte, chanPoint *wire.OutP
type closeLinkReq struct { type closeLinkReq struct {
chanPoint *wire.OutPoint chanPoint *wire.OutPoint
resp chan *closeLinkResp updates chan *lnrpc.CloseStatusUpdate
err chan error err chan error
} }
// closeChanResp is the response to a closeChanReq is simply houses a boolean
// value indicating if the channel coopertive channel closure was succesful or not.
type closeLinkResp struct {
txid *wire.ShaHash
success bool
}
// CloseLink closes an active link targetted by it's channel point. Closing the // CloseLink closes an active link targetted by it's channel point. Closing the
// link initiates a cooperative channel closure. // link initiates a cooperative channel closure.
// TODO(roabeef): bool flag for timeout/force // TODO(roabeef): bool flag for timeout/force
func (h *htlcSwitch) CloseLink(chanPoint *wire.OutPoint) (chan *closeLinkResp, chan error) { func (h *htlcSwitch) CloseLink(chanPoint *wire.OutPoint) (chan *lnrpc.CloseStatusUpdate, chan error) {
respChan := make(chan *closeLinkResp, 1) updateChan := make(chan *lnrpc.CloseStatusUpdate, 1)
errChan := make(chan error, 1) errChan := make(chan error, 1)
h.linkControl <- &closeLinkReq{chanPoint, respChan, errChan} h.linkControl <- &closeLinkReq{chanPoint, updateChan, errChan}
return respChan, errChan return updateChan, errChan
} }
// linkInfoUpdateMsg encapsulates a request for the htlc switch to update the // linkInfoUpdateMsg encapsulates a request for the htlc switch to update the

2
lnd.go

@ -143,7 +143,7 @@ func lndMain() error {
lnrpc.RegisterLightningServer(grpcServer, server.rpcServer) lnrpc.RegisterLightningServer(grpcServer, server.rpcServer)
// Finally, start the grpc server listening for HTTP/2 connections. // Finally, start the grpc server listening for HTTP/2 connections.
lis, err := net.Listen("tcp", fmt.Sprintf(":%d", loadedConfig.RPCPort)) lis, err := net.Listen("tcp", fmt.Sprintf("localhost:%d", loadedConfig.RPCPort))
if err != nil { if err != nil {
fmt.Printf("failed to listen: %v", err) fmt.Printf("failed to listen: %v", err)
return err return err

41
peer.go

@ -12,6 +12,7 @@ import (
"github.com/davecgh/go-spew/spew" "github.com/davecgh/go-spew/spew"
"github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/channeldb"
"github.com/lightningnetwork/lnd/lndc" "github.com/lightningnetwork/lnd/lndc"
"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/roasbeef/btcd/btcec" "github.com/roasbeef/btcd/btcec"
@ -639,7 +640,6 @@ func (p *peer) handleLocalClose(req *closeLinkReq) {
// when the remote node broadcasts the fully signed closing transaction. // when the remote node broadcasts the fully signed closing transaction.
sig, txid, err := channel.InitCooperativeClose() sig, txid, err := channel.InitCooperativeClose()
if err != nil { if err != nil {
req.resp <- nil
req.err <- err req.err <- err
return return
} }
@ -653,22 +653,33 @@ func (p *peer) handleLocalClose(req *closeLinkReq) {
// TODO(roasbeef): remove encoding redundancy // TODO(roasbeef): remove encoding redundancy
closeSig, err := btcec.ParseSignature(sig, btcec.S256()) closeSig, err := btcec.ParseSignature(sig, btcec.S256())
if err != nil { if err != nil {
req.resp <- nil
req.err <- err req.err <- err
return return
} }
closeReq := lnwire.NewCloseRequest(chanPoint, closeSig) closeReq := lnwire.NewCloseRequest(chanPoint, closeSig)
p.queueMsg(closeReq, nil) p.queueMsg(closeReq, nil)
// Update the caller w.r.t the current pending state of this request.
req.updates <- &lnrpc.CloseStatusUpdate{
Update: &lnrpc.CloseStatusUpdate_ClosePending{
ClosePending: &lnrpc.PendingUpdate{
Txid: txid[:],
},
},
}
// Finally, launch a goroutine which will request to be notified by the // Finally, launch a goroutine which will request to be notified by the
// ChainNotifier once the closure transaction obtains a single // ChainNotifier once the closure transaction obtains a single
// confirmation. // confirmation.
go func() { go func() {
// TODO(roasbeef): add param for num needed confs // TODO(roasbeef): add param for num needed confs
notifier := p.server.lnwallet.ChainNotifier notifier := p.server.lnwallet.ChainNotifier
confNtfn, _ := notifier.RegisterConfirmationsNtfn(txid, 1) confNtfn, err := notifier.RegisterConfirmationsNtfn(txid, 1)
if err != nil {
req.err <- err
return
}
var success bool
select { select {
case height, ok := <-confNtfn.Confirmed: case height, ok := <-confNtfn.Confirmed:
// In the case that the ChainNotifier is shutting // In the case that the ChainNotifier is shutting
@ -683,17 +694,24 @@ func (p *peer) handleLocalClose(req *closeLinkReq) {
// active indexes, and the database state. // active indexes, and the database state.
peerLog.Infof("ChannelPoint(%v) is now "+ peerLog.Infof("ChannelPoint(%v) is now "+
"closed at height %v", key, height) "closed at height %v", key, height)
wipeChannel(p, channel) if err := wipeChannel(p, channel); err != nil {
req.err <- err
success = true return
}
case <-p.quit: case <-p.quit:
return return
} }
// Respond to the local sub-system which requested the channel // Respond to the local sub-system which requested the channel
// closure. // closure.
req.resp <- &closeLinkResp{txid, success} req.updates <- &lnrpc.CloseStatusUpdate{
req.err <- nil Update: &lnrpc.CloseStatusUpdate_ChanClose{
ChanClose: &lnrpc.ChannelCloseUpdate{
ClosingTxid: txid[:],
Success: true,
},
},
}
}() }()
} }
@ -741,7 +759,7 @@ func (p *peer) handleRemoteClose(req *lnwire.CloseRequest) {
// wipeChannel removes the passed channel from all indexes associated with the // wipeChannel removes the passed channel from all indexes associated with the
// peer, and deletes the channel from the database. // peer, and deletes the channel from the database.
func wipeChannel(p *peer, channel *lnwallet.LightningChannel) { func wipeChannel(p *peer, channel *lnwallet.LightningChannel) error {
chanID := channel.ChannelPoint() chanID := channel.ChannelPoint()
delete(p.activeChannels, *chanID) delete(p.activeChannels, *chanID)
@ -756,7 +774,10 @@ func wipeChannel(p *peer, channel *lnwallet.LightningChannel) {
if err := channel.DeleteState(); err != nil { if err := channel.DeleteState(); err != nil {
peerLog.Errorf("Unable to delete ChannelPoint(%v) "+ peerLog.Errorf("Unable to delete ChannelPoint(%v) "+
"from db %v", chanID, err) "from db %v", chanID, err)
return err
} }
return nil
} }
// pendingPayment represents a pending HTLC which has yet to be settled by the // pendingPayment represents a pending HTLC which has yet to be settled by the

@ -201,30 +201,43 @@ func (r *rpcServer) OpenChannel(in *lnrpc.OpenChannelRequest,
remoteFundingAmt := btcutil.Amount(in.RemoteFundingAmount) remoteFundingAmt := btcutil.Amount(in.RemoteFundingAmount)
target := in.TargetPeerId target := in.TargetPeerId
numConfs := in.NumConfs numConfs := in.NumConfs
respChan, errChan := r.server.OpenChannel(target, localFundingAmt, updateChan, errChan := r.server.OpenChannel(target, localFundingAmt,
remoteFundingAmt, numConfs) remoteFundingAmt, numConfs)
if err := <-errChan; err != nil {
var outpoint wire.OutPoint
out:
for {
select {
case err := <-errChan:
rpcsLog.Errorf("unable to open channel to peerid(%v): %v", rpcsLog.Errorf("unable to open channel to peerid(%v): %v",
target, err) target, err)
return err return err
case fundingUpdate := <-updateChan:
rpcsLog.Tracef("[openchannel] sending update: %v",
fundingUpdate)
if err := updateStream.Send(fundingUpdate); err != nil {
return err
} }
var outpoint *wire.OutPoint // If a final channel open update is being sent, then
select { // we can break out of our recv loop as we no longer
case resp := <-respChan: // need to process any further updates.
outpoint = resp.chanPoint switch update := fundingUpdate.Update.(type) {
openUpdate := &lnrpc.ChannelOpenUpdate{ case *lnrpc.OpenStatusUpdate_ChanOpen:
&lnrpc.ChannelPoint{ chanPoint := update.ChanOpen.ChannelPoint
FundingTxid: outpoint.Hash[:], h, _ := wire.NewShaHash(chanPoint.FundingTxid)
OutputIndex: outpoint.Index, outpoint = wire.OutPoint{
}, Hash: *h,
Index: chanPoint.OutputIndex,
} }
if err := updateStream.Send(openUpdate); err != nil {
return err break out
} }
case <-r.quit: case <-r.quit:
return nil return nil
} }
}
rpcsLog.Tracef("[openchannel] success peerid(%v), ChannelPoint(%v)", rpcsLog.Tracef("[openchannel] success peerid(%v), ChannelPoint(%v)",
in.TargetPeerId, outpoint) in.TargetPeerId, outpoint)
return nil return nil
@ -247,25 +260,34 @@ func (r *rpcServer) CloseChannel(in *lnrpc.CloseChannelRequest,
rpcsLog.Tracef("[closechannel] request for ChannelPoint(%v)", rpcsLog.Tracef("[closechannel] request for ChannelPoint(%v)",
targetChannelPoint) targetChannelPoint)
respChan, errChan := r.server.htlcSwitch.CloseLink(targetChannelPoint) updateChan, errChan := r.server.htlcSwitch.CloseLink(targetChannelPoint)
if err := <-errChan; err != nil {
rpcsLog.Errorf("Unable to close ChannelPoint(%v): %v", out:
targetChannelPoint, err) for {
select {
case err := <-errChan:
rpcsLog.Errorf("[closechannel] unable to close "+
"ChannelPoint(%v): %v", targetChannelPoint, err)
return err
case closingUpdate := <-updateChan:
if err := updateStream.Send(closingUpdate); err != nil {
return err return err
} }
select { // If a final channel closing updates is being sent,
case resp := <-respChan: // then we can break out of our dispatch loop as we no
closeUpdate := &lnrpc.ChannelCloseUpdate{ // longer need to process any further updates.
ClosingTxid: resp.txid[:], switch closeUpdate := closingUpdate.Update.(type) {
Success: resp.success, case *lnrpc.CloseStatusUpdate_ChanClose:
} h, _ := wire.NewShaHash(closeUpdate.ChanClose.ClosingTxid)
if err := updateStream.Send(closeUpdate); err != nil { rpcsLog.Errorf("[closechannel] close completed: "+
return err "txid(%v)", h)
break out
} }
case <-r.quit: case <-r.quit:
return nil return nil
} }
}
return nil return nil
} }
@ -350,6 +372,7 @@ func (r *rpcServer) ListPeers(ctx context.Context,
// by the wallet. This method can be modified by having the request specify // by the wallet. This method can be modified by having the request specify
// only witness outputs should be factored into the final output sum. // only witness outputs should be factored into the final output sum.
// TODO(roasbeef): split into total and confirmed/unconfirmed // TODO(roasbeef): split into total and confirmed/unconfirmed
// TODO(roasbeef): add async hooks into wallet balance changes
func (r *rpcServer) WalletBalance(ctx context.Context, func (r *rpcServer) WalletBalance(ctx context.Context,
in *lnrpc.WalletBalanceRequest) (*lnrpc.WalletBalanceResponse, error) { in *lnrpc.WalletBalanceRequest) (*lnrpc.WalletBalanceResponse, error) {

@ -10,14 +10,13 @@ import (
"github.com/btcsuite/fastsha256" "github.com/btcsuite/fastsha256"
"github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/channeldb"
"github.com/lightningnetwork/lnd/lndc" "github.com/lightningnetwork/lnd/lndc"
"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/roasbeef/btcd/btcec" "github.com/roasbeef/btcd/btcec"
"github.com/roasbeef/btcd/wire"
"github.com/roasbeef/btcutil" "github.com/roasbeef/btcutil"
"github.com/BitfuryLightning/tools/routing" "github.com/BitfuryLightning/tools/routing"
"github.com/BitfuryLightning/tools/rt"
"github.com/BitfuryLightning/tools/rt/graph" "github.com/BitfuryLightning/tools/rt/graph"
"github.com/roasbeef/btcwallet/waddrmgr" "github.com/roasbeef/btcwallet/waddrmgr"
) )
@ -229,16 +228,10 @@ type openChanReq struct {
numConfs uint32 numConfs uint32
resp chan *openChanResp updates chan *lnrpc.OpenStatusUpdate
err chan error err chan error
} }
// openChanResp is the response to an openChanReq, it contains the channel
// point, or outpoint of the broadcast funding transaction.
type openChanResp struct {
chanPoint *wire.OutPoint
}
// queryHandler handles any requests to modify the server's internal state of // queryHandler handles any requests to modify the server's internal state of
// all active peers, or query/mutate the server's global state. Additionally, // all active peers, or query/mutate the server's global state. Additionally,
// any queries directed at peers will be handled by this goroutine. // any queries directed at peers will be handled by this goroutine.
@ -389,7 +382,6 @@ func (s *server) handleOpenChanReq(req *openChanReq) {
} }
if targetPeer == nil { if targetPeer == nil {
req.resp <- nil
req.err <- fmt.Errorf("unable to find peer %v", target) req.err <- fmt.Errorf("unable to find peer %v", target)
return return
} }
@ -398,23 +390,8 @@ func (s *server) handleOpenChanReq(req *openChanReq) {
// manager. This allows the server to continue handling queries instead of // manager. This allows the server to continue handling queries instead of
// blocking on this request which is exporeted as a synchronous request to // blocking on this request which is exporeted as a synchronous request to
// the outside world. // the outside world.
go func() {
// TODO(roasbeef): server semaphore to restrict num goroutines // TODO(roasbeef): server semaphore to restrict num goroutines
fundingID, err := s.fundingMgr.initFundingWorkflow(targetPeer, req) go s.fundingMgr.initFundingWorkflow(targetPeer, req)
if err == nil {
capacity := float64(req.localFundingAmt + req.remoteFundingAmt)
s.routingMgr.AddChannel(
graph.NewID(s.lightningID),
graph.NewID([32]byte(targetPeer.lightningID)),
graph.NewEdgeID(fundingID.String()),
&rt.ChannelInfo{
Cpt: capacity,
},
)
}
req.resp <- &openChanResp{fundingID}
req.err <- err
}()
} }
// ConnectToPeer requests that the server connect to a Lightning Network peer // ConnectToPeer requests that the server connect to a Lightning Network peer
@ -432,10 +409,10 @@ func (s *server) ConnectToPeer(addr *lndc.LNAdr) (int32, error) {
// OpenChannel sends a request to the server to open a channel to the specified // OpenChannel sends a request to the server to open a channel to the specified
// peer identified by ID with the passed channel funding paramters. // peer identified by ID with the passed channel funding paramters.
func (s *server) OpenChannel(nodeID int32, localAmt, remoteAmt btcutil.Amount, func (s *server) OpenChannel(nodeID int32, localAmt, remoteAmt btcutil.Amount,
numConfs uint32) (chan *openChanResp, chan error) { numConfs uint32) (chan *lnrpc.OpenStatusUpdate, chan error) {
errChan := make(chan error, 1) errChan := make(chan error, 1)
respChan := make(chan *openChanResp, 1) updateChan := make(chan *lnrpc.OpenStatusUpdate, 1)
s.queries <- &openChanReq{ s.queries <- &openChanReq{
targetNodeID: nodeID, targetNodeID: nodeID,
@ -443,12 +420,11 @@ func (s *server) OpenChannel(nodeID int32, localAmt, remoteAmt btcutil.Amount,
remoteFundingAmt: remoteAmt, remoteFundingAmt: remoteAmt,
numConfs: numConfs, numConfs: numConfs,
resp: respChan, updates: updateChan,
err: errChan, err: errChan,
} }
// TODO(roasbeef): hook in "progress" channel
return respChan, errChan return updateChan, errChan
} }
// Peers returns a slice of all active peers. // Peers returns a slice of all active peers.