lnwire: add specification onion errors
In this commit onion routing error from BOLT#4 have been added, the initial error construction have been splitted on two parts: The first part which contains the actual data will reside inside the lnwire package because it contains all necessary function to decode/encode the data. The second part obfuscation and hmac checking will resides inside the lighting-onion package because it requires the key generation.
This commit is contained in:
parent
d43a660cb1
commit
98956bc2fe
@ -108,12 +108,21 @@ func (u *UnknownMessage) Error() string {
|
||||
u.messageType)
|
||||
}
|
||||
|
||||
// Serializable is an interface which defines a lightning wire serializable
|
||||
// object.
|
||||
type Serializable interface {
|
||||
// Decode reads the bytes stream and converts it to the object.
|
||||
Decode(io.Reader, uint32) error
|
||||
|
||||
// Encode converts object to the bytes stream and write it in th writer.
|
||||
Encode(io.Writer, uint32) error
|
||||
}
|
||||
|
||||
// Message is an interface that defines a lightning wire protocol message. The
|
||||
// interface is general in order to allow implementing types full control over
|
||||
// the representation of its data.
|
||||
type Message interface {
|
||||
Decode(io.Reader, uint32) error
|
||||
Encode(io.Writer, uint32) error
|
||||
Serializable
|
||||
MsgType() MessageType
|
||||
MaxPayloadLength(uint32) uint32
|
||||
}
|
||||
|
985
lnwire/onion_error.go
Normal file
985
lnwire/onion_error.go
Normal file
@ -0,0 +1,985 @@
|
||||
package lnwire
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"io"
|
||||
|
||||
"bytes"
|
||||
|
||||
"github.com/go-errors/errors"
|
||||
"github.com/roasbeef/btcutil"
|
||||
)
|
||||
|
||||
// FailureMessage represent the onion failure object which is able to identify itself
|
||||
// by returning the unique failure code.
|
||||
type FailureMessage interface {
|
||||
Code() FailCode
|
||||
}
|
||||
|
||||
// failureMessageLength is the size of the failure message plus the size
|
||||
// of padding. FailureMessage message always should be equals to this size.
|
||||
const failureMessageLength = 128
|
||||
|
||||
const (
|
||||
// FlagBadOnion error flag denotes unparsable onion, encrypted by
|
||||
// previous node.
|
||||
FlagBadOnion FailCode = 0x8000
|
||||
|
||||
// FlagPerm error flag denotes permanent failure.
|
||||
FlagPerm FailCode = 0x4000
|
||||
|
||||
// FlagNode error flag denotes node failure.
|
||||
FlagNode FailCode = 0x2000
|
||||
|
||||
// FlagUpdate error flag denotes new channel update enclosed.
|
||||
FlagUpdate FailCode = 0x1000
|
||||
)
|
||||
|
||||
// FailCode specifies the precise reason that an upstream HTLC was cancelled.
|
||||
// Each UpdateFailHTLC message carries a FailCode which is to be passed back
|
||||
// unaltered to the source of the HTLC within the route.
|
||||
type FailCode uint16
|
||||
|
||||
// The currently defined onion failure types within this current version of the
|
||||
// Lightning protocol.
|
||||
const (
|
||||
CodeNone FailCode = 0
|
||||
CodeInvalidRealm = FlagBadOnion | 1
|
||||
CodeTemporaryNodeFailure = FlagNode | 2
|
||||
CodePermanentNodeFailure = FlagPerm | FlagNode | 2
|
||||
CodeRequiredNodeFeatureMissing = FlagPerm | FlagNode | 3
|
||||
CodeInvalidOnionVersion = FlagBadOnion | FlagPerm | 4
|
||||
CodeInvalidOnionHmac = FlagBadOnion | FlagPerm | 5
|
||||
CodeInvalidOnionKey = FlagBadOnion | FlagPerm | 6
|
||||
CodeTemporaryChannelFailure = FlagUpdate | 7
|
||||
CodePermanentChannelFailure = FlagPerm | 8
|
||||
CodeRequiredChannelFeatureMissing = FlagPerm | 9
|
||||
CodeUnknownNextPeer = FlagPerm | 10
|
||||
CodeAmountBelowMinimum = FlagUpdate | 11
|
||||
CodeFeeInsufficient = FlagUpdate | 12
|
||||
CodeIncorrectCltvExpiry = FlagUpdate | 13
|
||||
CodeExpiryTooSoon = FlagUpdate | 14
|
||||
CodeChannelDisabled = FlagUpdate | 20
|
||||
CodeUnknownPaymentHash = FlagPerm | 15
|
||||
CodeIncorrectPaymentAmount = FlagPerm | 16
|
||||
CodeFinalExpiryTooSoon FailCode = 17
|
||||
CodeFinalIncorrectCltvExpiry FailCode = 18
|
||||
CodeFinalIncorrectHtlcAmount FailCode = 19
|
||||
)
|
||||
|
||||
// String returns string representation of the failure code.
|
||||
func (c FailCode) String() string {
|
||||
switch c {
|
||||
case CodeInvalidRealm:
|
||||
return "InvalidRealm"
|
||||
|
||||
case CodeTemporaryNodeFailure:
|
||||
return "TemporaryNodeFailure"
|
||||
|
||||
case CodePermanentNodeFailure:
|
||||
return "PermanentNodeFailure"
|
||||
|
||||
case CodeRequiredNodeFeatureMissing:
|
||||
return "RequiredNodeFeatureMissing"
|
||||
|
||||
case CodeInvalidOnionVersion:
|
||||
return "InvalidOnionVersion"
|
||||
|
||||
case CodeInvalidOnionHmac:
|
||||
return "InvalidOnionHmac"
|
||||
|
||||
case CodeInvalidOnionKey:
|
||||
return "InvalidOnionKey"
|
||||
|
||||
case CodeTemporaryChannelFailure:
|
||||
return "TemporaryChannelFailure"
|
||||
|
||||
case CodePermanentChannelFailure:
|
||||
return "PermanentChannelFailure"
|
||||
|
||||
case CodeRequiredChannelFeatureMissing:
|
||||
return "RequiredChannelFeatureMissing"
|
||||
|
||||
case CodeUnknownNextPeer:
|
||||
return "UnknownNextPeer"
|
||||
|
||||
case CodeAmountBelowMinimum:
|
||||
return "AmountBelowMinimum"
|
||||
|
||||
case CodeFeeInsufficient:
|
||||
return "FeeInsufficient"
|
||||
|
||||
case CodeIncorrectCltvExpiry:
|
||||
return "IncorrectCltvExpiry"
|
||||
|
||||
case CodeExpiryTooSoon:
|
||||
return "ExpiryTooSoon"
|
||||
|
||||
case CodeChannelDisabled:
|
||||
return "ChannelDisabled"
|
||||
|
||||
case CodeUnknownPaymentHash:
|
||||
return "UnknownPaymentHash"
|
||||
|
||||
case CodeIncorrectPaymentAmount:
|
||||
return "IncorrectPaymentAmount"
|
||||
|
||||
case CodeFinalExpiryTooSoon:
|
||||
return "FinalExpiryTooSoon"
|
||||
|
||||
case CodeFinalIncorrectCltvExpiry:
|
||||
return "FinalIncorrectCltvExpiry"
|
||||
|
||||
case CodeFinalIncorrectHtlcAmount:
|
||||
return "FinalIncorrectHtlcAmount"
|
||||
|
||||
default:
|
||||
return "<unknown>"
|
||||
}
|
||||
}
|
||||
|
||||
// FailInvalidRealm is returned if the realm byte is unknown.
|
||||
//
|
||||
// NOTE: might be returned by any node.
|
||||
type FailInvalidRealm struct{}
|
||||
|
||||
// Code returns the failure unique code.
|
||||
//
|
||||
// NOTE: Part of the FailureMessage interface.
|
||||
func (f FailInvalidRealm) Code() FailCode {
|
||||
return CodeInvalidRealm
|
||||
}
|
||||
|
||||
// FailTemporaryNodeFailure is returned if an otherwise unspecified transient
|
||||
// error occurs for the entire node.
|
||||
//
|
||||
// NOTE: might be returned by any node.
|
||||
type FailTemporaryNodeFailure struct{}
|
||||
|
||||
// Code returns the failure unique code.
|
||||
// NOTE: Part of the FailureMessage interface.
|
||||
func (f FailTemporaryNodeFailure) Code() FailCode {
|
||||
return CodeTemporaryNodeFailure
|
||||
}
|
||||
|
||||
// FailPermanentNodeFailure is returned if an otherwise unspecified permanent
|
||||
// error occurs for the entire node.
|
||||
//
|
||||
// NOTE: might be returned by any node.
|
||||
type FailPermanentNodeFailure struct{}
|
||||
|
||||
// Code returns the failure unique code.
|
||||
//
|
||||
// NOTE: Part of the FailureMessage interface.
|
||||
func (f FailPermanentNodeFailure) Code() FailCode {
|
||||
return CodePermanentNodeFailure
|
||||
}
|
||||
|
||||
// FailRequiredNodeFeatureMissing is returned if a node has requirement
|
||||
// advertised in its node_announcement features which were not present in the
|
||||
// onion.
|
||||
//
|
||||
// NOTE: might be returned by any node.
|
||||
type FailRequiredNodeFeatureMissing struct{}
|
||||
|
||||
// Code returns the failure unique code.
|
||||
//
|
||||
// NOTE: Part of the FailureMessage interface.
|
||||
func (f FailRequiredNodeFeatureMissing) Code() FailCode {
|
||||
return CodeRequiredNodeFeatureMissing
|
||||
}
|
||||
|
||||
// FailPermanentChannelFailure is return if an otherwise unspecified
|
||||
// permanent error occurs for the outgoing channel (eg. channel (recently).
|
||||
//
|
||||
// NOTE: might be return by forwarding node only.
|
||||
type FailPermanentChannelFailure struct{}
|
||||
|
||||
// Code returns the failure unique code.
|
||||
//
|
||||
// NOTE: Part of the FailureMessage interface.
|
||||
func (f FailPermanentChannelFailure) Code() FailCode {
|
||||
return CodePermanentChannelFailure
|
||||
}
|
||||
|
||||
// FailRequiredChannelFeatureMissing is return if the outgoing channel has
|
||||
// requirement advertised in its channel announcement features which were not
|
||||
// present in the onion.
|
||||
//
|
||||
// NOTE: might be return by forwarding node only.
|
||||
type FailRequiredChannelFeatureMissing struct{}
|
||||
|
||||
// Code returns the failure unique code.
|
||||
//
|
||||
// NOTE: Part of the FailureMessage interface.
|
||||
func (f FailRequiredChannelFeatureMissing) Code() FailCode {
|
||||
return CodeRequiredChannelFeatureMissing
|
||||
}
|
||||
|
||||
// FailUnknownNextPeer is returned if the next peer specified by the onion is
|
||||
// not known.
|
||||
//
|
||||
// NOTE: might be return by forwarding node only.
|
||||
type FailUnknownNextPeer struct{}
|
||||
|
||||
// Code returns the failure unique code.
|
||||
//
|
||||
// NOTE: Part of the FailureMessage interface.
|
||||
func (f FailUnknownNextPeer) Code() FailCode {
|
||||
return CodeUnknownNextPeer
|
||||
}
|
||||
|
||||
// FailUnknownPaymentHash is returned If the payment hash has already been paid,
|
||||
// the final node MAY treat the payment hash as unknown, or may succeed in
|
||||
// accepting the HTLC. If the payment hash is unknown, the final node MUST fail
|
||||
// the HTLC.
|
||||
//
|
||||
// NOTE: might be returned by final node only.
|
||||
type FailUnknownPaymentHash struct{}
|
||||
|
||||
// Code returns the failure unique code.
|
||||
//
|
||||
// NOTE: Part of the FailureMessage interface.
|
||||
func (f FailUnknownPaymentHash) Code() FailCode {
|
||||
return CodeUnknownPaymentHash
|
||||
}
|
||||
|
||||
// FailIncorrectPaymentAmount is returned if the amount paid is less than the
|
||||
// amount expected, the final node MUST fail the HTLC. If the amount paid is
|
||||
// more than twice the amount expected, the final node SHOULD fail the HTLC.
|
||||
// This allows the sender to reduce information leakage by altering the amount,
|
||||
// without allowing accidental gross overpayment.
|
||||
//
|
||||
// NOTE: might be returned by final node only.
|
||||
type FailIncorrectPaymentAmount struct{}
|
||||
|
||||
// Code returns the failure unique code.
|
||||
//
|
||||
// NOTE: Part of the FailureMessage interface.
|
||||
func (f FailIncorrectPaymentAmount) Code() FailCode {
|
||||
return CodeIncorrectPaymentAmount
|
||||
}
|
||||
|
||||
// FailFinalExpiryTooSoon is returned if the cltv_expiry is too low, the final
|
||||
// node MUST fail the HTLC.
|
||||
//
|
||||
// NOTE: might be returned by final node only.
|
||||
type FailFinalExpiryTooSoon struct{}
|
||||
|
||||
// Code returns the failure unique code.
|
||||
//
|
||||
// NOTE: Part of the FailureMessage interface.
|
||||
func (f FailFinalExpiryTooSoon) Code() FailCode {
|
||||
return CodeFinalExpiryTooSoon
|
||||
}
|
||||
|
||||
// FailInvalidOnionVersion is returned if the onion version byte is unknown.
|
||||
//
|
||||
// NOTE: should be return by forwarding node only.
|
||||
type FailInvalidOnionVersion struct {
|
||||
// OnionSHA256 hash of the onion blob which haven't been proceeded.
|
||||
OnionSHA256 [sha256.Size]byte
|
||||
}
|
||||
|
||||
// NewInvalidOnionVersion creates new instance of the FailInvalidOnionVersion.
|
||||
func NewInvalidOnionVersion(onion []byte) *FailInvalidOnionVersion {
|
||||
return &FailInvalidOnionVersion{OnionSHA256: sha256.Sum256(onion)}
|
||||
}
|
||||
|
||||
// Code returns the failure unique code.
|
||||
//
|
||||
// NOTE: Part of the FailureMessage interface.
|
||||
func (f *FailInvalidOnionVersion) Code() FailCode {
|
||||
return CodeInvalidOnionVersion
|
||||
}
|
||||
|
||||
// Decode decodes the failure from bytes stream.
|
||||
//
|
||||
// NOTE: Part of the Serializable interface.
|
||||
func (f *FailInvalidOnionVersion) Decode(r io.Reader, pver uint32) error {
|
||||
return readElement(r, f.OnionSHA256[:])
|
||||
}
|
||||
|
||||
// Encode writes the failure in bytes stream.
|
||||
//
|
||||
// NOTE: Part of the Serializable interface.
|
||||
func (f *FailInvalidOnionVersion) Encode(w io.Writer, pver uint32) error {
|
||||
return writeElement(w, f.OnionSHA256[:])
|
||||
}
|
||||
|
||||
// FailInvalidOnionHmac is return if the onion HMAC is incorrect.
|
||||
//
|
||||
// NOTE: might be return by forwarding node only.
|
||||
type FailInvalidOnionHmac struct {
|
||||
// OnionSHA256 hash of the onion blob which haven't been proceeded.
|
||||
OnionSHA256 [sha256.Size]byte
|
||||
}
|
||||
|
||||
// NewInvalidOnionHmac creates new instance of the FailInvalidOnionHmac.
|
||||
func NewInvalidOnionHmac(onion []byte) *FailInvalidOnionHmac {
|
||||
return &FailInvalidOnionHmac{OnionSHA256: sha256.Sum256(onion)}
|
||||
}
|
||||
|
||||
// Code returns the failure unique code.
|
||||
//
|
||||
// NOTE: Part of the FailureMessage interface.
|
||||
func (f *FailInvalidOnionHmac) Code() FailCode {
|
||||
return CodeInvalidOnionHmac
|
||||
}
|
||||
|
||||
// Decode decodes the failure from bytes stream.
|
||||
//
|
||||
// NOTE: Part of the Serializable interface.
|
||||
func (f *FailInvalidOnionHmac) Decode(r io.Reader, pver uint32) error {
|
||||
return readElement(r, f.OnionSHA256[:])
|
||||
}
|
||||
|
||||
// Encode writes the failure in bytes stream.
|
||||
//
|
||||
// NOTE: Part of the Serializable interface.
|
||||
func (f *FailInvalidOnionHmac) Encode(w io.Writer, pver uint32) error {
|
||||
return writeElement(w, f.OnionSHA256[:])
|
||||
}
|
||||
|
||||
// FailInvalidOnionKey is return if the ephemeral key in the onion is
|
||||
// unparsable.
|
||||
//
|
||||
// NOTE: might be return by forwarding node only.
|
||||
type FailInvalidOnionKey struct {
|
||||
// OnionSHA256 hash of the onion blob which haven't been proceeded.
|
||||
OnionSHA256 [sha256.Size]byte
|
||||
}
|
||||
|
||||
// NewInvalidOnionKey creates new instance of the FailInvalidOnionKey.
|
||||
func NewInvalidOnionKey(onion []byte) *FailInvalidOnionKey {
|
||||
return &FailInvalidOnionKey{OnionSHA256: sha256.Sum256(onion)}
|
||||
}
|
||||
|
||||
// Code returns the failure unique code.
|
||||
//
|
||||
// NOTE: Part of the FailureMessage interface.
|
||||
func (f *FailInvalidOnionKey) Code() FailCode {
|
||||
return CodeInvalidOnionKey
|
||||
}
|
||||
|
||||
// Decode decodes the failure from bytes stream.
|
||||
//
|
||||
// NOTE: Part of the Serializable interface.
|
||||
func (f *FailInvalidOnionKey) Decode(r io.Reader, pver uint32) error {
|
||||
return readElement(r, f.OnionSHA256[:])
|
||||
}
|
||||
|
||||
// Encode writes the failure in bytes stream.
|
||||
//
|
||||
// NOTE: Part of the Serializable interface.
|
||||
func (f *FailInvalidOnionKey) Encode(w io.Writer, pver uint32) error {
|
||||
return writeElement(w, f.OnionSHA256[:])
|
||||
}
|
||||
|
||||
// FailTemporaryChannelFailure is if an otherwise unspecified transient
|
||||
// error occurs for the outgoing channel (eg. channel capacity reached,
|
||||
// too many in-flight htlc)
|
||||
//
|
||||
// NOTE: might be return by forwarding node only.
|
||||
type FailTemporaryChannelFailure struct {
|
||||
// Update is used to update information about state of the channel which
|
||||
// caused the failure.
|
||||
//
|
||||
// NOTE: Field is optional.
|
||||
Update *ChannelUpdate
|
||||
}
|
||||
|
||||
// NewTemporaryChannelFailure creates new instance of the FailTemporaryChannelFailure.
|
||||
func NewTemporaryChannelFailure(update *ChannelUpdate) *FailTemporaryChannelFailure {
|
||||
return &FailTemporaryChannelFailure{Update: update}
|
||||
}
|
||||
|
||||
// Code returns the failure unique code.
|
||||
//
|
||||
// NOTE: Part of the FailureMessage interface.
|
||||
func (f *FailTemporaryChannelFailure) Code() FailCode {
|
||||
return CodeTemporaryChannelFailure
|
||||
}
|
||||
|
||||
// Decode decodes the failure from bytes stream.
|
||||
//
|
||||
// NOTE: Part of the Serializable interface.
|
||||
func (f *FailTemporaryChannelFailure) Decode(r io.Reader, pver uint32) error {
|
||||
var length uint16
|
||||
err := readElement(r, &length)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if length != 0 {
|
||||
f.Update = &ChannelUpdate{}
|
||||
return f.Update.Decode(r, pver)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Encode writes the failure in bytes stream.
|
||||
//
|
||||
// NOTE: Part of the Serializable interface.
|
||||
func (f *FailTemporaryChannelFailure) Encode(w io.Writer, pver uint32) error {
|
||||
var payload []byte
|
||||
if f.Update != nil {
|
||||
var bw bytes.Buffer
|
||||
if err := f.Update.Encode(&bw, pver); err != nil {
|
||||
return err
|
||||
}
|
||||
payload = bw.Bytes()
|
||||
}
|
||||
|
||||
if err := writeElement(w, uint16(len(payload))); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err := w.Write(payload)
|
||||
return err
|
||||
}
|
||||
|
||||
// FailAmountBelowMinimum is returned if the HTLC does not reach the
|
||||
// current minimum amount, we tell them the amount of the incoming HTLC
|
||||
// and the current channel setting for the outgoing channel.
|
||||
//
|
||||
// NOTE: might be return by forwarding node only.
|
||||
type FailAmountBelowMinimum struct {
|
||||
// HtlcMsat is the wrong amount of the incoming HTLC.
|
||||
HtlcMsat btcutil.Amount
|
||||
|
||||
// Update is used to update information about state of the channel which
|
||||
// caused the failure.
|
||||
Update ChannelUpdate
|
||||
}
|
||||
|
||||
// NewAmountBelowMinimum creates new instance of the FailAmountBelowMinimum.
|
||||
func NewAmountBelowMinimum(htlcMsat btcutil.Amount,
|
||||
update ChannelUpdate) *FailAmountBelowMinimum {
|
||||
return &FailAmountBelowMinimum{
|
||||
HtlcMsat: htlcMsat,
|
||||
Update: update,
|
||||
}
|
||||
}
|
||||
|
||||
// Code returns the failure unique code.
|
||||
//
|
||||
// NOTE: Part of the FailureMessage interface.
|
||||
func (f *FailAmountBelowMinimum) Code() FailCode {
|
||||
return CodeAmountBelowMinimum
|
||||
}
|
||||
|
||||
// Decode decodes the failure from bytes stream.
|
||||
//
|
||||
// NOTE: Part of the Serializable interface.
|
||||
func (f *FailAmountBelowMinimum) Decode(r io.Reader, pver uint32) error {
|
||||
if err := readElement(r, &f.HtlcMsat); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// At current moment length is not used but in future we may use it to
|
||||
// differ versions of the update message.
|
||||
var length uint16
|
||||
if err := readElement(r, &length); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
f.Update = ChannelUpdate{}
|
||||
return f.Update.Decode(r, pver)
|
||||
}
|
||||
|
||||
// Encode writes the failure in bytes stream.
|
||||
//
|
||||
// NOTE: Part of the Serializable interface.
|
||||
func (f *FailAmountBelowMinimum) Encode(w io.Writer, pver uint32) error {
|
||||
if err := writeElement(w, f.HtlcMsat); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// We write the length here as the size of the channel updates may differ in
|
||||
// the future and at times additional information is coupled (appended to or
|
||||
// prepended to the channel update itself) along with the channel update.
|
||||
err := writeElement(w, uint16(f.Update.MaxPayloadLength(pver)))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return f.Update.Encode(w, pver)
|
||||
}
|
||||
|
||||
// FailFeeInsufficient is returned if the HTLC does not pay sufficient
|
||||
// fee, we tell them the amount of the incoming HTLC and the current
|
||||
// channel setting for the outgoing channel.
|
||||
//
|
||||
// NOTE: might be return by forwarding node only.
|
||||
type FailFeeInsufficient struct {
|
||||
// HtlcMsat is the wrong amount of the incoming HTLC.
|
||||
HtlcMsat btcutil.Amount
|
||||
|
||||
// Update is used to update information about state of the channel which
|
||||
// caused the failure.
|
||||
Update ChannelUpdate
|
||||
}
|
||||
|
||||
// NewFeeInsufficient creates new instance of the FailFeeInsufficient.
|
||||
func NewFeeInsufficient(htlcMsat btcutil.Amount,
|
||||
update ChannelUpdate) *FailFeeInsufficient {
|
||||
return &FailFeeInsufficient{
|
||||
HtlcMsat: htlcMsat,
|
||||
Update: update,
|
||||
}
|
||||
}
|
||||
|
||||
// Code returns the failure unique code.
|
||||
//
|
||||
// NOTE: Part of the FailureMessage interface.
|
||||
func (f *FailFeeInsufficient) Code() FailCode {
|
||||
return CodeFeeInsufficient
|
||||
}
|
||||
|
||||
// Decode decodes the failure from bytes stream.
|
||||
//
|
||||
// NOTE: Part of the Serializable interface.
|
||||
func (f *FailFeeInsufficient) Decode(r io.Reader, pver uint32) error {
|
||||
if err := readElement(r, &f.HtlcMsat); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// At current moment length is not used but in future we may use it to
|
||||
// differ versions of the update message.
|
||||
var length uint16
|
||||
if err := readElement(r, &length); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
f.Update = ChannelUpdate{}
|
||||
return f.Update.Decode(r, pver)
|
||||
}
|
||||
|
||||
// Encode writes the failure in bytes stream.
|
||||
//
|
||||
// NOTE: Part of the Serializable interface.
|
||||
func (f *FailFeeInsufficient) Encode(w io.Writer, pver uint32) error {
|
||||
if err := writeElement(w, f.HtlcMsat); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// We write the length here as the size of the channel updates may differ in
|
||||
// the future and at times additional information is coupled (appended to or
|
||||
// prepended to the channel update itself) along with the channel update.
|
||||
err := writeElement(w, uint16(f.Update.MaxPayloadLength(pver)))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return f.Update.Encode(w, pver)
|
||||
}
|
||||
|
||||
// FailIncorrectCltvExpiry is returned if outgoing cltv value does not
|
||||
// match the update add htlc's cltv expiry minus cltv expiry delta
|
||||
// for the outgoing channel, we tell them the cltv expiry and the
|
||||
// current channel setting for the outgoing channel.
|
||||
//
|
||||
// NOTE: might be return by forwarding node only.
|
||||
type FailIncorrectCltvExpiry struct {
|
||||
// CltvExpiry is the wrong absolute timeout in blocks, after which outgoing
|
||||
// HTLC expires.
|
||||
CltvExpiry uint32
|
||||
|
||||
// Update is used to update information about state of the channel which
|
||||
// caused the failure.
|
||||
Update ChannelUpdate
|
||||
}
|
||||
|
||||
// NewIncorrectCltvExpiry creates new instance of the FailIncorrectCltvExpiry.
|
||||
func NewIncorrectCltvExpiry(cltvExpiry uint32, update ChannelUpdate) *FailIncorrectCltvExpiry {
|
||||
return &FailIncorrectCltvExpiry{
|
||||
CltvExpiry: cltvExpiry,
|
||||
Update: update,
|
||||
}
|
||||
}
|
||||
|
||||
// Code returns the failure unique code.
|
||||
//
|
||||
// NOTE: Part of the FailureMessage interface.
|
||||
func (f *FailIncorrectCltvExpiry) Code() FailCode {
|
||||
return CodeIncorrectCltvExpiry
|
||||
}
|
||||
|
||||
// Decode decodes the failure from bytes stream.
|
||||
//
|
||||
// NOTE: Part of the Serializable interface.
|
||||
func (f *FailIncorrectCltvExpiry) Decode(r io.Reader, pver uint32) error {
|
||||
if err := readElement(r, &f.CltvExpiry); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// At current moment length is not used but in future we may use it to
|
||||
// differ versions of the update message.
|
||||
var length uint16
|
||||
if err := readElement(r, &length); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
f.Update = ChannelUpdate{}
|
||||
return f.Update.Decode(r, pver)
|
||||
}
|
||||
|
||||
// Encode writes the failure in bytes stream.
|
||||
//
|
||||
// NOTE: Part of the Serializable interface.
|
||||
func (f *FailIncorrectCltvExpiry) Encode(w io.Writer, pver uint32) error {
|
||||
if err := writeElement(w, f.CltvExpiry); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// We write the length here as the size of the channel updates may differ in
|
||||
// the future and at times additional information is coupled (appended to or
|
||||
// prepended to the channel update itself) along with the channel update.
|
||||
err := writeElement(w, uint16(f.Update.MaxPayloadLength(pver)))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return f.Update.Encode(w, pver)
|
||||
}
|
||||
|
||||
// FailExpiryTooSoon is returned if the ctlv-expiry is too near, we tell
|
||||
// them the the current channel setting for the outgoing channel.
|
||||
//
|
||||
// NOTE: might be return by forwarding node only.
|
||||
type FailExpiryTooSoon struct {
|
||||
// Update is used to update information about state of the channel which
|
||||
// caused the failure.
|
||||
Update ChannelUpdate
|
||||
}
|
||||
|
||||
// NewExpiryTooSoon creates new instance of the FailExpiryTooSoon
|
||||
func NewExpiryTooSoon(update ChannelUpdate) *FailExpiryTooSoon {
|
||||
return &FailExpiryTooSoon{
|
||||
Update: update,
|
||||
}
|
||||
}
|
||||
|
||||
// Code returns the failure unique code.
|
||||
//
|
||||
// NOTE: Part of the FailureMessage interface.
|
||||
func (f *FailExpiryTooSoon) Code() FailCode {
|
||||
return CodeExpiryTooSoon
|
||||
}
|
||||
|
||||
// Decode decodes the failure from bytes stream.
|
||||
//
|
||||
// NOTE: Part of the Serializable interface.
|
||||
func (f *FailExpiryTooSoon) Decode(r io.Reader, pver uint32) error {
|
||||
// At current moment length is not used but in future we may use it to
|
||||
// differ versions of the update message.
|
||||
var length uint16
|
||||
if err := readElement(r, &length); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
f.Update = ChannelUpdate{}
|
||||
return f.Update.Decode(r, pver)
|
||||
}
|
||||
|
||||
// Encode writes the failure in bytes stream.
|
||||
//
|
||||
// NOTE: Part of the Serializable interface.
|
||||
func (f *FailExpiryTooSoon) Encode(w io.Writer, pver uint32) error {
|
||||
// We write the length here as the size of the channel updates may differ in
|
||||
// the future and at times additional information is coupled (appended to or
|
||||
// prepended to the channel update itself) along with the channel update.
|
||||
err := writeElement(w, uint16(f.Update.MaxPayloadLength(pver)))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return f.Update.Encode(w, pver)
|
||||
}
|
||||
|
||||
// FailChannelDisabled is returned if the channel is disabled, we tell
|
||||
// them the the current channel setting for the outgoing channel.
|
||||
//
|
||||
// NOTE: might be return by forwarding node only.
|
||||
type FailChannelDisabled struct {
|
||||
// Flags least-significant bit must be set to 0 if the creating node
|
||||
// corresponds to the first node in the previously sent channel
|
||||
// announcement and 1 otherwise.
|
||||
Flags uint16
|
||||
|
||||
// Update is used to update information about state of the channel which
|
||||
// caused the failure.
|
||||
Update ChannelUpdate
|
||||
}
|
||||
|
||||
// NewChannelDisabled creates new instance of the FailChannelDisabled.
|
||||
func NewChannelDisabled(flags uint16, update ChannelUpdate) *FailChannelDisabled {
|
||||
return &FailChannelDisabled{
|
||||
Flags: flags,
|
||||
Update: update,
|
||||
}
|
||||
}
|
||||
|
||||
// Code returns the failure unique code.
|
||||
//
|
||||
// NOTE: Part of the FailureMessage interface.
|
||||
func (f *FailChannelDisabled) Code() FailCode {
|
||||
return CodeChannelDisabled
|
||||
}
|
||||
|
||||
// Decode decodes the failure from bytes stream.
|
||||
//
|
||||
// NOTE: Part of the Serializable interface.
|
||||
func (f *FailChannelDisabled) Decode(r io.Reader, pver uint32) error {
|
||||
if err := readElement(r, &f.Flags); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// At current moment length is not used but in future we may use it to
|
||||
// differ versions of the update message.
|
||||
var length uint16
|
||||
if err := readElement(r, &length); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
f.Update = ChannelUpdate{}
|
||||
return f.Update.Decode(r, pver)
|
||||
}
|
||||
|
||||
// Encode writes the failure in bytes stream.
|
||||
//
|
||||
// NOTE: Part of the Serializable interface.
|
||||
func (f *FailChannelDisabled) Encode(w io.Writer, pver uint32) error {
|
||||
if err := writeElement(w, f.Flags); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// We write the length here as the size of the channel updates may differ in
|
||||
// the future and at times additional information is coupled (appended to or
|
||||
// prepended to the channel update itself) along with the channel update.
|
||||
err := writeElement(w, uint16(f.Update.MaxPayloadLength(pver)))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return f.Update.Encode(w, pver)
|
||||
}
|
||||
|
||||
// FailFinalIncorrectCltvExpiry is returned if the outgoing_cltv_value does not
|
||||
// match the ctlv_expiry of the HTLC at the final hop.
|
||||
//
|
||||
// NOTE: might be returned by final node only.
|
||||
type FailFinalIncorrectCltvExpiry struct {
|
||||
// CltvExpiry is the wrong absolute timeout in blocks, after which outgoing
|
||||
// HTLC expires.
|
||||
CltvExpiry uint32
|
||||
}
|
||||
|
||||
// NewFinalIncorrectCltvExpiry creates new instance of the
|
||||
// FailFinalIncorrectCltvExpiry.
|
||||
func NewFinalIncorrectCltvExpiry(cltvExpiry uint32) *FailFinalIncorrectCltvExpiry {
|
||||
return &FailFinalIncorrectCltvExpiry{
|
||||
CltvExpiry: cltvExpiry,
|
||||
}
|
||||
}
|
||||
|
||||
// Code returns the failure unique code.
|
||||
//
|
||||
// NOTE: Part of the FailureMessage interface.
|
||||
func (f *FailFinalIncorrectCltvExpiry) Code() FailCode {
|
||||
return CodeFinalIncorrectCltvExpiry
|
||||
}
|
||||
|
||||
// Decode decodes the failure from bytes stream.
|
||||
//
|
||||
// NOTE: Part of the Serializable interface.
|
||||
func (f *FailFinalIncorrectCltvExpiry) Decode(r io.Reader, pver uint32) error {
|
||||
return readElement(r, &f.CltvExpiry)
|
||||
}
|
||||
|
||||
// Encode writes the failure in bytes stream.
|
||||
//
|
||||
// NOTE: Part of the Serializable interface.
|
||||
func (f *FailFinalIncorrectCltvExpiry) Encode(w io.Writer, pver uint32) error {
|
||||
return writeElement(w, f.CltvExpiry)
|
||||
}
|
||||
|
||||
// FailFinalIncorrectHtlcAmount is returned if the amt_to_forward is
|
||||
// higher than incoming_htlc_amt of the HTLC at the final hop.
|
||||
//
|
||||
// NOTE: might be returned by final node only.
|
||||
type FailFinalIncorrectHtlcAmount struct {
|
||||
// IncomingHTLCAmount is the wrong forwarded htlc amount.
|
||||
IncomingHTLCAmount btcutil.Amount
|
||||
}
|
||||
|
||||
// NewFinalIncorrectHtlcAmount creates new instance of the
|
||||
// FailFinalIncorrectHtlcAmount.
|
||||
func NewFinalIncorrectHtlcAmount(amount btcutil.Amount) *FailFinalIncorrectHtlcAmount {
|
||||
return &FailFinalIncorrectHtlcAmount{
|
||||
IncomingHTLCAmount: amount,
|
||||
}
|
||||
}
|
||||
|
||||
// Code returns the failure unique code.
|
||||
//
|
||||
// NOTE: Part of the FailureMessage interface.
|
||||
func (f *FailFinalIncorrectHtlcAmount) Code() FailCode {
|
||||
return CodeFinalIncorrectHtlcAmount
|
||||
}
|
||||
|
||||
// Decode decodes the failure from bytes stream.
|
||||
//
|
||||
// NOTE: Part of the Serializable interface.
|
||||
func (f *FailFinalIncorrectHtlcAmount) Decode(r io.Reader, pver uint32) error {
|
||||
return readElement(r, &f.IncomingHTLCAmount)
|
||||
}
|
||||
|
||||
// Encode writes the failure in bytes stream.
|
||||
//
|
||||
// NOTE: Part of the Serializable interface.
|
||||
func (f *FailFinalIncorrectHtlcAmount) Encode(w io.Writer, pver uint32) error {
|
||||
return writeElement(w, f.IncomingHTLCAmount)
|
||||
}
|
||||
|
||||
// DecodeFailure decodes, validates, and parses the lnwire onion failure, for the
|
||||
// provided protocol version.
|
||||
func DecodeFailure(r io.Reader, pver uint32) (FailureMessage, error) {
|
||||
// Start processing the failure message by reading the code.
|
||||
var code uint16
|
||||
if err := readElement(r, &code); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Create the empty failure by given code and populate the failure
|
||||
// with additional data if needed.
|
||||
failure, err := makeEmptyOnionError(FailCode(code))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Read failure length, check its size and read the failure message
|
||||
// in order to check padding afterwards.
|
||||
var failureLength uint16
|
||||
if err := readElement(r, &failureLength); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if failureLength > failureMessageLength {
|
||||
return nil, errors.New("failure message is too long")
|
||||
}
|
||||
|
||||
failureData := make([]byte, failureLength)
|
||||
if _, err := io.ReadFull(r, failureData); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
failureReader := bytes.NewReader(failureData)
|
||||
|
||||
switch f := failure.(type) {
|
||||
case Serializable:
|
||||
if err := f.Decode(failureReader, pver); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return failure, nil
|
||||
}
|
||||
|
||||
// EncodeFailure encodes, including the necessary onion failure header information.
|
||||
func EncodeFailure(w io.Writer, failure FailureMessage, pver uint32) error {
|
||||
var failureMessageBuffer bytes.Buffer
|
||||
|
||||
switch failure := failure.(type) {
|
||||
case Serializable:
|
||||
if err := failure.Encode(&failureMessageBuffer, pver); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
failureMessage := failureMessageBuffer.Bytes()
|
||||
if len(failureMessage) > failureMessageLength {
|
||||
return errors.New("failure message exceed max available size")
|
||||
}
|
||||
|
||||
code := uint16(failure.Code())
|
||||
pad := make([]byte, failureMessageLength-len(failureMessage))
|
||||
|
||||
return writeElements(w,
|
||||
code,
|
||||
uint16(len(failureMessage)),
|
||||
failureMessage,
|
||||
uint16(len(pad)),
|
||||
pad,
|
||||
)
|
||||
}
|
||||
|
||||
// makeEmptyOnionError creates a new empty onion error of the proper concrete
|
||||
// type based on the passed failure code.
|
||||
func makeEmptyOnionError(code FailCode) (FailureMessage, error) {
|
||||
switch code {
|
||||
case CodeInvalidRealm:
|
||||
return &FailInvalidRealm{}, nil
|
||||
|
||||
case CodeTemporaryNodeFailure:
|
||||
return &FailTemporaryNodeFailure{}, nil
|
||||
|
||||
case CodePermanentNodeFailure:
|
||||
return &FailPermanentNodeFailure{}, nil
|
||||
|
||||
case CodeRequiredNodeFeatureMissing:
|
||||
return &FailRequiredNodeFeatureMissing{}, nil
|
||||
|
||||
case CodePermanentChannelFailure:
|
||||
return &FailPermanentChannelFailure{}, nil
|
||||
|
||||
case CodeRequiredChannelFeatureMissing:
|
||||
return &FailRequiredChannelFeatureMissing{}, nil
|
||||
|
||||
case CodeUnknownNextPeer:
|
||||
return &FailUnknownNextPeer{}, nil
|
||||
|
||||
case CodeUnknownPaymentHash:
|
||||
return &FailUnknownPaymentHash{}, nil
|
||||
|
||||
case CodeIncorrectPaymentAmount:
|
||||
return &FailIncorrectPaymentAmount{}, nil
|
||||
|
||||
case CodeFinalExpiryTooSoon:
|
||||
return &FailFinalExpiryTooSoon{}, nil
|
||||
|
||||
case CodeInvalidOnionVersion:
|
||||
return &FailInvalidOnionVersion{}, nil
|
||||
|
||||
case CodeInvalidOnionHmac:
|
||||
return &FailInvalidOnionHmac{}, nil
|
||||
|
||||
case CodeInvalidOnionKey:
|
||||
return &FailInvalidOnionKey{}, nil
|
||||
|
||||
case CodeTemporaryChannelFailure:
|
||||
return &FailTemporaryChannelFailure{}, nil
|
||||
|
||||
case CodeAmountBelowMinimum:
|
||||
return &FailAmountBelowMinimum{}, nil
|
||||
|
||||
case CodeFeeInsufficient:
|
||||
return &FailFeeInsufficient{}, nil
|
||||
|
||||
case CodeIncorrectCltvExpiry:
|
||||
return &FailIncorrectCltvExpiry{}, nil
|
||||
|
||||
case CodeExpiryTooSoon:
|
||||
return &FailExpiryTooSoon{}, nil
|
||||
|
||||
case CodeChannelDisabled:
|
||||
return &FailChannelDisabled{}, nil
|
||||
|
||||
case CodeFinalIncorrectCltvExpiry:
|
||||
return &FailFinalIncorrectCltvExpiry{}, nil
|
||||
|
||||
case CodeFinalIncorrectHtlcAmount:
|
||||
return &FailFinalIncorrectHtlcAmount{}, nil
|
||||
default:
|
||||
return nil, errors.Errorf("unknown error code: %v", code)
|
||||
}
|
||||
}
|
72
lnwire/onion_error_test.go
Normal file
72
lnwire/onion_error_test.go
Normal file
@ -0,0 +1,72 @@
|
||||
package lnwire
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/roasbeef/btcutil"
|
||||
)
|
||||
|
||||
var (
|
||||
testOnionHash = []byte{}
|
||||
testAmount = btcutil.Amount(1)
|
||||
testCtlvExpiry = uint32(2)
|
||||
testFlags = uint16(2)
|
||||
testChannelUpdate = ChannelUpdate{
|
||||
Signature: testSig,
|
||||
ShortChannelID: NewShortChanIDFromInt(1),
|
||||
Timestamp: 1,
|
||||
Flags: 1,
|
||||
}
|
||||
)
|
||||
|
||||
var onionFailures = []FailureMessage{
|
||||
&FailInvalidRealm{},
|
||||
&FailTemporaryNodeFailure{},
|
||||
&FailPermanentNodeFailure{},
|
||||
&FailRequiredNodeFeatureMissing{},
|
||||
&FailPermanentChannelFailure{},
|
||||
&FailRequiredChannelFeatureMissing{},
|
||||
&FailUnknownNextPeer{},
|
||||
&FailUnknownPaymentHash{},
|
||||
&FailIncorrectPaymentAmount{},
|
||||
&FailFinalExpiryTooSoon{},
|
||||
|
||||
NewInvalidOnionVersion(testOnionHash),
|
||||
NewInvalidOnionHmac(testOnionHash),
|
||||
NewInvalidOnionKey(testOnionHash),
|
||||
NewTemporaryChannelFailure(&testChannelUpdate),
|
||||
NewTemporaryChannelFailure(nil),
|
||||
NewAmountBelowMinimum(testAmount, testChannelUpdate),
|
||||
NewFeeInsufficient(testAmount, testChannelUpdate),
|
||||
NewIncorrectCltvExpiry(testCtlvExpiry, testChannelUpdate),
|
||||
NewExpiryTooSoon(testChannelUpdate),
|
||||
NewChannelDisabled(testFlags, testChannelUpdate),
|
||||
NewFinalIncorrectCltvExpiry(testCtlvExpiry),
|
||||
NewFinalIncorrectHtlcAmount(testAmount),
|
||||
}
|
||||
|
||||
// TestEncodeDecodeCode tests the ability of onion errors to be properly encoded
|
||||
// and decoded.
|
||||
func TestEncodeDecodeCode(t *testing.T) {
|
||||
for _, failure1 := range onionFailures {
|
||||
var b bytes.Buffer
|
||||
|
||||
if err := EncodeFailure(&b, failure1, 0); err != nil {
|
||||
t.Fatalf("unable to encode failure code(%v): %v",
|
||||
failure1.Code(), err)
|
||||
}
|
||||
|
||||
failure2, err := DecodeFailure(&b, 0)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to decode failure code(%v): %v",
|
||||
failure1.Code(), err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(failure1, failure2) {
|
||||
t.Fatalf("failure message are different, failure "+
|
||||
"code(%v)", failure1.Code())
|
||||
}
|
||||
}
|
||||
}
|
@ -1,102 +1,19 @@
|
||||
package lnwire
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
)
|
||||
|
||||
// FailCode specifies the precise reason that an upstream HTLC was cancelled.
|
||||
// Each UpdateFailHTLC message carries a FailCode which is to be passed back
|
||||
// unaltered to the source of the HTLC within the route.
|
||||
//
|
||||
// TODO(roasbeef): implement proper encrypted error messages as defined in spec
|
||||
// * these errors as it stands reveal the error cause to all links in the
|
||||
// route and are horrible for privacy
|
||||
type FailCode uint16
|
||||
|
||||
const (
|
||||
// InsufficientCapacity indicates that a payment failed due to a link
|
||||
// in the ultimate route not having enough satoshi flow to successfully
|
||||
// carry the payment.
|
||||
InsufficientCapacity FailCode = 0
|
||||
|
||||
// UpstreamTimeout indicates that an upstream link had to enforce the
|
||||
// absolute HTLC timeout, removing the HTLC.
|
||||
UpstreamTimeout FailCode = 1
|
||||
|
||||
// UnknownPaymentHash indicates that the destination did not recognize
|
||||
// the payment hash.
|
||||
UnknownPaymentHash FailCode = 2
|
||||
|
||||
// UnknownDestination indicates that the specified next hop within the
|
||||
// Sphinx packet at a point in the route contained an unknown or
|
||||
// invalid "next hop".
|
||||
UnknownDestination FailCode = 3
|
||||
|
||||
// SphinxParseError indicates that an intermediate node was unable
|
||||
// properly parse the HTLC.
|
||||
SphinxParseError FailCode = 4
|
||||
|
||||
// IncorrectValue indicates that the HTLC ultimately extended to the
|
||||
// destination did not match the value that was expected.
|
||||
IncorrectValue FailCode = 5
|
||||
|
||||
// UnknownError indicates the error which should be returned, but
|
||||
// not exist in specification yet.
|
||||
UnknownError FailCode = 6
|
||||
)
|
||||
|
||||
// String returns a human-readable version of the FailCode type.
|
||||
func (c FailCode) String() string {
|
||||
switch c {
|
||||
case InsufficientCapacity:
|
||||
return "InsufficientCapacity: next hop had insufficient " +
|
||||
"capacity for payment"
|
||||
|
||||
case UpstreamTimeout:
|
||||
return "UpstreamTimeout: HTLC has timed out upstream"
|
||||
|
||||
case UnknownPaymentHash:
|
||||
return "UnknownPaymentHash: the destination did not know the " +
|
||||
"preimage"
|
||||
|
||||
case UnknownDestination:
|
||||
return "UnknownDestination: next hop unknown"
|
||||
|
||||
case SphinxParseError:
|
||||
return "SphinxParseError: unable to parse sphinx packet"
|
||||
|
||||
case IncorrectValue:
|
||||
return "IncorrectValue: htlc value was wrong"
|
||||
|
||||
default:
|
||||
return "unknown reason"
|
||||
}
|
||||
}
|
||||
import "io"
|
||||
|
||||
// OpaqueReason is an opaque encrypted byte slice that encodes the exact
|
||||
// failure reason and additional some supplemental data. The contents of this
|
||||
// slice can only be decrypted by the sender of the original HTLC.
|
||||
type OpaqueReason []byte
|
||||
|
||||
// ToFailCode converts the reason in fail code.
|
||||
// TODO(andrew.shvv) Future version of this method should implement
|
||||
// decryption opaque reason logic.
|
||||
func (r OpaqueReason) ToFailCode() (FailCode, error) {
|
||||
if len(r) != 1 {
|
||||
return 0, errors.New("wrong opaque code length")
|
||||
}
|
||||
|
||||
return FailCode(r[0]), nil
|
||||
}
|
||||
|
||||
// UpdateFailHTLC is sent by Alice to Bob in order to remove a previously added
|
||||
// HTLC. Upon receipt of an UpdateFailHTLC the HTLC should be removed from the
|
||||
// next commitment transaction, with the UpdateFailHTLC propagated backwards in
|
||||
// the route to fully undo the HTLC.
|
||||
type UpdateFailHTLC struct {
|
||||
// ChannelPoint is the particular active channel that this
|
||||
// UpdateFailHTLC is bound to.
|
||||
// ChanIDPoint is the particular active channel that this UpdateFailHTLC
|
||||
// is bound to.
|
||||
ChanID ChannelID
|
||||
|
||||
// ID references which HTLC on the remote node's commitment transaction
|
||||
@ -106,7 +23,6 @@ type UpdateFailHTLC struct {
|
||||
// Reason is an onion-encrypted blob that details why the HTLC was
|
||||
// failed. This blob is only fully decryptable by the initiator of the
|
||||
// HTLC message.
|
||||
// TODO(roasbeef): properly format the encrypted failure reason
|
||||
Reason OpaqueReason
|
||||
}
|
||||
|
||||
@ -151,6 +67,19 @@ func (c *UpdateFailHTLC) MsgType() MessageType {
|
||||
//
|
||||
// This is part of the lnwire.Message interface.
|
||||
func (c *UpdateFailHTLC) MaxPayloadLength(uint32) uint32 {
|
||||
// 32 + 8 + 154
|
||||
return 194
|
||||
var length uint32
|
||||
|
||||
// Length of the ChanID
|
||||
length += 32
|
||||
|
||||
// Length of the ID
|
||||
length += 8
|
||||
|
||||
// Length of the length opaque reason
|
||||
length += 2
|
||||
|
||||
// Length of the Reason
|
||||
length += 166
|
||||
|
||||
return length
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user