From 4e416da4cdc5280aa7d3117e7de96a4e570a70e0 Mon Sep 17 00:00:00 2001 From: Olaoluwa Osuntokun Date: Thu, 25 Aug 2016 16:30:22 -0700 Subject: [PATCH] htlcswitch: properly update channel bandwidth after payment recv MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit fixes an omission within the htlcSwitch. With this commit, a channels bandwidth is now properly updated once an incoming HTLC is settled. This also fixes a bug where if a node received a payment, it wouldn’t be able to then utilize the newly available bandwidth to send further payments. --- htlcswitch.go | 28 ++++++++++++++++++++++++++++ peer.go | 34 ++++++++++++++++++++++++---------- 2 files changed, 52 insertions(+), 10 deletions(-) diff --git a/htlcswitch.go b/htlcswitch.go index 44e4b0e7..05624790 100644 --- a/htlcswitch.go +++ b/htlcswitch.go @@ -240,6 +240,8 @@ out: h.handleRegisterLink(req) case *unregisterLinkMsg: h.handleUnregisterLink(req) + case *linkInfoUpdateMsg: + h.handleLinkUpdate(req) } case <-h.quit: break out @@ -333,6 +335,16 @@ func (h *htlcSwitch) handleCloseLink(req *closeLinkReq) { targetLink.peer.localCloseChanReqs <- req } +// handleLinkUpdate processes the link info update message by adjusting the +// channels available bandwidth by the delta specified within the message. +func (h *htlcSwitch) handleLinkUpdate(req *linkInfoUpdateMsg) { + link := h.chanIndex[*req.targetLink] + link.availableBandwidth += req.bandwidthDelta + + hswcLog.Tracef("adjusting bandwidth of link %v by %v", req.targetLink, + req.bandwidthDelta) +} + // registerLinkMsg is message which requests a new link to be registered. type registerLinkMsg struct { peer *peer @@ -406,3 +418,19 @@ func (h *htlcSwitch) CloseLink(chanPoint *wire.OutPoint) (chan *closeLinkResp, c return respChan, errChan } + +// linkInfoUpdateMsg encapsulates a request for the htlc switch to update the +// meta-data related to the target link. +type linkInfoUpdateMsg struct { + targetLink *wire.OutPoint + + bandwidthDelta btcutil.Amount +} + +// UpdateLink sends a message to the switch to update the available bandwidth +// within the link by the passed satoshi delta. This function may be used when +// re-anchoring to boost the capacity of a channel, or once a peer settles an +// HTLC invoice. +func (h *htlcSwitch) UpdateLink(chanPoint *wire.OutPoint, bandwidthDelta btcutil.Amount) { + h.linkControl <- &linkInfoUpdateMsg{chanPoint, bandwidthDelta} +} diff --git a/peer.go b/peer.go index 6bc4ef5f..2abaefd6 100644 --- a/peer.go +++ b/peer.go @@ -17,6 +17,7 @@ import ( "github.com/roasbeef/btcd/btcec" "github.com/roasbeef/btcd/txscript" "github.com/roasbeef/btcd/wire" + "github.com/roasbeef/btcutil" ) var ( @@ -776,8 +777,7 @@ type pendingPayment struct { type commitmentState struct { // htlcsToSettle is a list of preimages which allow us to settle one or // many of the pending HTLC's we've received from the upstream peer. - // TODO(roasbeef): should send sig to settle once preimage is known. - htlcsToSettle map[uint32][32]byte + htlcsToSettle map[uint32]invoice // TODO(roasbeef): use once trickle+batch logic is in pendingBatch []*pendingPayment @@ -839,7 +839,7 @@ func (p *peer) htlcManager(channel *lnwallet.LightningChannel, channel: channel, chanPoint: channel.ChannelPoint(), clearedHTCLs: make(map[uint32]*pendingPayment), - htlcsToSettle: make(map[uint32][32]byte), + htlcsToSettle: make(map[uint32]invoice), switchChan: htlcPlex, } @@ -964,8 +964,9 @@ func (p *peer) handleUpstreamMsg(state *commitmentState, msg lnwire.Message) { // TODO(roasbeef): check value // * onion layer strip should also be before invoice lookup // * also can immediately send the settle msg - pre := invoice.paymentPreimage - state.htlcsToSettle[index] = pre + invCopy := *invoice + invCopy.value = btcutil.Amount(htlcPkt.Amount) + state.htlcsToSettle[index] = invCopy } case *lnwire.HTLCSettleRequest: // TODO(roasbeef): this assumes no "multi-sig" @@ -1024,10 +1025,12 @@ func (p *peer) handleUpstreamMsg(state *commitmentState, msg lnwire.Message) { // We perform the HTLC forwarding to the switch in a distinct // goroutine in order not to block the post-processing of // HTLC's that are eligble for forwarding. + // TODO(roasbeef): no need to forward if have settled any of + // these. go func() { for _, htlc := range htlcsToForward { - // Send this fully activated HTLC to the htlc switch to - // continue the chained clear/settle. + // Send this fully activated HTLC to the htlc + // switch to continue the chained clear/settle. state.switchChan <- p.logEntryToHtlcPkt(htlc) } @@ -1037,6 +1040,7 @@ func (p *peer) handleUpstreamMsg(state *commitmentState, msg lnwire.Message) { // settling or timeing out previous outgoing payments, then we // can them from the pending set, and signal the requster (if // existing) that the payment has been fully fulfilled. + var bandwidthUpdate btcutil.Amount numSettled := 0 for _, htlc := range htlcsToForward { if p, ok := state.clearedHTCLs[htlc.ParentIndex]; ok { @@ -1052,7 +1056,7 @@ func (p *peer) handleUpstreamMsg(state *commitmentState, msg lnwire.Message) { // If we can't immediately settle this HTLC, then we // can halt processing here. - preimage, ok := state.htlcsToSettle[htlc.Index] + invoice, ok := state.htlcsToSettle[htlc.Index] if !ok { continue } @@ -1060,7 +1064,7 @@ func (p *peer) handleUpstreamMsg(state *commitmentState, msg lnwire.Message) { // Otherwise, we settle this HTLC within our local // state update log, then send the update entry to the // remote party. - logIndex, err := state.channel.SettleHTLC(preimage) + logIndex, err := state.channel.SettleHTLC(invoice.paymentPreimage) if err != nil { peerLog.Errorf("unable to settle htlc: %v", err) p.Disconnect() @@ -1070,11 +1074,13 @@ func (p *peer) handleUpstreamMsg(state *commitmentState, msg lnwire.Message) { settleMsg := &lnwire.HTLCSettleRequest{ ChannelPoint: state.chanPoint, HTLCKey: lnwire.HTLCKey(logIndex), - RedemptionProofs: [][32]byte{preimage}, + RedemptionProofs: [][32]byte{invoice.paymentPreimage}, } p.queueMsg(settleMsg, nil) delete(state.htlcsToSettle, htlc.Index) + bandwidthUpdate += invoice.value + numSettled++ } @@ -1082,6 +1088,14 @@ func (p *peer) handleUpstreamMsg(state *commitmentState, msg lnwire.Message) { return } + // Send an update to the htlc switch of our newly available + // payment bandwidth. + // TODO(roasbeef): ideally should wait for next state update. + if bandwidthUpdate != 0 { + p.server.htlcSwitch.UpdateLink(state.chanPoint, + bandwidthUpdate) + } + // With all the settle updates added to the local and remote // HTLC logs, initiate a state transition by updating the // remote commitment chain.