diff --git a/fundingmanager.go b/fundingmanager.go index 9e29de16..a1fe9dbd 100644 --- a/fundingmanager.go +++ b/fundingmanager.go @@ -855,12 +855,15 @@ func (f *fundingManager) handleFundingOpen(fmsg *fundingOpenMsg) { // TODO(roasbeef): modify to only accept a _single_ pending channel per // block unless white listed + f.resMtx.RLock() if len(f.activeReservations[peerIDKey]) >= cfg.MaxPendingChannels { + f.resMtx.RUnlock() f.failFundingFlow( fmsg.peerAddress.IdentityKey, fmsg.msg.PendingChannelID, lnwire.ErrMaxPendingChannels) return } + f.resMtx.RUnlock() // We'll also reject any requests to create channels until we're fully // synced to the network as we won't be able to properly validate the @@ -2656,6 +2659,22 @@ func (f *fundingManager) getReservationCtx(peerKey *btcec.PublicKey, return resCtx, nil } +// IsPendingChannel returns a boolean indicating whether the channel identified +// by the pendingChanID and given peer is pending, meaning it is in the process +// of being funded. After the funding transaction has been confirmed, the +// channel will receive a new, permanent channel ID, and will no longer be +// considered pending. +func (f *fundingManager) IsPendingChannel(pendingChanID [32]byte, + peerAddress *lnwire.NetAddress) bool { + + peerIDKey := newSerializedKey(peerAddress.IdentityKey) + f.resMtx.RLock() + _, ok := f.activeReservations[peerIDKey][pendingChanID] + f.resMtx.RUnlock() + + return ok +} + func copyPubKey(pub *btcec.PublicKey) *btcec.PublicKey { return &btcec.PublicKey{ Curve: btcec.S256(), diff --git a/htlcswitch/link.go b/htlcswitch/link.go index 528dd353..e84d43b1 100644 --- a/htlcswitch/link.go +++ b/htlcswitch/link.go @@ -1319,7 +1319,21 @@ func (l *channelLink) handleUpstreamMsg(msg lnwire.Message) { l.fail("error receiving fee update: %v", err) return } + case *lnwire.Error: + // Error received from remote, MUST fail channel, but should + // only print the contents of the error message if all + // characters are printable ASCII. + errMsg := "non-ascii data" + if isASCII(msg.Data) { + errMsg = string(msg.Data) + } + l.fail("ChannelPoint(%v): recieved error from peer: %v", + l.channel.ChannelPoint(), errMsg) + default: + log.Warnf("ChannelPoint(%v): received unknown message of type %T", + l.channel.ChannelPoint(), msg) } + } // ackDownStreamPackets is responsible for removing htlcs from a link's @@ -2407,3 +2421,16 @@ func (l *channelLink) tracef(format string, a ...interface{}) { msg := fmt.Sprintf(format, a...) log.Tracef("ChannelLink(%s) %s", l.ShortChanID(), msg) } + +// isASCII is a helper method that checks whether all bytes in `data` would be +// printable ASCII characters if interpreted as a string. +func isASCII(data []byte) bool { + isASCII := true + for _, c := range data { + if c < 32 || c > 126 { + isASCII = false + break + } + } + return isASCII +} diff --git a/lnwire/channel_id.go b/lnwire/channel_id.go index 827efbaa..3033f401 100644 --- a/lnwire/channel_id.go +++ b/lnwire/channel_id.go @@ -24,6 +24,10 @@ const ( // ChannelID can be calculated by XOR'ing the big-endian serialization of the type ChannelID [32]byte +// ConnectionWideID is an all-zero ChannelID, which is used to represent a +// message intended for all channels to to specific peer. +var ConnectionWideID = ChannelID{} + // String returns the string representation of the ChannelID. This is just the // hex string encoding of the ChannelID itself. func (c ChannelID) String() string { diff --git a/peer.go b/peer.go index a0a5cc8b..cca99733 100644 --- a/peer.go +++ b/peer.go @@ -748,7 +748,27 @@ out: } case *lnwire.Error: - p.server.fundingMgr.processFundingError(msg, p.addr) + switch { + + // In the case of an all-zero channel ID we want to + // forward the error to all channels with this peer. + case msg.ChanID == lnwire.ConnectionWideID: + for _, chanStream := range chanMsgStreams { + chanStream.AddMsg(nextMsg) + } + + // If the channel ID for the error message corresponds + // to a pending channel, then the funding manager will + // handle the error. + case p.server.fundingMgr.IsPendingChannel(msg.ChanID, p.addr): + p.server.fundingMgr.processFundingError(msg, p.addr) + + // If not we hand the error to the channel link for + // this channel. + default: + isChanUpdate = true + targetChan = msg.ChanID + } // TODO(roasbeef): create ChanUpdater interface for the below case *lnwire.UpdateAddHTLC: