diff --git a/fundingmanager.go b/fundingmanager.go index 6251cfde..2055217c 100644 --- a/fundingmanager.go +++ b/fundingmanager.go @@ -14,6 +14,7 @@ import ( "github.com/roasbeef/btcutil" "fmt" + "github.com/BitfuryLightning/tools/rt" "github.com/BitfuryLightning/tools/rt/graph" "google.golang.org/grpc" @@ -309,7 +310,6 @@ func (f *fundingManager) processFundingRequest(msg *lnwire.SingleFundingRequest, // TODO(roasbeef): add error chan to all, let channelManager handle // error+propagate func (f *fundingManager) handleFundingRequest(fmsg *fundingRequestMsg) { - // Check number of pending channels to be smaller than maximum allowed // number and send ErrorGeneric to remote peer if condition is violated. if len(f.activeReservations[fmsg.peer.id]) >= cfg.MaxPendingChannels { @@ -319,7 +319,7 @@ func (f *fundingManager) handleFundingRequest(fmsg *fundingRequestMsg) { Index: 0, }, Problem: "Number of pending channels exceed maximum", - ErrorID: lnwire.ErrorMaxPendingChannels, + Code: lnwire.ErrorMaxPendingChannels, PendingChannelID: fmsg.msg.ChannelID, } fmsg.peer.queueMsg(errMsg, nil) @@ -713,7 +713,6 @@ func (f *fundingManager) initFundingWorkflow(targetPeer *peer, req *openChanReq) // wallet, then sends a funding request to the remote peer kicking off the // funding workflow. func (f *fundingManager) handleInitFundingMsg(msg *initFundingMsg) { - nodeID := msg.peer.lightningID localAmt := msg.localFundingAmt @@ -786,10 +785,11 @@ func (f *fundingManager) handleInitFundingMsg(msg *initFundingMsg) { msg.peer.queueMsg(fundingReq, nil) } -// processErrorGeneric sends a message to the fundingManager allowing it -// to process the occurred generic error. +// processErrorGeneric sends a message to the fundingManager allowing it to +// process the occurred generic error. func (f *fundingManager) processErrorGeneric(err *lnwire.ErrorGeneric, peer *peer) { + f.fundingMsgs <- &fundingErrorMsg{err, peer} } @@ -797,7 +797,8 @@ func (f *fundingManager) processErrorGeneric(err *lnwire.ErrorGeneric, // depends on the type of error we should do different clean up steps and // inform user about it. func (f *fundingManager) handleErrorGenericMsg(fmsg *fundingErrorMsg) { - if fmsg.err.ErrorID == lnwire.ErrorMaxPendingChannels { + switch fmsg.err.Code { + case lnwire.ErrorMaxPendingChannels: peerID := fmsg.peer.id chanID := fmsg.err.PendingChannelID @@ -805,8 +806,9 @@ func (f *fundingManager) handleErrorGenericMsg(fmsg *fundingErrorMsg) { resCtx, ok := f.activeReservations[peerID][chanID] f.resMtx.RUnlock() + // TODO(roasbeef): comment if !ok { - resCtx.err <- fmt.Errorf("ErrorGeneric error " + + resCtx.err <- fmt.Errorf("ErrorGeneric error "+ "was returned from remote peer for channel "+ "(id: %v), but it can't be found and thereby "+ "can't be canceled.", chanID) @@ -826,5 +828,7 @@ func (f *fundingManager) handleErrorGenericMsg(fmsg *fundingErrorMsg) { f.resMtx.Lock() delete(f.activeReservations[peerID], chanID) f.resMtx.Unlock() + default: + fndgLog.Warnf("unknown funding error %v", fmsg.err) } } diff --git a/lnwire/error_generic.go b/lnwire/error_generic.go index dea6f1d3..0c49dc82 100644 --- a/lnwire/error_generic.go +++ b/lnwire/error_generic.go @@ -7,10 +7,14 @@ import ( "github.com/roasbeef/btcd/wire" ) +// ErrorCode represents the short error code for each of the defined errors +// within the Lightning Network protocol spec. +type ErrorCode uint16 + const ( - // Is returned by remote peer when number of pending channels exceed max - // value. - ErrorMaxPendingChannels = 1 + // ErrorMaxPendingChannels is returned by remote peer when the number + // of active pending channels exceeds their maximum policy limit. + ErrorMaxPendingChannels ErrorCode = 1 ) // ErrorGeneric represents a generic error bound to an exact channel. The @@ -18,26 +22,25 @@ const ( // array of possible errors. Each ErrorGeneric message is directed at a particular // open channel referenced by ChannelPoint. type ErrorGeneric struct { - // ChannelPoint references the active channel in which the error occurred - // within. A ChannelPoint of zeroHash:0 denotes this error applies to - // the entire established connection. + // ChannelPoint references the active channel in which the error + // occurred within. A ChannelPoint of zeroHash:0 denotes this error + // applies to the entire established connection. ChannelPoint *wire.OutPoint - // ErrorID quickly defines the nature of the error according to error - // type. - ErrorID uint16 - - // Problem is a human-readable string further elaborating upon the - // nature of the exact error. The maximum allowed length of this - // message is 8192 bytes. - Problem string - // PendingChannelID allows peers communicate errors in the context of a // particular pending channel. With this field, once a peer reads an // ErrorGeneric message with the PendingChannelID field set, then they // can forward the error to the fundingManager who can handle it // properly. PendingChannelID uint64 + + // Code is the short error ID which describes the nature of the error. + Code ErrorCode + + // Problem is a human-readable string further elaborating upon the + // nature of the exact error. The maximum allowed length of this + // message is 8192 bytes. + Problem string } // NewErrorGeneric creates a new ErrorGeneric message. @@ -58,7 +61,7 @@ func (c *ErrorGeneric) Decode(r io.Reader, pver uint32) error { // Problem err := readElements(r, &c.ChannelPoint, - &c.ErrorID, + &c.Code, &c.Problem, &c.PendingChannelID, ) @@ -76,7 +79,7 @@ func (c *ErrorGeneric) Decode(r io.Reader, pver uint32) error { func (c *ErrorGeneric) Encode(w io.Writer, pver uint32) error { err := writeElements(w, c.ChannelPoint, - c.ErrorID, + c.Code, c.Problem, c.PendingChannelID, ) @@ -123,7 +126,7 @@ func (c *ErrorGeneric) Validate() error { func (c *ErrorGeneric) String() string { return fmt.Sprintf("\n--- Begin ErrorGeneric ---\n") + fmt.Sprintf("ChannelPoint:\t%d\n", c.ChannelPoint) + - fmt.Sprintf("ErrorID:\t%d\n", c.ErrorID) + + fmt.Sprintf("Code:\t%d\n", c.Code) + fmt.Sprintf("Problem:\t%s\n", c.Problem) + fmt.Sprintf("PendingChannelID:\t%s\n", c.PendingChannelID) + fmt.Sprintf("--- End ErrorGeneric ---\n") diff --git a/lnwire/error_generic_test.go b/lnwire/error_generic_test.go index 37519785..71cfa574 100644 --- a/lnwire/error_generic_test.go +++ b/lnwire/error_generic_test.go @@ -8,10 +8,10 @@ import ( func TestErrorGenericEncodeDecode(t *testing.T) { eg := &ErrorGeneric{ - ChannelPoint: outpoint1, - ErrorID: 99, - Problem: "Hello world!", + ChannelPoint: outpoint1, PendingChannelID: 1, + Code: 99, + Problem: "Hello world!", } // Next encode the EG message into an empty bytes buffer. diff --git a/lnwire/lnwire.go b/lnwire/lnwire.go index 8e6d1f06..230897cb 100644 --- a/lnwire/lnwire.go +++ b/lnwire/lnwire.go @@ -84,6 +84,12 @@ func writeElement(w io.Writer, element interface{}) error { if _, err := w.Write(b[:]); err != nil { return err } + case ErrorCode: + var b [2]byte + binary.BigEndian.PutUint16(b[:], uint16(e)) + if _, err := w.Write(b[:]); err != nil { + return err + } case CreditsAmount: if err := binary.Write(w, binary.BigEndian, int64(e)); err != nil { return err @@ -308,6 +314,12 @@ func readElement(r io.Reader, element interface{}) error { return err } *e = binary.BigEndian.Uint16(b[:]) + case *ErrorCode: + var b [2]byte + if _, err := io.ReadFull(r, b[:]); err != nil { + return err + } + *e = ErrorCode(binary.BigEndian.Uint16(b[:])) case *CreditsAmount: var b [8]byte if _, err := io.ReadFull(r, b[:]); err != nil { diff --git a/peer.go b/peer.go index f970c8d9..d0c02efb 100644 --- a/peer.go +++ b/peer.go @@ -375,14 +375,13 @@ out: // * .(CommitmentUpdater) case *lnwire.ErrorGeneric: - switch msg.ErrorID { + switch msg.Code { case lnwire.ErrorMaxPendingChannels: p.server.fundingMgr.processErrorGeneric(msg, p) default: - peerLog.Warn("ErrorGeneric(%v) handling isn't" + - " implemented.", msg.ErrorID) + peerLog.Warnf("ErrorGeneric(%v) handling isn't"+ + " implemented.", msg.Code) } - case *lnwire.HTLCAddRequest: isChanUpdate = true targetChan = msg.ChannelPoint