lnd/htlcswitch/linkfailure.go

154 lines
4.5 KiB
Go
Raw Normal View History

package htlcswitch
import "github.com/go-errors/errors"
var (
// ErrLinkShuttingDown signals that the link is shutting down.
ErrLinkShuttingDown = errors.New("link shutting down")
// ErrLinkFailedShutdown signals that a requested shutdown failed.
ErrLinkFailedShutdown = errors.New("link failed to shutdown")
)
// 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
// ErrRemoteUnresponsive indicates that our peer took too long to
// complete a commitment dance.
ErrRemoteUnresponsive
// 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
// ErrRecoveryError the channel was unable to be resumed, we need the
// remote party to force close the channel out on chain now as a
// result.
ErrRecoveryError
// ErrCircuitError indicates a duplicate keystone error was hit in the
// circuit map. This is non-fatal and will resolve itself (usually
// within several minutes).
ErrCircuitError
)
// LinkFailureAction is an enum-like type that describes the action that should
// be taken in response to a link failure.
type LinkFailureAction uint8
const (
// LinkFailureForceNone indicates no action is to be taken.
LinkFailureForceNone LinkFailureAction = iota
// LinkFailureForceClose indicates that the channel should be force
// closed.
LinkFailureForceClose
// LinkFailureDisconnect indicates that we should disconnect in an
// attempt to recycle the connection. This can be useful if we think a
// TCP connection or state machine is stalled.
LinkFailureDisconnect
)
// 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
// FailureAction describes what we should do to fail the channel.
FailureAction LinkFailureAction
// PermanentFailure indicates whether this failure is permanent, and
// the channel should not be attempted loaded again.
PermanentFailure bool
multi: ensure link is always torn down due to db failures, add exponential back off for sql-kvdb failures (#7927) * lnwallet: fix log output msg The log message is off by one. * htlcswitch: fail channel when revoking it fails. When the revocation of a channel state fails after receiving a new CommitmentSigned msg we have to fail the channel otherwise we continue with an unclean state. * docs: update release-docs * htlcswitch: tear down connection if revocation processing fails If we couldn't revoke due to a DB error, then we want to also tear down the connection, as we don't want the other party to continue to send updates. That may lead to de-sync'd state an eventual force close. Otherwise, the database might be able to recover come the next reconnection attempt. * kvdb: use sql.LevelSerializable for all backends In this commit, we modify the default isolation level to be `sql.LevelSerializable. This is the strictness isolation type for postgres. For sqlite, there's only ever a single writer, so this doesn't apply directly. * kvdb/sqlbase: add randomized exponential backoff for serialization failures In this commit, we add randomized exponential backoff for serialization failures. For postgres, we''ll his this any time a transaction set fails to be linearized. For sqlite, we'll his this if we have many writers trying to grab the write lock at time same time, manifesting as a `SQLITE_BUSY` error code. As is, we'll retry up to 10 times, waiting a minimum of 50 miliseconds between each attempt, up to 5 seconds without any delay at all. For sqlite, this is also bounded by the busy timeout set, which applies on top of this retry logic (block for busy timeout seconds, then apply this back off logic). * docs/release-notes: add entry for sqlite/postgres tx retry --------- Co-authored-by: ziggie <ziggie1984@protonmail.com>
2023-08-31 01:48:00 +02:00
// Warning denotes if this is a non-terminal error that doesn't warrant
// failing the channel all together.
Warning 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 ErrRemoteUnresponsive:
return "remote unresponsive"
case ErrSyncError:
return "sync error"
case ErrInvalidUpdate:
return "invalid update"
case ErrInvalidCommitment:
return "invalid commitment"
case ErrInvalidRevocation:
return "invalid revocation"
case ErrRecoveryError:
return "unable to resume channel, recovery required"
case ErrCircuitError:
return "non-fatal circuit map error"
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 {
// Since sending an error can lead some nodes to force close the
// channel, create a whitelist of the failures we want to send so that
// newly added error codes aren't automatically sent to the remote peer.
case
ErrInternalError,
ErrRemoteError,
ErrSyncError,
ErrInvalidUpdate,
ErrInvalidCommitment,
ErrInvalidRevocation,
ErrRecoveryError:
return true
// In all other cases we will not attempt to send our peer an error.
default:
return false
}
}