diff --git a/htlcswitch/linkfailure.go b/htlcswitch/linkfailure.go new file mode 100644 index 00000000..2f44e434 --- /dev/null +++ b/htlcswitch/linkfailure.go @@ -0,0 +1,95 @@ +package htlcswitch + +import "github.com/go-errors/errors" + +var ( + // ErrLinkShuttingDown signals that the link is shutting down. + ErrLinkShuttingDown = errors.New("link shutting down") +) + +// errorCode encodes the possible types of errors that will make us fail the +// current link. +type errorCode uint8 + +const ( + // ErrInternalError indicates that something internal in the link + // failed. In this case we will send a generic error to our peer. + ErrInternalError errorCode = iota + + // ErrRemoteError indicates that our peer sent an error, prompting up + // to fail the link. + ErrRemoteError + + // ErrSyncError indicates that we failed synchronizing the state of the + // channel with our peer. + ErrSyncError + + // ErrInvalidUpdate indicates that the peer send us an invalid update. + ErrInvalidUpdate + + // ErrInvalidCommitment indicates that the remote peer sent us an + // invalid commitment signature. + ErrInvalidCommitment + + // ErrInvalidRevocation indicates that the remote peer send us an + // invalid revocation message. + ErrInvalidRevocation +) + +// LinkFailureError encapsulates an error that will make us fail the current +// link. It contains the necessary information needed to determine if we should +// force close the channel in the process, and if any error data should be sent +// to the peer. +type LinkFailureError struct { + // code is the type of error this LinkFailureError encapsulates. + code errorCode + + // ForceClose indicates whether we should force close the channel + // because of this error. + ForceClose bool + + // SendData is a byte slice that will be sent to the peer. If nil a + // generic error will be sent. + SendData []byte +} + +// A compile time check to ensure LinkFailureError implements the error +// interface. +var _ error = (*LinkFailureError)(nil) + +// Error returns a generic error for the LinkFailureError. +// +// NOTE: Part of the error interface. +func (e LinkFailureError) Error() string { + switch e.code { + case ErrInternalError: + return "internal error" + case ErrRemoteError: + return "remote error" + case ErrSyncError: + return "sync error" + case ErrInvalidUpdate: + return "invalid update" + case ErrInvalidCommitment: + return "invalid commitment" + case ErrInvalidRevocation: + return "invalid revocation" + default: + return "unknown error" + } +} + +// ShouldSendToPeer indicates whether we should send an error to the peer if +// the link fails with this LinkFailureError. +func (e LinkFailureError) ShouldSendToPeer() bool { + switch e.code { + // If the failure is a result of the peer sending us an error, we don't + // have to respond with one. + case ErrRemoteError: + return false + + // In all other cases we will attempt to send our peer an error message. + default: + return true + } +}