Merge pull request #3188 from joostjager/error-source-idx
htlcswitch+routing+routerrpc: error source as index and expose decrypt failure
This commit is contained in:
commit
a4f4ff0f83
2
go.mod
2
go.mod
@ -30,7 +30,7 @@ require (
|
||||
github.com/juju/version v0.0.0-20180108022336-b64dbd566305 // indirect
|
||||
github.com/kkdai/bstream v0.0.0-20181106074824-b3251f7901ec
|
||||
github.com/lightninglabs/neutrino v0.0.0-20190629001446-52dd89dd1aaa
|
||||
github.com/lightningnetwork/lightning-onion v0.0.0-20190430041606-751fb4dd8b72
|
||||
github.com/lightningnetwork/lightning-onion v0.0.0-20190703000913-ecc936dc56c9
|
||||
github.com/lightningnetwork/lnd/queue v1.0.1
|
||||
github.com/lightningnetwork/lnd/ticker v1.0.0
|
||||
github.com/ltcsuite/ltcd v0.0.0-20190101042124-f37f8bf35796
|
||||
|
4
go.sum
4
go.sum
@ -137,8 +137,8 @@ github.com/lightninglabs/neutrino v0.0.0-20190313035638-e1ad4c33fb18 h1:lxD7RgKY
|
||||
github.com/lightninglabs/neutrino v0.0.0-20190313035638-e1ad4c33fb18/go.mod h1:v6tz6jbuAubTrRpX8ke2KH9sJxml8KlPQTKgo9mAp1Q=
|
||||
github.com/lightninglabs/neutrino v0.0.0-20190629001446-52dd89dd1aaa h1:vLsdHrqHKNDShoSRkrFEM0FsNt5waIKS87IgP1YLz+g=
|
||||
github.com/lightninglabs/neutrino v0.0.0-20190629001446-52dd89dd1aaa/go.mod h1:vzLU75ll8qbRJIzW5dvK/UXtR9c2FecJ6VNOM8chyVM=
|
||||
github.com/lightningnetwork/lightning-onion v0.0.0-20190430041606-751fb4dd8b72 h1:KgmypyQfJnEf2vhwboKCtTp4mHxIcLeXPBPWDbPuzFQ=
|
||||
github.com/lightningnetwork/lightning-onion v0.0.0-20190430041606-751fb4dd8b72/go.mod h1:Sooe/CoCqa85JxqHV+IBR2HW+6t2Cv+36awSmoccswM=
|
||||
github.com/lightningnetwork/lightning-onion v0.0.0-20190703000913-ecc936dc56c9 h1:u6dbtgPtilk/HWg9GwA8GniHqzCW/7an3ZSpZARfHx4=
|
||||
github.com/lightningnetwork/lightning-onion v0.0.0-20190703000913-ecc936dc56c9/go.mod h1:Sooe/CoCqa85JxqHV+IBR2HW+6t2Cv+36awSmoccswM=
|
||||
github.com/ltcsuite/ltcd v0.0.0-20190101042124-f37f8bf35796 h1:sjOGyegMIhvgfq5oaue6Td+hxZuf3tDC8lAPrFldqFw=
|
||||
github.com/ltcsuite/ltcd v0.0.0-20190101042124-f37f8bf35796/go.mod h1:3p7ZTf9V1sNPI5H8P3NkTFF4LuwMdPl2DodF60qAKqY=
|
||||
github.com/ltcsuite/ltcutil v0.0.0-20181217130922-17f3b04680b6/go.mod h1:8Vg/LTOO0KYa/vlHWJ6XZAevPQThGH5sufO0Hrou/lA=
|
||||
|
@ -6,17 +6,18 @@ import (
|
||||
"io"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec"
|
||||
"github.com/lightningnetwork/lightning-onion"
|
||||
sphinx "github.com/lightningnetwork/lightning-onion"
|
||||
"github.com/lightningnetwork/lnd/lnwire"
|
||||
)
|
||||
|
||||
// ForwardingError wraps an lnwire.FailureMessage in a struct that also
|
||||
// includes the source of the error.
|
||||
type ForwardingError struct {
|
||||
// ErrorSource is the public key of the node that sent the error. With
|
||||
// this information, the dispatcher of a payment can modify their set
|
||||
// of candidate routes in response to the type of error extracted.
|
||||
ErrorSource *btcec.PublicKey
|
||||
// FailureSourceIdx is the index of the node that sent the failure. With
|
||||
// this information, the dispatcher of a payment can modify their set of
|
||||
// candidate routes in response to the type of failure extracted. Index
|
||||
// zero is the self node.
|
||||
FailureSourceIdx int
|
||||
|
||||
// ExtraMsg is an additional error message that callers can provide in
|
||||
// order to provide context specific error details.
|
||||
@ -30,10 +31,10 @@ type ForwardingError struct {
|
||||
// returned.
|
||||
func (f *ForwardingError) Error() string {
|
||||
if f.ExtraMsg == "" {
|
||||
return f.FailureMessage.Error()
|
||||
return fmt.Sprintf("%v", f.FailureMessage)
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%v: %v", f.FailureMessage.Error(), f.ExtraMsg)
|
||||
return fmt.Sprintf("%v: %v", f.FailureMessage, f.ExtraMsg)
|
||||
}
|
||||
|
||||
// ErrorDecrypter is an interface that is used to decrypt the onion encrypted
|
||||
@ -243,10 +244,21 @@ func (s *SphinxErrorEncrypter) Reextract(
|
||||
// ErrorEncrypter interface.
|
||||
var _ ErrorEncrypter = (*SphinxErrorEncrypter)(nil)
|
||||
|
||||
// OnionErrorDecrypter is the interface that provides onion level error
|
||||
// decryption.
|
||||
type OnionErrorDecrypter interface {
|
||||
// DecryptError attempts to decrypt the passed encrypted error response.
|
||||
// The onion failure is encrypted in backward manner, starting from the
|
||||
// node where error have occurred. As a result, in order to decrypt the
|
||||
// error we need get all shared secret and apply decryption in the
|
||||
// reverse order.
|
||||
DecryptError(encryptedData []byte) (*sphinx.DecryptedError, error)
|
||||
}
|
||||
|
||||
// SphinxErrorDecrypter wraps the sphinx data SphinxErrorDecrypter and maps the
|
||||
// returned errors to concrete lnwire.FailureMessage instances.
|
||||
type SphinxErrorDecrypter struct {
|
||||
*sphinx.OnionErrorDecrypter
|
||||
OnionErrorDecrypter
|
||||
}
|
||||
|
||||
// DecryptError peels off each layer of onion encryption from the first hop, to
|
||||
@ -254,22 +266,27 @@ type SphinxErrorDecrypter struct {
|
||||
// along with the source of the error.
|
||||
//
|
||||
// NOTE: Part of the ErrorDecrypter interface.
|
||||
func (s *SphinxErrorDecrypter) DecryptError(reason lnwire.OpaqueReason) (*ForwardingError, error) {
|
||||
func (s *SphinxErrorDecrypter) DecryptError(reason lnwire.OpaqueReason) (
|
||||
*ForwardingError, error) {
|
||||
|
||||
source, failureData, err := s.OnionErrorDecrypter.DecryptError(reason)
|
||||
failure, err := s.OnionErrorDecrypter.DecryptError(reason)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
r := bytes.NewReader(failureData)
|
||||
// Decode the failure. If an error occurs, we leave the failure message
|
||||
// field nil.
|
||||
r := bytes.NewReader(failure.Message)
|
||||
failureMsg, err := lnwire.DecodeFailure(r, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return &ForwardingError{
|
||||
FailureSourceIdx: failure.SenderIdx,
|
||||
}, nil
|
||||
}
|
||||
|
||||
return &ForwardingError{
|
||||
ErrorSource: source,
|
||||
FailureMessage: failureMsg,
|
||||
FailureSourceIdx: failure.SenderIdx,
|
||||
FailureMessage: failureMsg,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
@ -1214,7 +1214,7 @@ func (l *channelLink) processHodlEvent(hodlEvent invoices.HodlEvent,
|
||||
)
|
||||
|
||||
case invoices.CancelExpiryTooSoon:
|
||||
failure = lnwire.FailFinalExpiryTooSoon{}
|
||||
failure = &lnwire.FailFinalExpiryTooSoon{}
|
||||
|
||||
default:
|
||||
return fmt.Errorf("unknown cancel reason: %v",
|
||||
|
@ -163,10 +163,7 @@ func initSwitchWithDB(startingHeight uint32, db *channeldb.DB) (*Switch, error)
|
||||
}
|
||||
}
|
||||
|
||||
priv, _ := btcec.NewPrivateKey(btcec.S256())
|
||||
pubkey := priv.PubKey()
|
||||
cfg := Config{
|
||||
SelfKey: pubkey,
|
||||
DB: db,
|
||||
SwitchPackager: channeldb.NewSwitchPackager(),
|
||||
FwdingLog: &mockForwardingLog{
|
||||
@ -393,12 +390,9 @@ func (o *mockDeobfuscator) DecryptError(reason lnwire.OpaqueReason) (*Forwarding
|
||||
return nil, err
|
||||
}
|
||||
|
||||
priv, _ := btcec.NewPrivateKey(btcec.S256())
|
||||
pubkey := priv.PubKey()
|
||||
|
||||
return &ForwardingError{
|
||||
ErrorSource: pubkey,
|
||||
FailureMessage: failure,
|
||||
FailureSourceIdx: 1,
|
||||
FailureMessage: failure,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@ -971,3 +965,18 @@ func (m *mockCircuitMap) NumPending() int {
|
||||
func (m *mockCircuitMap) NumOpen() int {
|
||||
return 0
|
||||
}
|
||||
|
||||
type mockOnionErrorDecryptor struct {
|
||||
sourceIdx int
|
||||
message []byte
|
||||
err error
|
||||
}
|
||||
|
||||
func (m *mockOnionErrorDecryptor) DecryptError(encryptedData []byte) (
|
||||
*sphinx.DecryptedError, error) {
|
||||
|
||||
return &sphinx.DecryptedError{
|
||||
SenderIdx: m.sourceIdx,
|
||||
Message: m.message,
|
||||
}, m.err
|
||||
}
|
||||
|
@ -9,7 +9,6 @@ import (
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/btcsuite/btcutil"
|
||||
"github.com/coreos/bbolt"
|
||||
@ -59,6 +58,10 @@ var (
|
||||
// active links in the switch for a specific destination.
|
||||
ErrNoLinksFound = errors.New("no channel links found")
|
||||
|
||||
// ErrUnreadableFailureMessage is returned when the failure message
|
||||
// cannot be decrypted.
|
||||
ErrUnreadableFailureMessage = errors.New("unreadable failure message")
|
||||
|
||||
// zeroPreimage is the empty preimage which is returned when we have
|
||||
// some errors.
|
||||
zeroPreimage [sha256.Size]byte
|
||||
@ -112,11 +115,6 @@ type ChanClose struct {
|
||||
// Config defines the configuration for the service. ALL elements within the
|
||||
// configuration MUST be non-nil for the service to carry out its duties.
|
||||
type Config struct {
|
||||
// SelfKey is the key of the backing Lightning node. This key is used
|
||||
// to properly craft failure messages, such that the Layer 3 router can
|
||||
// properly route around link./vertex failures.
|
||||
SelfKey *btcec.PublicKey
|
||||
|
||||
// FwdingLog is an interface that will be used by the switch to log
|
||||
// forwarding events. A forwarding event happens each time a payment
|
||||
// circuit is successfully completed. So when we forward an HTLC, and a
|
||||
@ -776,8 +774,8 @@ func (s *Switch) handleLocalDispatch(pkt *htlcPacket) error {
|
||||
if err != nil {
|
||||
log.Errorf("Link %v not found", pkt.outgoingChanID)
|
||||
return &ForwardingError{
|
||||
ErrorSource: s.cfg.SelfKey,
|
||||
FailureMessage: &lnwire.FailUnknownNextPeer{},
|
||||
FailureSourceIdx: 0,
|
||||
FailureMessage: &lnwire.FailUnknownNextPeer{},
|
||||
}
|
||||
}
|
||||
|
||||
@ -790,9 +788,9 @@ func (s *Switch) handleLocalDispatch(pkt *htlcPacket) error {
|
||||
// will be returned back to the router.
|
||||
htlcErr := lnwire.NewTemporaryChannelFailure(nil)
|
||||
return &ForwardingError{
|
||||
ErrorSource: s.cfg.SelfKey,
|
||||
ExtraMsg: err.Error(),
|
||||
FailureMessage: htlcErr,
|
||||
FailureSourceIdx: 0,
|
||||
ExtraMsg: err.Error(),
|
||||
FailureMessage: htlcErr,
|
||||
}
|
||||
}
|
||||
|
||||
@ -808,8 +806,8 @@ func (s *Switch) handleLocalDispatch(pkt *htlcPacket) error {
|
||||
"satisfied", pkt.outgoingChanID)
|
||||
|
||||
return &ForwardingError{
|
||||
ErrorSource: s.cfg.SelfKey,
|
||||
FailureMessage: htlcErr,
|
||||
FailureSourceIdx: 0,
|
||||
FailureMessage: htlcErr,
|
||||
}
|
||||
}
|
||||
|
||||
@ -823,9 +821,9 @@ func (s *Switch) handleLocalDispatch(pkt *htlcPacket) error {
|
||||
// will be returned back to the router.
|
||||
htlcErr := lnwire.NewTemporaryChannelFailure(nil)
|
||||
return &ForwardingError{
|
||||
ErrorSource: s.cfg.SelfKey,
|
||||
ExtraMsg: err.Error(),
|
||||
FailureMessage: htlcErr,
|
||||
FailureSourceIdx: 0,
|
||||
ExtraMsg: err.Error(),
|
||||
FailureMessage: htlcErr,
|
||||
}
|
||||
}
|
||||
|
||||
@ -942,9 +940,7 @@ func (s *Switch) extractResult(deobfuscator ErrorDecrypter, n *networkResult,
|
||||
// the payment deobfuscator.
|
||||
func (s *Switch) parseFailedPayment(deobfuscator ErrorDecrypter,
|
||||
paymentID uint64, paymentHash lntypes.Hash, unencrypted,
|
||||
isResolution bool, htlc *lnwire.UpdateFailHTLC) *ForwardingError {
|
||||
|
||||
var failure *ForwardingError
|
||||
isResolution bool, htlc *lnwire.UpdateFailHTLC) error {
|
||||
|
||||
switch {
|
||||
|
||||
@ -966,10 +962,11 @@ func (s *Switch) parseFailedPayment(deobfuscator ErrorDecrypter,
|
||||
// router.
|
||||
failureMsg = lnwire.NewTemporaryChannelFailure(nil)
|
||||
}
|
||||
failure = &ForwardingError{
|
||||
ErrorSource: s.cfg.SelfKey,
|
||||
ExtraMsg: userErr,
|
||||
FailureMessage: failureMsg,
|
||||
|
||||
return &ForwardingError{
|
||||
FailureSourceIdx: 0,
|
||||
ExtraMsg: userErr,
|
||||
FailureMessage: failureMsg,
|
||||
}
|
||||
|
||||
// A payment had to be timed out on chain before it got past
|
||||
@ -980,33 +977,29 @@ func (s *Switch) parseFailedPayment(deobfuscator ErrorDecrypter,
|
||||
userErr := fmt.Sprintf("payment was resolved "+
|
||||
"on-chain, then cancelled back (hash=%v, pid=%d)",
|
||||
paymentHash, paymentID)
|
||||
failure = &ForwardingError{
|
||||
ErrorSource: s.cfg.SelfKey,
|
||||
ExtraMsg: userErr,
|
||||
FailureMessage: lnwire.FailPermanentChannelFailure{},
|
||||
|
||||
return &ForwardingError{
|
||||
FailureSourceIdx: 0,
|
||||
ExtraMsg: userErr,
|
||||
FailureMessage: &lnwire.FailPermanentChannelFailure{},
|
||||
}
|
||||
|
||||
// A regular multi-hop payment error that we'll need to
|
||||
// decrypt.
|
||||
default:
|
||||
var err error
|
||||
// We'll attempt to fully decrypt the onion encrypted
|
||||
// error. If we're unable to then we'll bail early.
|
||||
failure, err = deobfuscator.DecryptError(htlc.Reason)
|
||||
failure, err := deobfuscator.DecryptError(htlc.Reason)
|
||||
if err != nil {
|
||||
userErr := fmt.Sprintf("unable to de-obfuscate "+
|
||||
"onion failure (hash=%v, pid=%d): %v",
|
||||
log.Errorf("unable to de-obfuscate onion failure "+
|
||||
"(hash=%v, pid=%d): %v",
|
||||
paymentHash, paymentID, err)
|
||||
log.Error(userErr)
|
||||
failure = &ForwardingError{
|
||||
ErrorSource: s.cfg.SelfKey,
|
||||
ExtraMsg: userErr,
|
||||
FailureMessage: lnwire.NewTemporaryChannelFailure(nil),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return failure
|
||||
return ErrUnreadableFailureMessage
|
||||
}
|
||||
|
||||
return failure
|
||||
}
|
||||
}
|
||||
|
||||
// handlePacketForward is used in cases when we need forward the htlc update
|
||||
|
@ -6,7 +6,6 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@ -1825,9 +1824,13 @@ func TestSwitchSendPayment(t *testing.T) {
|
||||
|
||||
select {
|
||||
case err := <-errChan:
|
||||
if !strings.Contains(err.Error(), lnwire.CodeUnknownPaymentHash.String()) {
|
||||
t.Fatalf("expected %v got %v", err,
|
||||
lnwire.CodeUnknownPaymentHash)
|
||||
fErr, ok := err.(*ForwardingError)
|
||||
if !ok {
|
||||
t.Fatal("expected ForwardingError")
|
||||
}
|
||||
|
||||
if _, ok := fErr.FailureMessage.(*lnwire.FailUnknownPaymentHash); !ok {
|
||||
t.Fatalf("expected UnknownPaymentHash got %v", fErr)
|
||||
}
|
||||
case <-time.After(time.Second):
|
||||
t.Fatal("err wasn't received")
|
||||
@ -2238,3 +2241,140 @@ func TestSwitchGetPaymentResult(t *testing.T) {
|
||||
t.Fatalf("result not received")
|
||||
}
|
||||
}
|
||||
|
||||
// TestInvalidFailure tests that the switch returns an unreadable failure error
|
||||
// if the failure cannot be decrypted.
|
||||
func TestInvalidFailure(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
alicePeer, err := newMockServer(t, "alice", testStartingHeight, nil, 6)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create alice server: %v", err)
|
||||
}
|
||||
|
||||
s, err := initSwitchWithDB(testStartingHeight, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to init switch: %v", err)
|
||||
}
|
||||
if err := s.Start(); err != nil {
|
||||
t.Fatalf("unable to start switch: %v", err)
|
||||
}
|
||||
defer s.Stop()
|
||||
|
||||
chanID1, _, aliceChanID, _ := genIDs()
|
||||
|
||||
// Set up a mock channel link.
|
||||
aliceChannelLink := newMockChannelLink(
|
||||
s, chanID1, aliceChanID, alicePeer, true,
|
||||
)
|
||||
if err := s.AddLink(aliceChannelLink); err != nil {
|
||||
t.Fatalf("unable to add link: %v", err)
|
||||
}
|
||||
|
||||
// Create a request which should be forwarded to the mock channel link.
|
||||
preimage, err := genPreimage()
|
||||
if err != nil {
|
||||
t.Fatalf("unable to generate preimage: %v", err)
|
||||
}
|
||||
rhash := fastsha256.Sum256(preimage[:])
|
||||
update := &lnwire.UpdateAddHTLC{
|
||||
PaymentHash: rhash,
|
||||
Amount: 1,
|
||||
}
|
||||
|
||||
paymentID := uint64(123)
|
||||
|
||||
// Send the request.
|
||||
err = s.SendHTLC(
|
||||
aliceChannelLink.ShortChanID(), paymentID, update,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to send payment: %v", err)
|
||||
}
|
||||
|
||||
// Catch the packet and complete the circuit so that the switch is ready
|
||||
// for a response.
|
||||
select {
|
||||
case packet := <-aliceChannelLink.packets:
|
||||
if err := aliceChannelLink.completeCircuit(packet); err != nil {
|
||||
t.Fatalf("unable to complete payment circuit: %v", err)
|
||||
}
|
||||
|
||||
case <-time.After(time.Second):
|
||||
t.Fatal("request was not propagated to destination")
|
||||
}
|
||||
|
||||
// Send response packet with an unreadable failure message to the
|
||||
// switch. The reason failed is not relevant, because we mock the
|
||||
// decryption.
|
||||
packet := &htlcPacket{
|
||||
outgoingChanID: aliceChannelLink.ShortChanID(),
|
||||
outgoingHTLCID: 0,
|
||||
amount: 1,
|
||||
htlc: &lnwire.UpdateFailHTLC{
|
||||
Reason: []byte{1, 2, 3},
|
||||
},
|
||||
}
|
||||
|
||||
if err := s.forward(packet); err != nil {
|
||||
t.Fatalf("can't forward htlc packet: %v", err)
|
||||
}
|
||||
|
||||
// Get payment result from switch. We expect an unreadable failure
|
||||
// message error.
|
||||
deobfuscator := SphinxErrorDecrypter{
|
||||
OnionErrorDecrypter: &mockOnionErrorDecryptor{
|
||||
err: ErrUnreadableFailureMessage,
|
||||
},
|
||||
}
|
||||
|
||||
resultChan, err := s.GetPaymentResult(
|
||||
paymentID, rhash, &deobfuscator,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
select {
|
||||
case result := <-resultChan:
|
||||
if result.Error != ErrUnreadableFailureMessage {
|
||||
t.Fatal("expected unreadable failure message")
|
||||
}
|
||||
|
||||
case <-time.After(time.Second):
|
||||
t.Fatal("err wasn't received")
|
||||
}
|
||||
|
||||
// Modify the decryption to simulate that decryption went alright, but
|
||||
// the failure cannot be decoded.
|
||||
deobfuscator = SphinxErrorDecrypter{
|
||||
OnionErrorDecrypter: &mockOnionErrorDecryptor{
|
||||
sourceIdx: 2,
|
||||
message: []byte{200},
|
||||
},
|
||||
}
|
||||
|
||||
resultChan, err = s.GetPaymentResult(
|
||||
paymentID, rhash, &deobfuscator,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
select {
|
||||
case result := <-resultChan:
|
||||
fErr, ok := result.Error.(*ForwardingError)
|
||||
if !ok {
|
||||
t.Fatal("expected ForwardingError")
|
||||
}
|
||||
if fErr.FailureSourceIdx != 2 {
|
||||
t.Fatal("unexpected error source index")
|
||||
}
|
||||
if fErr.FailureMessage != nil {
|
||||
t.Fatal("expected empty failure message")
|
||||
}
|
||||
|
||||
case <-time.After(time.Second):
|
||||
t.Fatal("err wasn't received")
|
||||
}
|
||||
}
|
||||
|
@ -103,31 +103,40 @@ const (
|
||||
Failure_TEMPORARY_NODE_FAILURE Failure_FailureCode = 19
|
||||
Failure_PERMANENT_NODE_FAILURE Failure_FailureCode = 20
|
||||
Failure_PERMANENT_CHANNEL_FAILURE Failure_FailureCode = 21
|
||||
//*
|
||||
//The error source is known, but the failure itself couldn't be decoded.
|
||||
Failure_UNKNOWN_FAILURE Failure_FailureCode = 998
|
||||
//*
|
||||
//An unreadable failure result is returned if the received failure message
|
||||
//cannot be decrypted. In that case the error source is unknown.
|
||||
Failure_UNREADABLE_FAILURE Failure_FailureCode = 999
|
||||
)
|
||||
|
||||
var Failure_FailureCode_name = map[int32]string{
|
||||
0: "RESERVED",
|
||||
1: "UNKNOWN_PAYMENT_HASH",
|
||||
2: "INCORRECT_PAYMENT_AMOUNT",
|
||||
3: "FINAL_INCORRECT_CLTV_EXPIRY",
|
||||
4: "FINAL_INCORRECT_HTLC_AMOUNT",
|
||||
5: "FINAL_EXPIRY_TOO_SOON",
|
||||
6: "INVALID_REALM",
|
||||
7: "EXPIRY_TOO_SOON",
|
||||
8: "INVALID_ONION_VERSION",
|
||||
9: "INVALID_ONION_HMAC",
|
||||
10: "INVALID_ONION_KEY",
|
||||
11: "AMOUNT_BELOW_MINIMUM",
|
||||
12: "FEE_INSUFFICIENT",
|
||||
13: "INCORRECT_CLTV_EXPIRY",
|
||||
14: "CHANNEL_DISABLED",
|
||||
15: "TEMPORARY_CHANNEL_FAILURE",
|
||||
16: "REQUIRED_NODE_FEATURE_MISSING",
|
||||
17: "REQUIRED_CHANNEL_FEATURE_MISSING",
|
||||
18: "UNKNOWN_NEXT_PEER",
|
||||
19: "TEMPORARY_NODE_FAILURE",
|
||||
20: "PERMANENT_NODE_FAILURE",
|
||||
21: "PERMANENT_CHANNEL_FAILURE",
|
||||
0: "RESERVED",
|
||||
1: "UNKNOWN_PAYMENT_HASH",
|
||||
2: "INCORRECT_PAYMENT_AMOUNT",
|
||||
3: "FINAL_INCORRECT_CLTV_EXPIRY",
|
||||
4: "FINAL_INCORRECT_HTLC_AMOUNT",
|
||||
5: "FINAL_EXPIRY_TOO_SOON",
|
||||
6: "INVALID_REALM",
|
||||
7: "EXPIRY_TOO_SOON",
|
||||
8: "INVALID_ONION_VERSION",
|
||||
9: "INVALID_ONION_HMAC",
|
||||
10: "INVALID_ONION_KEY",
|
||||
11: "AMOUNT_BELOW_MINIMUM",
|
||||
12: "FEE_INSUFFICIENT",
|
||||
13: "INCORRECT_CLTV_EXPIRY",
|
||||
14: "CHANNEL_DISABLED",
|
||||
15: "TEMPORARY_CHANNEL_FAILURE",
|
||||
16: "REQUIRED_NODE_FEATURE_MISSING",
|
||||
17: "REQUIRED_CHANNEL_FEATURE_MISSING",
|
||||
18: "UNKNOWN_NEXT_PEER",
|
||||
19: "TEMPORARY_NODE_FAILURE",
|
||||
20: "PERMANENT_NODE_FAILURE",
|
||||
21: "PERMANENT_CHANNEL_FAILURE",
|
||||
998: "UNKNOWN_FAILURE",
|
||||
999: "UNREADABLE_FAILURE",
|
||||
}
|
||||
|
||||
var Failure_FailureCode_value = map[string]int32{
|
||||
@ -153,6 +162,8 @@ var Failure_FailureCode_value = map[string]int32{
|
||||
"TEMPORARY_NODE_FAILURE": 19,
|
||||
"PERMANENT_NODE_FAILURE": 20,
|
||||
"PERMANENT_CHANNEL_FAILURE": 21,
|
||||
"UNKNOWN_FAILURE": 998,
|
||||
"UNREADABLE_FAILURE": 999,
|
||||
}
|
||||
|
||||
func (x Failure_FailureCode) String() string {
|
||||
@ -610,10 +621,6 @@ func (m *SendToRouteResponse) GetFailure() *Failure {
|
||||
type Failure struct {
|
||||
/// Failure code as defined in the Lightning spec
|
||||
Code Failure_FailureCode `protobuf:"varint,1,opt,name=code,proto3,enum=routerrpc.Failure_FailureCode" json:"code,omitempty"`
|
||||
//*
|
||||
//The node pubkey of the intermediate or final node that generated the failure
|
||||
//message.
|
||||
FailureSourcePubkey []byte `protobuf:"bytes,2,opt,name=failure_source_pubkey,json=failureSourcePubkey,proto3" json:"failure_source_pubkey,omitempty"`
|
||||
/// An optional channel update message.
|
||||
ChannelUpdate *ChannelUpdate `protobuf:"bytes,3,opt,name=channel_update,json=channelUpdate,proto3" json:"channel_update,omitempty"`
|
||||
/// A failure type-dependent htlc value.
|
||||
@ -623,7 +630,11 @@ type Failure struct {
|
||||
/// A failure type-dependent cltv expiry value.
|
||||
CltvExpiry uint32 `protobuf:"varint,6,opt,name=cltv_expiry,json=cltvExpiry,proto3" json:"cltv_expiry,omitempty"`
|
||||
/// A failure type-dependent flags value.
|
||||
Flags uint32 `protobuf:"varint,7,opt,name=flags,proto3" json:"flags,omitempty"`
|
||||
Flags uint32 `protobuf:"varint,7,opt,name=flags,proto3" json:"flags,omitempty"`
|
||||
//*
|
||||
//The position in the path of the intermediate or final node that generated
|
||||
//the failure message. Position zero is the sender node.
|
||||
FailureSourceIndex uint32 `protobuf:"varint,8,opt,name=failure_source_index,json=failureSourceIndex,proto3" json:"failure_source_index,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
@ -661,13 +672,6 @@ func (m *Failure) GetCode() Failure_FailureCode {
|
||||
return Failure_RESERVED
|
||||
}
|
||||
|
||||
func (m *Failure) GetFailureSourcePubkey() []byte {
|
||||
if m != nil {
|
||||
return m.FailureSourcePubkey
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Failure) GetChannelUpdate() *ChannelUpdate {
|
||||
if m != nil {
|
||||
return m.ChannelUpdate
|
||||
@ -703,6 +707,13 @@ func (m *Failure) GetFlags() uint32 {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *Failure) GetFailureSourceIndex() uint32 {
|
||||
if m != nil {
|
||||
return m.FailureSourceIndex
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type ChannelUpdate struct {
|
||||
//*
|
||||
//The signature that validates the announced data and proves the ownership
|
||||
@ -1167,109 +1178,111 @@ func init() {
|
||||
func init() { proto.RegisterFile("routerrpc/router.proto", fileDescriptor_7a0613f69d37b0a5) }
|
||||
|
||||
var fileDescriptor_7a0613f69d37b0a5 = []byte{
|
||||
// 1623 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x57, 0xdd, 0x72, 0x1a, 0xc9,
|
||||
0x15, 0x5e, 0x04, 0x08, 0x71, 0xf8, 0x1b, 0xb5, 0x64, 0x79, 0x8c, 0x2c, 0xaf, 0x76, 0x92, 0x78,
|
||||
0x55, 0xae, 0x8d, 0x94, 0x90, 0xf2, 0xd6, 0x5e, 0x25, 0x85, 0xa1, 0x59, 0x26, 0x86, 0x19, 0x6d,
|
||||
0x03, 0xde, 0x75, 0x72, 0xd1, 0xd5, 0x82, 0x16, 0x4c, 0x09, 0x66, 0xd8, 0x99, 0x66, 0x63, 0xe5,
|
||||
0x22, 0x77, 0xc9, 0x5d, 0x9e, 0x25, 0x79, 0x82, 0xbc, 0x47, 0x5e, 0x25, 0x57, 0xa9, 0xee, 0x1e,
|
||||
0x60, 0x40, 0xc8, 0xeb, 0x2b, 0x31, 0xdf, 0xf9, 0xfa, 0x9c, 0xd3, 0xe7, 0xaf, 0x8f, 0xe0, 0x24,
|
||||
0x0c, 0x16, 0x82, 0x87, 0xe1, 0x7c, 0x78, 0xa5, 0x7f, 0x5d, 0xce, 0xc3, 0x40, 0x04, 0x28, 0xbf,
|
||||
0xc2, 0xab, 0xf9, 0x70, 0x3e, 0xd4, 0xa8, 0xf5, 0xbf, 0x3d, 0x40, 0x3d, 0xee, 0x8f, 0xae, 0xd9,
|
||||
0xfd, 0x8c, 0xfb, 0x82, 0xf0, 0x1f, 0x17, 0x3c, 0x12, 0x08, 0x41, 0x66, 0xc4, 0x23, 0x61, 0xa6,
|
||||
0xce, 0x53, 0x17, 0x45, 0xa2, 0x7e, 0x23, 0x03, 0xd2, 0x6c, 0x26, 0xcc, 0xbd, 0xf3, 0xd4, 0x45,
|
||||
0x9a, 0xc8, 0x9f, 0xe8, 0x0b, 0x28, 0xce, 0xf5, 0x39, 0x3a, 0x61, 0xd1, 0xc4, 0x4c, 0x2b, 0x76,
|
||||
0x21, 0xc6, 0xda, 0x2c, 0x9a, 0xa0, 0x0b, 0x30, 0x6e, 0x3d, 0x9f, 0x4d, 0xe9, 0x70, 0x2a, 0x7e,
|
||||
0xa2, 0x23, 0x3e, 0x15, 0xcc, 0xcc, 0x9c, 0xa7, 0x2e, 0xb2, 0xa4, 0xac, 0xf0, 0xc6, 0x54, 0xfc,
|
||||
0xd4, 0x94, 0x28, 0xfa, 0x12, 0x2a, 0x4b, 0x65, 0xa1, 0xf6, 0xc2, 0xcc, 0x9e, 0xa7, 0x2e, 0xf2,
|
||||
0xa4, 0x3c, 0xdf, 0xf4, 0xed, 0x4b, 0xa8, 0x08, 0x6f, 0xc6, 0x83, 0x85, 0xa0, 0x11, 0x1f, 0x06,
|
||||
0xfe, 0x28, 0x32, 0xf7, 0xb5, 0xc6, 0x18, 0xee, 0x69, 0x14, 0x59, 0x50, 0xba, 0xe5, 0x9c, 0x4e,
|
||||
0xbd, 0x99, 0x27, 0x68, 0xc4, 0x84, 0x99, 0x53, 0xae, 0x17, 0x6e, 0x39, 0xef, 0x48, 0xac, 0xc7,
|
||||
0x84, 0xf4, 0x2f, 0x58, 0x88, 0x71, 0xe0, 0xf9, 0x63, 0x3a, 0x9c, 0x30, 0x9f, 0x7a, 0x23, 0xf3,
|
||||
0xe0, 0x3c, 0x75, 0x91, 0x21, 0xe5, 0x25, 0xde, 0x98, 0x30, 0xdf, 0x1e, 0xa1, 0x33, 0x00, 0x75,
|
||||
0x07, 0xa5, 0xce, 0xcc, 0x2b, 0x8b, 0x79, 0x89, 0x28, 0x5d, 0xa8, 0x06, 0x05, 0x15, 0x60, 0x3a,
|
||||
0xf1, 0x7c, 0x11, 0x99, 0x70, 0x9e, 0xbe, 0x28, 0xd4, 0x8c, 0xcb, 0xa9, 0x2f, 0x63, 0x4d, 0xa4,
|
||||
0xa4, 0xed, 0xf9, 0x82, 0x24, 0x49, 0xd6, 0x37, 0x70, 0xd4, 0x0f, 0xd9, 0xf0, 0x6e, 0x2b, 0xf8,
|
||||
0xdb, 0x61, 0x4d, 0x3d, 0x08, 0xab, 0xf5, 0x37, 0x28, 0xc5, 0x87, 0x7a, 0x82, 0x89, 0x45, 0x84,
|
||||
0x7e, 0x0d, 0xd9, 0x48, 0x30, 0xc1, 0x15, 0xb9, 0x5c, 0x7b, 0x7a, 0xb9, 0xca, 0xf6, 0x65, 0x82,
|
||||
0xc8, 0x89, 0x66, 0xa1, 0x2a, 0x1c, 0xcc, 0x43, 0xee, 0xcd, 0xd8, 0x98, 0xab, 0x84, 0x16, 0xc9,
|
||||
0xea, 0x1b, 0x59, 0x90, 0x55, 0x87, 0x55, 0x3a, 0x0b, 0xb5, 0x62, 0xf2, 0x0e, 0x44, 0x8b, 0xac,
|
||||
0xdf, 0x43, 0x45, 0x7d, 0xb7, 0x38, 0xff, 0x58, 0xc9, 0x3c, 0x85, 0x1c, 0x9b, 0xe9, 0xd8, 0xeb,
|
||||
0xb2, 0xd9, 0x67, 0x33, 0x19, 0x76, 0x6b, 0x04, 0xc6, 0xfa, 0x7c, 0x34, 0x0f, 0xfc, 0x88, 0xcb,
|
||||
0x54, 0x48, 0xe5, 0x32, 0x13, 0x32, 0x6d, 0x33, 0x79, 0x2a, 0xa5, 0x4e, 0x95, 0x63, 0xbc, 0xc5,
|
||||
0x79, 0x37, 0x62, 0x02, 0xbd, 0xd4, 0x15, 0x40, 0xa7, 0xc1, 0xf0, 0x4e, 0xd6, 0x14, 0xbb, 0x8f,
|
||||
0xd5, 0x97, 0x24, 0xdc, 0x09, 0x86, 0x77, 0x4d, 0x09, 0x5a, 0x7f, 0xd6, 0xb5, 0xdd, 0x0f, 0xb4,
|
||||
0xef, 0x9f, 0x1c, 0xde, 0x75, 0x08, 0xf6, 0x1e, 0x0f, 0x01, 0x85, 0xa3, 0x0d, 0xe5, 0xf1, 0x2d,
|
||||
0x92, 0x91, 0x4d, 0x6d, 0x45, 0xf6, 0x2b, 0xc8, 0xdd, 0x32, 0x6f, 0xba, 0x08, 0x97, 0x8a, 0x51,
|
||||
0x22, 0x4d, 0x2d, 0x2d, 0x21, 0x4b, 0x8a, 0xf5, 0x8f, 0x1c, 0xe4, 0x62, 0x10, 0xd5, 0x20, 0x33,
|
||||
0x0c, 0x46, 0xcb, 0xec, 0xbe, 0x78, 0x78, 0x6c, 0xf9, 0xb7, 0x11, 0x8c, 0x38, 0x51, 0x5c, 0x54,
|
||||
0x83, 0x27, 0xb1, 0x2a, 0x1a, 0x05, 0x8b, 0x70, 0xc8, 0xe9, 0x7c, 0x71, 0x73, 0xc7, 0xef, 0xe3,
|
||||
0x84, 0x1f, 0xc5, 0xc2, 0x9e, 0x92, 0x5d, 0x2b, 0x11, 0xfa, 0x03, 0x94, 0x65, 0x17, 0xf8, 0x7c,
|
||||
0x4a, 0x17, 0xf3, 0x11, 0x5b, 0x15, 0x81, 0x99, 0xb0, 0xd8, 0xd0, 0x84, 0x81, 0x92, 0x93, 0xd2,
|
||||
0x30, 0xf9, 0x89, 0x4e, 0x21, 0x3f, 0x11, 0xd3, 0xa1, 0xce, 0x5e, 0x46, 0x35, 0xd2, 0x81, 0x04,
|
||||
0x54, 0xde, 0x2c, 0x28, 0x05, 0xbe, 0x17, 0xf8, 0x34, 0x9a, 0x30, 0x5a, 0x7b, 0xfd, 0xb5, 0x6a,
|
||||
0xf0, 0x22, 0x29, 0x28, 0xb0, 0x37, 0x61, 0xb5, 0xd7, 0x5f, 0xa3, 0xcf, 0xa1, 0xa0, 0xda, 0x8c,
|
||||
0x7f, 0x98, 0x7b, 0xe1, 0xbd, 0xea, 0xec, 0x12, 0x51, 0x9d, 0x87, 0x15, 0x82, 0x8e, 0x21, 0x7b,
|
||||
0x3b, 0x65, 0xe3, 0x48, 0x75, 0x73, 0x89, 0xe8, 0x0f, 0xeb, 0xbf, 0x19, 0x28, 0x24, 0x42, 0x80,
|
||||
0x8a, 0x70, 0x40, 0x70, 0x0f, 0x93, 0x77, 0xb8, 0x69, 0x7c, 0x86, 0x4c, 0x38, 0x1e, 0x38, 0x6f,
|
||||
0x1d, 0xf7, 0x7b, 0x87, 0x5e, 0xd7, 0xdf, 0x77, 0xb1, 0xd3, 0xa7, 0xed, 0x7a, 0xaf, 0x6d, 0xa4,
|
||||
0xd0, 0x73, 0x30, 0x6d, 0xa7, 0xe1, 0x12, 0x82, 0x1b, 0xfd, 0x95, 0xac, 0xde, 0x75, 0x07, 0x4e,
|
||||
0xdf, 0xd8, 0x43, 0x9f, 0xc3, 0x69, 0xcb, 0x76, 0xea, 0x1d, 0xba, 0xe6, 0x34, 0x3a, 0xfd, 0x77,
|
||||
0x14, 0xff, 0x70, 0x6d, 0x93, 0xf7, 0x46, 0x7a, 0x17, 0xa1, 0xdd, 0xef, 0x34, 0x96, 0x1a, 0x32,
|
||||
0xe8, 0x19, 0x3c, 0xd1, 0x04, 0x7d, 0x84, 0xf6, 0x5d, 0x97, 0xf6, 0x5c, 0xd7, 0x31, 0xb2, 0xe8,
|
||||
0x10, 0x4a, 0xb6, 0xf3, 0xae, 0xde, 0xb1, 0x9b, 0x94, 0xe0, 0x7a, 0xa7, 0x6b, 0xec, 0xa3, 0x23,
|
||||
0xa8, 0x6c, 0xf3, 0x72, 0x52, 0xc5, 0x92, 0xe7, 0x3a, 0xb6, 0xeb, 0xd0, 0x77, 0x98, 0xf4, 0x6c,
|
||||
0xd7, 0x31, 0x0e, 0xd0, 0x09, 0xa0, 0x4d, 0x51, 0xbb, 0x5b, 0x6f, 0x18, 0x79, 0xf4, 0x04, 0x0e,
|
||||
0x37, 0xf1, 0xb7, 0xf8, 0xbd, 0x01, 0x32, 0x0c, 0xda, 0x31, 0xfa, 0x06, 0x77, 0xdc, 0xef, 0x69,
|
||||
0xd7, 0x76, 0xec, 0xee, 0xa0, 0x6b, 0x14, 0xd0, 0x31, 0x18, 0x2d, 0x8c, 0xa9, 0xed, 0xf4, 0x06,
|
||||
0xad, 0x96, 0xdd, 0xb0, 0xb1, 0xd3, 0x37, 0x8a, 0xda, 0xf2, 0xae, 0x8b, 0x97, 0xe4, 0x81, 0x46,
|
||||
0xbb, 0xee, 0x38, 0xb8, 0x43, 0x9b, 0x76, 0xaf, 0xfe, 0xa6, 0x83, 0x9b, 0x46, 0x19, 0x9d, 0xc1,
|
||||
0xb3, 0x3e, 0xee, 0x5e, 0xbb, 0xa4, 0x4e, 0xde, 0xd3, 0xa5, 0xbc, 0x55, 0xb7, 0x3b, 0x03, 0x82,
|
||||
0x8d, 0x0a, 0xfa, 0x02, 0xce, 0x08, 0xfe, 0x6e, 0x60, 0x13, 0xdc, 0xa4, 0x8e, 0xdb, 0xc4, 0xb4,
|
||||
0x85, 0xeb, 0xfd, 0x01, 0xc1, 0xb4, 0x6b, 0xf7, 0x7a, 0xb6, 0xf3, 0xad, 0x61, 0xa0, 0x5f, 0xc2,
|
||||
0xf9, 0x8a, 0xb2, 0x52, 0xb0, 0xc5, 0x3a, 0x94, 0xf7, 0x5b, 0xe6, 0xd3, 0xc1, 0x3f, 0xf4, 0xe9,
|
||||
0x35, 0xc6, 0xc4, 0x40, 0xa8, 0x0a, 0x27, 0x6b, 0xf3, 0xda, 0x40, 0x6c, 0xfb, 0x48, 0xca, 0xae,
|
||||
0x31, 0xe9, 0xd6, 0x1d, 0x99, 0xe0, 0x0d, 0xd9, 0xb1, 0x74, 0x7b, 0x2d, 0xdb, 0x76, 0xfb, 0x89,
|
||||
0xf5, 0xaf, 0x34, 0x94, 0x36, 0x8a, 0x1e, 0x3d, 0x87, 0x7c, 0xe4, 0x8d, 0x7d, 0x26, 0x64, 0x2b,
|
||||
0xeb, 0x2e, 0x5f, 0x03, 0xea, 0xa5, 0x98, 0x30, 0xcf, 0xd7, 0xe3, 0x45, 0x77, 0x5b, 0x5e, 0x21,
|
||||
0x6a, 0xb8, 0x3c, 0x85, 0xdc, 0xf2, 0xa5, 0x49, 0xab, 0x06, 0xd9, 0x1f, 0xea, 0x17, 0xe6, 0x39,
|
||||
0xe4, 0xe5, 0xfc, 0x8a, 0x04, 0x9b, 0xcd, 0x55, 0xef, 0x94, 0xc8, 0x1a, 0x40, 0xbf, 0x80, 0xd2,
|
||||
0x8c, 0x47, 0x11, 0x1b, 0x73, 0xaa, 0xeb, 0x1f, 0x14, 0xa3, 0x18, 0x83, 0x2d, 0x89, 0x49, 0xd2,
|
||||
0xb2, 0x7f, 0x35, 0x29, 0xab, 0x49, 0x31, 0xa8, 0x49, 0xdb, 0xe3, 0x53, 0xb0, 0xb8, 0xcd, 0x92,
|
||||
0xe3, 0x53, 0x30, 0xf4, 0x0a, 0x0e, 0x75, 0x2f, 0x7b, 0xbe, 0x37, 0x5b, 0xcc, 0x74, 0x4f, 0xe7,
|
||||
0x94, 0xcb, 0x15, 0xd5, 0xd3, 0x1a, 0x57, 0xad, 0xfd, 0x0c, 0x0e, 0x6e, 0x58, 0xc4, 0xe5, 0xe4,
|
||||
0x56, 0xef, 0x67, 0x89, 0xe4, 0xe4, 0x77, 0x8b, 0x73, 0x29, 0x92, 0xf3, 0x3c, 0x94, 0xd3, 0x24,
|
||||
0xaf, 0x45, 0xb7, 0x9c, 0x13, 0x19, 0xc7, 0x95, 0x05, 0xf6, 0x61, 0x6d, 0xa1, 0x90, 0xb0, 0xa0,
|
||||
0x71, 0x65, 0xe1, 0x15, 0x1c, 0xf2, 0x0f, 0x22, 0x64, 0x34, 0x98, 0xb3, 0x1f, 0x17, 0x9c, 0x8e,
|
||||
0x98, 0x60, 0x66, 0x51, 0x05, 0xb7, 0xa2, 0x04, 0xae, 0xc2, 0x9b, 0x4c, 0x30, 0xeb, 0x39, 0x54,
|
||||
0x09, 0x8f, 0xb8, 0xe8, 0x7a, 0x51, 0xe4, 0x05, 0x7e, 0x23, 0xf0, 0x45, 0x18, 0x4c, 0xe3, 0x07,
|
||||
0xc0, 0x3a, 0x83, 0xd3, 0x9d, 0x52, 0x3d, 0xc1, 0xe5, 0xe1, 0xef, 0x16, 0x3c, 0xbc, 0xdf, 0x7d,
|
||||
0xf8, 0x2d, 0x9c, 0xee, 0x94, 0xc6, 0xe3, 0xff, 0x2b, 0xc8, 0xfa, 0xc1, 0x88, 0x47, 0x66, 0x4a,
|
||||
0x2d, 0x00, 0x27, 0x89, 0xb9, 0xe9, 0x04, 0x23, 0xde, 0xf6, 0x22, 0x11, 0x84, 0xf7, 0x44, 0x93,
|
||||
0xac, 0xff, 0xa4, 0xa0, 0x90, 0x80, 0xd1, 0x09, 0xec, 0xc7, 0x33, 0x5a, 0x17, 0x55, 0xfc, 0x85,
|
||||
0x5e, 0x42, 0x79, 0xca, 0x22, 0x41, 0xe5, 0xc8, 0xa6, 0x32, 0x49, 0xf1, 0x7b, 0xb7, 0x85, 0xa2,
|
||||
0x6f, 0xe0, 0x69, 0x20, 0x26, 0x3c, 0xd4, 0xab, 0x4c, 0xb4, 0x18, 0x0e, 0x79, 0x14, 0xd1, 0x79,
|
||||
0x18, 0xdc, 0xa8, 0x52, 0xdb, 0x23, 0x8f, 0x89, 0xd1, 0x6b, 0x38, 0x88, 0x6b, 0x24, 0x32, 0x33,
|
||||
0xca, 0xf5, 0x67, 0x0f, 0x47, 0xfe, 0xd2, 0xfb, 0x15, 0xd5, 0xfa, 0x77, 0x0a, 0xca, 0x9b, 0x42,
|
||||
0xf4, 0x42, 0x55, 0xbf, 0x2a, 0x41, 0x6f, 0xa4, 0xee, 0x91, 0x21, 0x09, 0xe4, 0x93, 0xef, 0x52,
|
||||
0x83, 0xe3, 0x99, 0xe7, 0xd3, 0x39, 0xf7, 0xd9, 0xd4, 0xfb, 0x2b, 0xa7, 0xcb, 0x45, 0x22, 0xad,
|
||||
0xd8, 0x3b, 0x65, 0xc8, 0x82, 0xe2, 0xc6, 0xa5, 0x33, 0xea, 0xd2, 0x1b, 0xd8, 0xab, 0x7f, 0xa6,
|
||||
0xa0, 0x98, 0x5c, 0x89, 0x50, 0x09, 0xf2, 0xb6, 0x43, 0x5b, 0x1d, 0xfb, 0xdb, 0x76, 0xdf, 0xf8,
|
||||
0x4c, 0x7e, 0xf6, 0x06, 0x8d, 0x06, 0xc6, 0x4d, 0xdc, 0x34, 0x52, 0x08, 0x41, 0x59, 0x4e, 0x02,
|
||||
0xdc, 0xa4, 0x7d, 0xbb, 0x8b, 0xdd, 0x81, 0x7c, 0x16, 0x8e, 0xa0, 0x12, 0x63, 0x8e, 0x4b, 0x89,
|
||||
0x3b, 0xe8, 0x63, 0x23, 0x8d, 0x0c, 0x28, 0xc6, 0x20, 0x26, 0xc4, 0x25, 0x46, 0x46, 0xce, 0xb2,
|
||||
0x18, 0x79, 0xf8, 0xc4, 0x34, 0x71, 0xbf, 0x6e, 0x77, 0x7a, 0x46, 0xb6, 0xf6, 0xf7, 0x0c, 0xec,
|
||||
0xab, 0x15, 0x22, 0x44, 0x6d, 0x28, 0x24, 0x76, 0x71, 0x74, 0x96, 0xc8, 0xc0, 0xc3, 0x1d, 0xbd,
|
||||
0x6a, 0xee, 0xde, 0xf1, 0x16, 0xd1, 0x6f, 0x52, 0xe8, 0x8f, 0x50, 0x4c, 0x6e, 0x96, 0x28, 0xb9,
|
||||
0x31, 0xec, 0x58, 0x39, 0x3f, 0xaa, 0xeb, 0x2d, 0x18, 0x38, 0x12, 0xde, 0x4c, 0xbe, 0xf6, 0xf1,
|
||||
0xce, 0x86, 0xaa, 0x09, 0xfe, 0xd6, 0x22, 0x58, 0x3d, 0xdd, 0x29, 0x8b, 0xfb, 0xa3, 0xa3, 0xaf,
|
||||
0x18, 0x6f, 0x4d, 0x0f, 0xae, 0xb8, 0xb9, 0xaa, 0x55, 0x5f, 0x3c, 0x26, 0x8e, 0xb5, 0x8d, 0xe0,
|
||||
0x68, 0x47, 0x27, 0xa3, 0x5f, 0x25, 0x3d, 0x78, 0x74, 0x0e, 0x54, 0x5f, 0xfe, 0x1c, 0x6d, 0x6d,
|
||||
0x65, 0x47, 0xcb, 0x6f, 0x58, 0x79, 0x7c, 0x60, 0x6c, 0x58, 0xf9, 0xc8, 0xe4, 0x78, 0xf3, 0xdb,
|
||||
0x3f, 0x5d, 0x8d, 0x3d, 0x31, 0x59, 0xdc, 0x5c, 0x0e, 0x83, 0xd9, 0xd5, 0xd4, 0x1b, 0x4f, 0x84,
|
||||
0xef, 0xf9, 0x63, 0x9f, 0x8b, 0xbf, 0x04, 0xe1, 0xdd, 0xd5, 0xd4, 0x1f, 0x5d, 0xa9, 0x2d, 0xf4,
|
||||
0x6a, 0xa5, 0xee, 0x66, 0x5f, 0xfd, 0x0f, 0xf7, 0xbb, 0xff, 0x07, 0x00, 0x00, 0xff, 0xff, 0xb7,
|
||||
0x0c, 0x44, 0x60, 0xf3, 0x0d, 0x00, 0x00,
|
||||
// 1659 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x57, 0x4f, 0x73, 0x22, 0xc7,
|
||||
0x15, 0x37, 0x02, 0x84, 0x78, 0xfc, 0xd1, 0xa8, 0xa5, 0x95, 0x58, 0xb4, 0x5a, 0xcb, 0xe3, 0x64,
|
||||
0xad, 0xda, 0x72, 0x24, 0x87, 0xd4, 0xba, 0x7c, 0x4a, 0x8a, 0x85, 0xc6, 0x8c, 0x17, 0x66, 0xe4,
|
||||
0x06, 0xd6, 0xde, 0xe4, 0xd0, 0xd5, 0x62, 0x5a, 0x30, 0x25, 0x98, 0xc1, 0x33, 0x8d, 0xb3, 0xca,
|
||||
0x21, 0xb7, 0x54, 0xe5, 0x92, 0xcf, 0x92, 0x5c, 0x73, 0xc9, 0xc7, 0x49, 0xbe, 0x43, 0x4e, 0xa9,
|
||||
0xee, 0x1e, 0x60, 0x40, 0x68, 0xb3, 0x27, 0x31, 0xbf, 0xdf, 0xaf, 0xdf, 0xeb, 0x7e, 0xaf, 0xdf,
|
||||
0xeb, 0x27, 0x38, 0x0e, 0x83, 0xb9, 0xe0, 0x61, 0x38, 0x1b, 0x5e, 0xe9, 0x5f, 0x97, 0xb3, 0x30,
|
||||
0x10, 0x01, 0xca, 0x2f, 0xf1, 0x6a, 0x3e, 0x9c, 0x0d, 0x35, 0x6a, 0xfe, 0x77, 0x07, 0x50, 0x8f,
|
||||
0xfb, 0xee, 0x35, 0xbb, 0x9f, 0x72, 0x5f, 0x10, 0xfe, 0xd3, 0x9c, 0x47, 0x02, 0x21, 0xc8, 0xb8,
|
||||
0x3c, 0x12, 0x95, 0xd4, 0x79, 0xea, 0xa2, 0x48, 0xd4, 0x6f, 0x64, 0x40, 0x9a, 0x4d, 0x45, 0x65,
|
||||
0xe7, 0x3c, 0x75, 0x91, 0x26, 0xf2, 0x27, 0xfa, 0x0c, 0x8a, 0x33, 0xbd, 0x8e, 0x8e, 0x59, 0x34,
|
||||
0xae, 0xa4, 0x95, 0xba, 0x10, 0x63, 0x6d, 0x16, 0x8d, 0xd1, 0x05, 0x18, 0xb7, 0x9e, 0xcf, 0x26,
|
||||
0x74, 0x38, 0x11, 0x3f, 0x53, 0x97, 0x4f, 0x04, 0xab, 0x64, 0xce, 0x53, 0x17, 0x59, 0x52, 0x56,
|
||||
0x78, 0x63, 0x22, 0x7e, 0x6e, 0x4a, 0x14, 0x7d, 0x01, 0xfb, 0x0b, 0x63, 0xa1, 0xde, 0x45, 0x25,
|
||||
0x7b, 0x9e, 0xba, 0xc8, 0x93, 0xf2, 0x6c, 0x7d, 0x6f, 0x5f, 0xc0, 0xbe, 0xf0, 0xa6, 0x3c, 0x98,
|
||||
0x0b, 0x1a, 0xf1, 0x61, 0xe0, 0xbb, 0x51, 0x65, 0x57, 0x5b, 0x8c, 0xe1, 0x9e, 0x46, 0x91, 0x09,
|
||||
0xa5, 0x5b, 0xce, 0xe9, 0xc4, 0x9b, 0x7a, 0x82, 0x46, 0x4c, 0x54, 0x72, 0x6a, 0xeb, 0x85, 0x5b,
|
||||
0xce, 0x3b, 0x12, 0xeb, 0x31, 0x21, 0xf7, 0x17, 0xcc, 0xc5, 0x28, 0xf0, 0xfc, 0x11, 0x1d, 0x8e,
|
||||
0x99, 0x4f, 0x3d, 0xb7, 0xb2, 0x77, 0x9e, 0xba, 0xc8, 0x90, 0xf2, 0x02, 0x6f, 0x8c, 0x99, 0x6f,
|
||||
0xb9, 0xe8, 0x0c, 0x40, 0x9d, 0x41, 0x99, 0xab, 0xe4, 0x95, 0xc7, 0xbc, 0x44, 0x94, 0x2d, 0x54,
|
||||
0x83, 0x82, 0x0a, 0x30, 0x1d, 0x7b, 0xbe, 0x88, 0x2a, 0x70, 0x9e, 0xbe, 0x28, 0xd4, 0x8c, 0xcb,
|
||||
0x89, 0x2f, 0x63, 0x4d, 0x24, 0xd3, 0xf6, 0x7c, 0x41, 0x92, 0x22, 0xf3, 0x1b, 0x38, 0xec, 0x87,
|
||||
0x6c, 0x78, 0xb7, 0x11, 0xfc, 0xcd, 0xb0, 0xa6, 0x1e, 0x84, 0xd5, 0xfc, 0x33, 0x94, 0xe2, 0x45,
|
||||
0x3d, 0xc1, 0xc4, 0x3c, 0x42, 0xbf, 0x82, 0x6c, 0x24, 0x98, 0xe0, 0x4a, 0x5c, 0xae, 0x9d, 0x5c,
|
||||
0x2e, 0xb3, 0x7d, 0x99, 0x10, 0x72, 0xa2, 0x55, 0xa8, 0x0a, 0x7b, 0xb3, 0x90, 0x7b, 0x53, 0x36,
|
||||
0xe2, 0x2a, 0xa1, 0x45, 0xb2, 0xfc, 0x46, 0x26, 0x64, 0xd5, 0x62, 0x95, 0xce, 0x42, 0xad, 0x98,
|
||||
0x3c, 0x03, 0xd1, 0x94, 0xf9, 0x5b, 0xd8, 0x57, 0xdf, 0x2d, 0xce, 0x3f, 0x74, 0x65, 0x4e, 0x20,
|
||||
0xc7, 0xa6, 0x3a, 0xf6, 0xfa, 0xda, 0xec, 0xb2, 0xa9, 0x0c, 0xbb, 0xe9, 0x82, 0xb1, 0x5a, 0x1f,
|
||||
0xcd, 0x02, 0x3f, 0xe2, 0x32, 0x15, 0xd2, 0xb8, 0xcc, 0x84, 0x4c, 0xdb, 0x54, 0xae, 0x4a, 0xa9,
|
||||
0x55, 0xe5, 0x18, 0x6f, 0x71, 0xde, 0x8d, 0x98, 0x40, 0x2f, 0xf4, 0x0d, 0xa0, 0x93, 0x60, 0x78,
|
||||
0x27, 0xef, 0x14, 0xbb, 0x8f, 0xcd, 0x97, 0x24, 0xdc, 0x09, 0x86, 0x77, 0x4d, 0x09, 0x9a, 0x7f,
|
||||
0xd0, 0x77, 0xbb, 0x1f, 0xe8, 0xbd, 0x7f, 0x74, 0x78, 0x57, 0x21, 0xd8, 0x79, 0x3c, 0x04, 0x14,
|
||||
0x0e, 0xd7, 0x8c, 0xc7, 0xa7, 0x48, 0x46, 0x36, 0xb5, 0x11, 0xd9, 0x2f, 0x21, 0x77, 0xcb, 0xbc,
|
||||
0xc9, 0x3c, 0x5c, 0x18, 0x46, 0x89, 0x34, 0xb5, 0x34, 0x43, 0x16, 0x12, 0xf3, 0x9f, 0x39, 0xc8,
|
||||
0xc5, 0x20, 0xaa, 0x41, 0x66, 0x18, 0xb8, 0x8b, 0xec, 0x3e, 0x7f, 0xb8, 0x6c, 0xf1, 0xb7, 0x11,
|
||||
0xb8, 0x9c, 0x28, 0x2d, 0xfa, 0x1d, 0x94, 0xe5, 0x8d, 0xf6, 0xf9, 0x84, 0xce, 0x67, 0x2e, 0x5b,
|
||||
0x26, 0xb4, 0x92, 0x58, 0xdd, 0xd0, 0x82, 0x81, 0xe2, 0x49, 0x69, 0x98, 0xfc, 0x44, 0xa7, 0x90,
|
||||
0x1f, 0x8b, 0xc9, 0x50, 0x67, 0x22, 0xa3, 0x8a, 0x62, 0x4f, 0x02, 0x2a, 0x07, 0x26, 0x94, 0x02,
|
||||
0xdf, 0x0b, 0x7c, 0x1a, 0x8d, 0x19, 0xad, 0xbd, 0xfa, 0x5a, 0x15, 0x6b, 0x91, 0x14, 0x14, 0xd8,
|
||||
0x1b, 0xb3, 0xda, 0xab, 0xaf, 0xd1, 0xa7, 0x50, 0x50, 0x25, 0xc3, 0xdf, 0xcf, 0xbc, 0xf0, 0x5e,
|
||||
0x55, 0x69, 0x89, 0xa8, 0x2a, 0xc2, 0x0a, 0x41, 0x47, 0x90, 0xbd, 0x9d, 0xb0, 0x51, 0xa4, 0x2a,
|
||||
0xb3, 0x44, 0xf4, 0x07, 0xfa, 0x0a, 0x8e, 0xe2, 0x18, 0xd0, 0x28, 0x98, 0x87, 0x43, 0x4e, 0x3d,
|
||||
0xdf, 0xe5, 0xef, 0x55, 0x5d, 0x96, 0x08, 0x8a, 0xb9, 0x9e, 0xa2, 0x2c, 0xc9, 0x98, 0x7f, 0xcd,
|
||||
0x42, 0x21, 0x11, 0x00, 0x54, 0x84, 0x3d, 0x82, 0x7b, 0x98, 0xbc, 0xc5, 0x4d, 0xe3, 0x13, 0x54,
|
||||
0x81, 0xa3, 0x81, 0xfd, 0xc6, 0x76, 0x7e, 0xb0, 0xe9, 0x75, 0xfd, 0x5d, 0x17, 0xdb, 0x7d, 0xda,
|
||||
0xae, 0xf7, 0xda, 0x46, 0x0a, 0x3d, 0x83, 0x8a, 0x65, 0x37, 0x1c, 0x42, 0x70, 0xa3, 0xbf, 0xe4,
|
||||
0xea, 0x5d, 0x67, 0x60, 0xf7, 0x8d, 0x1d, 0xf4, 0x29, 0x9c, 0xb6, 0x2c, 0xbb, 0xde, 0xa1, 0x2b,
|
||||
0x4d, 0xa3, 0xd3, 0x7f, 0x4b, 0xf1, 0x8f, 0xd7, 0x16, 0x79, 0x67, 0xa4, 0xb7, 0x09, 0xda, 0xfd,
|
||||
0x4e, 0x63, 0x61, 0x21, 0x83, 0x9e, 0xc2, 0x13, 0x2d, 0xd0, 0x4b, 0x68, 0xdf, 0x71, 0x68, 0xcf,
|
||||
0x71, 0x6c, 0x23, 0x8b, 0x0e, 0xa0, 0x64, 0xd9, 0x6f, 0xeb, 0x1d, 0xab, 0x49, 0x09, 0xae, 0x77,
|
||||
0xba, 0xc6, 0x2e, 0x3a, 0x84, 0xfd, 0x4d, 0x5d, 0x4e, 0x9a, 0x58, 0xe8, 0x1c, 0xdb, 0x72, 0x6c,
|
||||
0xfa, 0x16, 0x93, 0x9e, 0xe5, 0xd8, 0xc6, 0x1e, 0x3a, 0x06, 0xb4, 0x4e, 0xb5, 0xbb, 0xf5, 0x86,
|
||||
0x91, 0x47, 0x4f, 0xe0, 0x60, 0x1d, 0x7f, 0x83, 0xdf, 0x19, 0x20, 0xc3, 0xa0, 0x37, 0x46, 0x5f,
|
||||
0xe3, 0x8e, 0xf3, 0x03, 0xed, 0x5a, 0xb6, 0xd5, 0x1d, 0x74, 0x8d, 0x02, 0x3a, 0x02, 0xa3, 0x85,
|
||||
0x31, 0xb5, 0xec, 0xde, 0xa0, 0xd5, 0xb2, 0x1a, 0x16, 0xb6, 0xfb, 0x46, 0x51, 0x7b, 0xde, 0x76,
|
||||
0xf0, 0x92, 0x5c, 0xd0, 0x68, 0xd7, 0x6d, 0x1b, 0x77, 0x68, 0xd3, 0xea, 0xd5, 0x5f, 0x77, 0x70,
|
||||
0xd3, 0x28, 0xa3, 0x33, 0x78, 0xda, 0xc7, 0xdd, 0x6b, 0x87, 0xd4, 0xc9, 0x3b, 0xba, 0xe0, 0x5b,
|
||||
0x75, 0xab, 0x33, 0x20, 0xd8, 0xd8, 0x47, 0x9f, 0xc1, 0x19, 0xc1, 0xdf, 0x0f, 0x2c, 0x82, 0x9b,
|
||||
0xd4, 0x76, 0x9a, 0x98, 0xb6, 0x70, 0xbd, 0x3f, 0x20, 0x98, 0x76, 0xad, 0x5e, 0xcf, 0xb2, 0xbf,
|
||||
0x35, 0x0c, 0xf4, 0x0b, 0x38, 0x5f, 0x4a, 0x96, 0x06, 0x36, 0x54, 0x07, 0xf2, 0x7c, 0x8b, 0x7c,
|
||||
0xda, 0xf8, 0xc7, 0x3e, 0xbd, 0xc6, 0x98, 0x18, 0x08, 0x55, 0xe1, 0x78, 0xe5, 0x5e, 0x3b, 0x88,
|
||||
0x7d, 0x1f, 0x4a, 0xee, 0x1a, 0x93, 0x6e, 0xdd, 0x96, 0x09, 0x5e, 0xe3, 0x8e, 0xe4, 0xb6, 0x57,
|
||||
0xdc, 0xe6, 0xb6, 0x9f, 0xa0, 0x23, 0xd8, 0x5f, 0x78, 0x5b, 0x80, 0xff, 0xce, 0xa1, 0x13, 0x40,
|
||||
0x03, 0x9b, 0xe0, 0x7a, 0x53, 0x1e, 0x7e, 0x49, 0xfc, 0x27, 0xf7, 0x5d, 0x66, 0x6f, 0xc7, 0x48,
|
||||
0x9b, 0x7f, 0x4f, 0x43, 0x69, 0xad, 0xb6, 0xd0, 0x33, 0xc8, 0x47, 0xde, 0xc8, 0x67, 0x42, 0x56,
|
||||
0xbf, 0x6e, 0x0c, 0x2b, 0x40, 0x3d, 0x2e, 0x63, 0xe6, 0xf9, 0xba, 0x23, 0xe9, 0x8e, 0x9c, 0x57,
|
||||
0x88, 0xea, 0x47, 0x27, 0x90, 0x5b, 0x3c, 0x4e, 0x69, 0x55, 0x87, 0xbb, 0x43, 0xfd, 0x28, 0x3d,
|
||||
0x83, 0xbc, 0x6c, 0x79, 0x91, 0x60, 0xd3, 0x99, 0x2a, 0xd1, 0x12, 0x59, 0x01, 0xe8, 0x73, 0x28,
|
||||
0x4d, 0x79, 0x14, 0xb1, 0x11, 0xa7, 0xba, 0xcc, 0x40, 0x29, 0x8a, 0x31, 0xd8, 0x52, 0xd5, 0xf6,
|
||||
0x39, 0x2c, 0xca, 0x3e, 0x16, 0x65, 0xb5, 0x28, 0x06, 0xb5, 0x68, 0xb3, 0xe3, 0x0a, 0x16, 0x57,
|
||||
0x73, 0xb2, 0xe3, 0x0a, 0x86, 0x5e, 0xc2, 0x81, 0x6e, 0x19, 0x9e, 0xef, 0x4d, 0xe7, 0x53, 0xdd,
|
||||
0x3a, 0x72, 0x6a, 0xcb, 0xfb, 0xaa, 0x75, 0x68, 0x5c, 0x75, 0x90, 0xa7, 0xb0, 0x77, 0xc3, 0x22,
|
||||
0x2e, 0x9b, 0x7d, 0x5c, 0xda, 0x39, 0xf9, 0xdd, 0xe2, 0x5c, 0x52, 0xf2, 0x09, 0x08, 0x65, 0xd3,
|
||||
0xca, 0x6b, 0xea, 0x96, 0x73, 0x22, 0xe3, 0xb8, 0xf4, 0xc0, 0xde, 0xaf, 0x3c, 0x14, 0x12, 0x1e,
|
||||
0x34, 0xae, 0x3c, 0xbc, 0x84, 0x03, 0xfe, 0x5e, 0x84, 0x8c, 0x06, 0x33, 0xf6, 0xd3, 0x9c, 0x53,
|
||||
0x97, 0x09, 0x56, 0x29, 0xaa, 0xe0, 0xee, 0x2b, 0xc2, 0x51, 0x78, 0x93, 0x09, 0x66, 0x3e, 0x83,
|
||||
0x2a, 0xe1, 0x11, 0x17, 0x5d, 0x2f, 0x8a, 0xbc, 0xc0, 0x6f, 0x04, 0xbe, 0x08, 0x83, 0x49, 0xfc,
|
||||
0x66, 0x98, 0x67, 0x70, 0xba, 0x95, 0xd5, 0x4d, 0x5f, 0x2e, 0xfe, 0x7e, 0xce, 0xc3, 0xfb, 0xed,
|
||||
0x8b, 0xdf, 0xc0, 0xe9, 0x56, 0x36, 0x7e, 0x31, 0xbe, 0x84, 0xac, 0x1f, 0xb8, 0x3c, 0xaa, 0xa4,
|
||||
0xd4, 0xcc, 0x70, 0x9c, 0x68, 0xcf, 0x76, 0xe0, 0xf2, 0xb6, 0x17, 0x89, 0x20, 0xbc, 0x27, 0x5a,
|
||||
0x64, 0xfe, 0x2b, 0x05, 0x85, 0x04, 0x8c, 0x8e, 0x61, 0x77, 0x36, 0xbf, 0xb9, 0xe3, 0xf7, 0xf1,
|
||||
0xa5, 0x8a, 0xbf, 0xd0, 0x0b, 0x28, 0x4f, 0x58, 0x24, 0xa8, 0xec, 0x96, 0x54, 0x26, 0x29, 0x7e,
|
||||
0x22, 0x37, 0x50, 0xf4, 0x0d, 0x9c, 0x04, 0x62, 0xcc, 0x43, 0x3d, 0xfd, 0x44, 0xf3, 0xe1, 0x90,
|
||||
0x47, 0x11, 0x9d, 0x85, 0xc1, 0x8d, 0xba, 0x6a, 0x3b, 0xe4, 0x31, 0x1a, 0xbd, 0x82, 0xbd, 0xf8,
|
||||
0x8e, 0x44, 0x95, 0x8c, 0xda, 0xfa, 0xd3, 0x87, 0x2f, 0xcb, 0x62, 0xf7, 0x4b, 0xa9, 0xf9, 0x8f,
|
||||
0x14, 0x94, 0xd7, 0x49, 0xf4, 0x5c, 0xdd, 0x7e, 0x75, 0x05, 0x3d, 0x57, 0x9d, 0x23, 0x43, 0x12,
|
||||
0xc8, 0x47, 0x9f, 0xa5, 0x06, 0x47, 0x53, 0xcf, 0xa7, 0x33, 0xee, 0xb3, 0x89, 0xf7, 0x27, 0x4e,
|
||||
0x17, 0xb3, 0x47, 0x5a, 0xa9, 0xb7, 0x72, 0xc8, 0x84, 0xe2, 0xda, 0xa1, 0x33, 0xea, 0xd0, 0x6b,
|
||||
0xd8, 0xcb, 0xbf, 0xa5, 0xa0, 0x98, 0x9c, 0xa2, 0x50, 0x09, 0xf2, 0x96, 0x4d, 0x5b, 0x1d, 0xeb,
|
||||
0xdb, 0x76, 0xdf, 0xf8, 0x44, 0x7e, 0xf6, 0x06, 0x8d, 0x06, 0xc6, 0x4d, 0xdc, 0x34, 0x52, 0x08,
|
||||
0x41, 0x59, 0x36, 0x04, 0xdc, 0xa4, 0x7d, 0xab, 0x8b, 0x9d, 0x81, 0x7c, 0x4b, 0x0e, 0x61, 0x3f,
|
||||
0xc6, 0x6c, 0x87, 0x12, 0x67, 0xd0, 0xc7, 0x46, 0x1a, 0x19, 0x50, 0x8c, 0x41, 0x4c, 0x88, 0x43,
|
||||
0x8c, 0x8c, 0x6c, 0x80, 0x31, 0xf2, 0xf0, 0x5d, 0x6a, 0xe2, 0x7e, 0xdd, 0xea, 0xf4, 0x8c, 0x6c,
|
||||
0xed, 0x2f, 0x19, 0xd8, 0x55, 0x53, 0x47, 0x88, 0xda, 0x50, 0x48, 0x8c, 0xef, 0xe8, 0x2c, 0x91,
|
||||
0x81, 0x87, 0x63, 0x7d, 0xb5, 0xb2, 0x7d, 0x2c, 0x9c, 0x47, 0x5f, 0xa5, 0xd0, 0x77, 0x50, 0x4c,
|
||||
0x0e, 0xa3, 0x28, 0x39, 0x64, 0x6c, 0x99, 0x52, 0x3f, 0x68, 0xeb, 0x0d, 0x18, 0x38, 0x12, 0xde,
|
||||
0x54, 0x0e, 0x15, 0xf1, 0x98, 0x87, 0xaa, 0x09, 0xfd, 0xc6, 0xec, 0x58, 0x3d, 0xdd, 0xca, 0xc5,
|
||||
0xf5, 0xd1, 0xd1, 0x47, 0x8c, 0x07, 0xad, 0x07, 0x47, 0x5c, 0x9f, 0xee, 0xaa, 0xcf, 0x1f, 0xa3,
|
||||
0x63, 0x6b, 0x2e, 0x1c, 0x6e, 0xa9, 0x64, 0xf4, 0xcb, 0xe4, 0x0e, 0x1e, 0xed, 0x03, 0xd5, 0x17,
|
||||
0xff, 0x4f, 0xb6, 0xf2, 0xb2, 0xa5, 0xe4, 0xd7, 0xbc, 0x3c, 0xde, 0x30, 0xd6, 0xbc, 0x7c, 0xa0,
|
||||
0x73, 0xbc, 0xfe, 0xf5, 0xef, 0xaf, 0x46, 0x9e, 0x18, 0xcf, 0x6f, 0x2e, 0x87, 0xc1, 0xf4, 0x6a,
|
||||
0xe2, 0x8d, 0xc6, 0xc2, 0xf7, 0xfc, 0x91, 0xcf, 0xc5, 0x1f, 0x83, 0xf0, 0xee, 0x6a, 0xe2, 0xbb,
|
||||
0x57, 0x6a, 0x70, 0xbd, 0x5a, 0x9a, 0xbb, 0xd9, 0x55, 0xff, 0xf6, 0xfd, 0xe6, 0x7f, 0x01, 0x00,
|
||||
0x00, 0xff, 0xff, 0xcc, 0x5a, 0xee, 0x77, 0x26, 0x0e, 0x00, 0x00,
|
||||
}
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
|
@ -194,16 +194,23 @@ message Failure {
|
||||
TEMPORARY_NODE_FAILURE = 19;
|
||||
PERMANENT_NODE_FAILURE = 20;
|
||||
PERMANENT_CHANNEL_FAILURE = 21;
|
||||
|
||||
/**
|
||||
The error source is known, but the failure itself couldn't be decoded.
|
||||
*/
|
||||
UNKNOWN_FAILURE = 998;
|
||||
|
||||
/**
|
||||
An unreadable failure result is returned if the received failure message
|
||||
cannot be decrypted. In that case the error source is unknown.
|
||||
*/
|
||||
UNREADABLE_FAILURE = 999;
|
||||
}
|
||||
|
||||
/// Failure code as defined in the Lightning spec
|
||||
FailureCode code = 1;
|
||||
|
||||
/**
|
||||
The node pubkey of the intermediate or final node that generated the failure
|
||||
message.
|
||||
**/
|
||||
bytes failure_source_pubkey = 2;
|
||||
reserved 2;
|
||||
|
||||
/// An optional channel update message.
|
||||
ChannelUpdate channel_update = 3;
|
||||
@ -219,6 +226,12 @@ message Failure {
|
||||
|
||||
/// A failure type-dependent flags value.
|
||||
uint32 flags = 7;
|
||||
|
||||
/**
|
||||
The position in the path of the intermediate or final node that generated
|
||||
the failure message. Position zero is the sender node.
|
||||
**/
|
||||
uint32 failure_source_index = 8;
|
||||
}
|
||||
|
||||
|
||||
|
@ -310,6 +310,11 @@ func (s *Server) SendToRoute(ctx context.Context,
|
||||
func marshallError(sendError error) (*Failure, error) {
|
||||
response := &Failure{}
|
||||
|
||||
if sendError == htlcswitch.ErrUnreadableFailureMessage {
|
||||
response.Code = Failure_UNREADABLE_FAILURE
|
||||
return response, nil
|
||||
}
|
||||
|
||||
fErr, ok := sendError.(*htlcswitch.ForwardingError)
|
||||
if !ok {
|
||||
return nil, sendError
|
||||
@ -394,12 +399,11 @@ func marshallError(sendError error) (*Failure, error) {
|
||||
|
||||
case *lnwire.FailPermanentChannelFailure:
|
||||
response.Code = Failure_PERMANENT_CHANNEL_FAILURE
|
||||
|
||||
default:
|
||||
return nil, errors.New("unknown wire error")
|
||||
response.Code = Failure_UNKNOWN_FAILURE
|
||||
}
|
||||
|
||||
response.FailureSourcePubkey = fErr.ErrorSource.SerializeCompressed()
|
||||
response.FailureSourceIndex = uint32(fErr.FailureSourceIdx)
|
||||
|
||||
return response, nil
|
||||
}
|
||||
|
@ -162,14 +162,14 @@ type FailInvalidRealm struct{}
|
||||
// Returns a human readable string describing the target FailureMessage.
|
||||
//
|
||||
// NOTE: Implements the error interface.
|
||||
func (f FailInvalidRealm) Error() string {
|
||||
func (f *FailInvalidRealm) Error() string {
|
||||
return f.Code().String()
|
||||
}
|
||||
|
||||
// Code returns the failure unique code.
|
||||
//
|
||||
// NOTE: Part of the FailureMessage interface.
|
||||
func (f FailInvalidRealm) Code() FailCode {
|
||||
func (f *FailInvalidRealm) Code() FailCode {
|
||||
return CodeInvalidRealm
|
||||
}
|
||||
|
||||
@ -181,14 +181,14 @@ type FailTemporaryNodeFailure struct{}
|
||||
|
||||
// Code returns the failure unique code.
|
||||
// NOTE: Part of the FailureMessage interface.
|
||||
func (f FailTemporaryNodeFailure) Code() FailCode {
|
||||
func (f *FailTemporaryNodeFailure) Code() FailCode {
|
||||
return CodeTemporaryNodeFailure
|
||||
}
|
||||
|
||||
// Returns a human readable string describing the target FailureMessage.
|
||||
//
|
||||
// NOTE: Implements the error interface.
|
||||
func (f FailTemporaryNodeFailure) Error() string {
|
||||
func (f *FailTemporaryNodeFailure) Error() string {
|
||||
return f.Code().String()
|
||||
}
|
||||
|
||||
@ -201,14 +201,14 @@ type FailPermanentNodeFailure struct{}
|
||||
// Code returns the failure unique code.
|
||||
//
|
||||
// NOTE: Part of the FailureMessage interface.
|
||||
func (f FailPermanentNodeFailure) Code() FailCode {
|
||||
func (f *FailPermanentNodeFailure) Code() FailCode {
|
||||
return CodePermanentNodeFailure
|
||||
}
|
||||
|
||||
// Returns a human readable string describing the target FailureMessage.
|
||||
//
|
||||
// NOTE: Implements the error interface.
|
||||
func (f FailPermanentNodeFailure) Error() string {
|
||||
func (f *FailPermanentNodeFailure) Error() string {
|
||||
return f.Code().String()
|
||||
}
|
||||
|
||||
@ -222,14 +222,14 @@ type FailRequiredNodeFeatureMissing struct{}
|
||||
// Code returns the failure unique code.
|
||||
//
|
||||
// NOTE: Part of the FailureMessage interface.
|
||||
func (f FailRequiredNodeFeatureMissing) Code() FailCode {
|
||||
func (f *FailRequiredNodeFeatureMissing) Code() FailCode {
|
||||
return CodeRequiredNodeFeatureMissing
|
||||
}
|
||||
|
||||
// Returns a human readable string describing the target FailureMessage.
|
||||
//
|
||||
// NOTE: Implements the error interface.
|
||||
func (f FailRequiredNodeFeatureMissing) Error() string {
|
||||
func (f *FailRequiredNodeFeatureMissing) Error() string {
|
||||
return f.Code().String()
|
||||
}
|
||||
|
||||
@ -242,14 +242,14 @@ type FailPermanentChannelFailure struct{}
|
||||
// Code returns the failure unique code.
|
||||
//
|
||||
// NOTE: Part of the FailureMessage interface.
|
||||
func (f FailPermanentChannelFailure) Code() FailCode {
|
||||
func (f *FailPermanentChannelFailure) Code() FailCode {
|
||||
return CodePermanentChannelFailure
|
||||
}
|
||||
|
||||
// Returns a human readable string describing the target FailureMessage.
|
||||
//
|
||||
// NOTE: Implements the error interface.
|
||||
func (f FailPermanentChannelFailure) Error() string {
|
||||
func (f *FailPermanentChannelFailure) Error() string {
|
||||
return f.Code().String()
|
||||
}
|
||||
|
||||
@ -263,14 +263,14 @@ type FailRequiredChannelFeatureMissing struct{}
|
||||
// Code returns the failure unique code.
|
||||
//
|
||||
// NOTE: Part of the FailureMessage interface.
|
||||
func (f FailRequiredChannelFeatureMissing) Code() FailCode {
|
||||
func (f *FailRequiredChannelFeatureMissing) Code() FailCode {
|
||||
return CodeRequiredChannelFeatureMissing
|
||||
}
|
||||
|
||||
// Returns a human readable string describing the target FailureMessage.
|
||||
//
|
||||
// NOTE: Implements the error interface.
|
||||
func (f FailRequiredChannelFeatureMissing) Error() string {
|
||||
func (f *FailRequiredChannelFeatureMissing) Error() string {
|
||||
return f.Code().String()
|
||||
}
|
||||
|
||||
@ -283,14 +283,14 @@ type FailUnknownNextPeer struct{}
|
||||
// Code returns the failure unique code.
|
||||
//
|
||||
// NOTE: Part of the FailureMessage interface.
|
||||
func (f FailUnknownNextPeer) Code() FailCode {
|
||||
func (f *FailUnknownNextPeer) Code() FailCode {
|
||||
return CodeUnknownNextPeer
|
||||
}
|
||||
|
||||
// Returns a human readable string describing the target FailureMessage.
|
||||
//
|
||||
// NOTE: Implements the error interface.
|
||||
func (f FailUnknownNextPeer) Error() string {
|
||||
func (f *FailUnknownNextPeer) Error() string {
|
||||
return f.Code().String()
|
||||
}
|
||||
|
||||
@ -306,14 +306,14 @@ type FailIncorrectPaymentAmount struct{}
|
||||
// Code returns the failure unique code.
|
||||
//
|
||||
// NOTE: Part of the FailureMessage interface.
|
||||
func (f FailIncorrectPaymentAmount) Code() FailCode {
|
||||
func (f *FailIncorrectPaymentAmount) Code() FailCode {
|
||||
return CodeIncorrectPaymentAmount
|
||||
}
|
||||
|
||||
// Returns a human readable string describing the target FailureMessage.
|
||||
//
|
||||
// NOTE: Implements the error interface.
|
||||
func (f FailIncorrectPaymentAmount) Error() string {
|
||||
func (f *FailIncorrectPaymentAmount) Error() string {
|
||||
return f.Code().String()
|
||||
}
|
||||
|
||||
@ -344,21 +344,21 @@ func NewFailUnknownPaymentHash(amt MilliSatoshi) *FailUnknownPaymentHash {
|
||||
}
|
||||
|
||||
// Amount is the value of the extended HTLC.
|
||||
func (f FailUnknownPaymentHash) Amount() MilliSatoshi {
|
||||
func (f *FailUnknownPaymentHash) Amount() MilliSatoshi {
|
||||
return f.amount
|
||||
}
|
||||
|
||||
// Code returns the failure unique code.
|
||||
//
|
||||
// NOTE: Part of the FailureMessage interface.
|
||||
func (f FailUnknownPaymentHash) Code() FailCode {
|
||||
func (f *FailUnknownPaymentHash) Code() FailCode {
|
||||
return CodeUnknownPaymentHash
|
||||
}
|
||||
|
||||
// Returns a human readable string describing the target FailureMessage.
|
||||
//
|
||||
// NOTE: Implements the error interface.
|
||||
func (f FailUnknownPaymentHash) Error() string {
|
||||
func (f *FailUnknownPaymentHash) Error() string {
|
||||
return fmt.Sprintf("UnknownPaymentHash(amt=%v)", f.amount)
|
||||
}
|
||||
|
||||
@ -398,14 +398,14 @@ type FailFinalExpiryTooSoon struct{}
|
||||
// Code returns the failure unique code.
|
||||
//
|
||||
// NOTE: Part of the FailureMessage interface.
|
||||
func (f FailFinalExpiryTooSoon) Code() FailCode {
|
||||
func (f *FailFinalExpiryTooSoon) Code() FailCode {
|
||||
return CodeFinalExpiryTooSoon
|
||||
}
|
||||
|
||||
// Returns a human readable string describing the target FailureMessage.
|
||||
//
|
||||
// NOTE: Implements the error interface.
|
||||
func (f FailFinalExpiryTooSoon) Error() string {
|
||||
func (f *FailFinalExpiryTooSoon) Error() string {
|
||||
return f.Code().String()
|
||||
}
|
||||
|
||||
@ -425,7 +425,7 @@ type FailInvalidOnionVersion struct {
|
||||
// Returns a human readable string describing the target FailureMessage.
|
||||
//
|
||||
// NOTE: Implements the error interface.
|
||||
func (f FailInvalidOnionVersion) Error() string {
|
||||
func (f *FailInvalidOnionVersion) Error() string {
|
||||
return fmt.Sprintf("InvalidOnionVersion(onion_sha=%x)", f.OnionSHA256[:])
|
||||
}
|
||||
|
||||
@ -492,7 +492,7 @@ func (f *FailInvalidOnionHmac) Encode(w io.Writer, pver uint32) error {
|
||||
// Returns a human readable string describing the target FailureMessage.
|
||||
//
|
||||
// NOTE: Implements the error interface.
|
||||
func (f FailInvalidOnionHmac) Error() string {
|
||||
func (f *FailInvalidOnionHmac) Error() string {
|
||||
return fmt.Sprintf("InvalidOnionHMAC(onion_sha=%x)", f.OnionSHA256[:])
|
||||
}
|
||||
|
||||
@ -534,7 +534,7 @@ func (f *FailInvalidOnionKey) Encode(w io.Writer, pver uint32) error {
|
||||
// Returns a human readable string describing the target FailureMessage.
|
||||
//
|
||||
// NOTE: Implements the error interface.
|
||||
func (f FailInvalidOnionKey) Error() string {
|
||||
func (f *FailInvalidOnionKey) Error() string {
|
||||
return fmt.Sprintf("InvalidOnionKey(onion_sha=%x)", f.OnionSHA256[:])
|
||||
}
|
||||
|
||||
@ -604,7 +604,7 @@ func (f *FailTemporaryChannelFailure) Code() FailCode {
|
||||
// Returns a human readable string describing the target FailureMessage.
|
||||
//
|
||||
// NOTE: Implements the error interface.
|
||||
func (f FailTemporaryChannelFailure) Error() string {
|
||||
func (f *FailTemporaryChannelFailure) Error() string {
|
||||
if f.Update == nil {
|
||||
return f.Code().String()
|
||||
}
|
||||
@ -688,7 +688,7 @@ func (f *FailAmountBelowMinimum) Code() FailCode {
|
||||
// Returns a human readable string describing the target FailureMessage.
|
||||
//
|
||||
// NOTE: Implements the error interface.
|
||||
func (f FailAmountBelowMinimum) Error() string {
|
||||
func (f *FailAmountBelowMinimum) Error() string {
|
||||
return fmt.Sprintf("AmountBelowMinimum(amt=%v, update=%v", f.HtlcMsat,
|
||||
spew.Sdump(f.Update))
|
||||
}
|
||||
@ -756,7 +756,7 @@ func (f *FailFeeInsufficient) Code() FailCode {
|
||||
// Returns a human readable string describing the target FailureMessage.
|
||||
//
|
||||
// NOTE: Implements the error interface.
|
||||
func (f FailFeeInsufficient) Error() string {
|
||||
func (f *FailFeeInsufficient) Error() string {
|
||||
return fmt.Sprintf("FeeInsufficient(htlc_amt==%v, update=%v", f.HtlcMsat,
|
||||
spew.Sdump(f.Update))
|
||||
}
|
||||
@ -945,7 +945,7 @@ func (f *FailChannelDisabled) Code() FailCode {
|
||||
// Returns a human readable string describing the target FailureMessage.
|
||||
//
|
||||
// NOTE: Implements the error interface.
|
||||
func (f FailChannelDisabled) Error() string {
|
||||
func (f *FailChannelDisabled) Error() string {
|
||||
return fmt.Sprintf("ChannelDisabled(flags=%v, update=%v", f.Flags,
|
||||
spew.Sdump(f.Update))
|
||||
}
|
||||
@ -993,7 +993,7 @@ type FailFinalIncorrectCltvExpiry struct {
|
||||
// Returns a human readable string describing the target FailureMessage.
|
||||
//
|
||||
// NOTE: Implements the error interface.
|
||||
func (f FailFinalIncorrectCltvExpiry) Error() string {
|
||||
func (f *FailFinalIncorrectCltvExpiry) Error() string {
|
||||
return fmt.Sprintf("FinalIncorrectCltvExpiry(expiry=%v)", f.CltvExpiry)
|
||||
}
|
||||
|
||||
@ -1038,7 +1038,7 @@ type FailFinalIncorrectHtlcAmount struct {
|
||||
// Returns a human readable string describing the target FailureMessage.
|
||||
//
|
||||
// NOTE: Implements the error interface.
|
||||
func (f FailFinalIncorrectHtlcAmount) Error() string {
|
||||
func (f *FailFinalIncorrectHtlcAmount) Error() string {
|
||||
return fmt.Sprintf("FinalIncorrectHtlcAmount(amt=%v)",
|
||||
f.IncomingHTLCAmount)
|
||||
}
|
||||
@ -1081,14 +1081,14 @@ type FailExpiryTooFar struct{}
|
||||
// Code returns the failure unique code.
|
||||
//
|
||||
// NOTE: Part of the FailureMessage interface.
|
||||
func (f FailExpiryTooFar) Code() FailCode {
|
||||
func (f *FailExpiryTooFar) Code() FailCode {
|
||||
return CodeExpiryTooFar
|
||||
}
|
||||
|
||||
// Returns a human readable string describing the target FailureMessage.
|
||||
//
|
||||
// NOTE: Implements the error interface.
|
||||
func (f FailExpiryTooFar) Error() string {
|
||||
func (f *FailExpiryTooFar) Error() string {
|
||||
return f.Code().String()
|
||||
}
|
||||
|
||||
|
@ -177,7 +177,7 @@ func TestFailUnknownPaymentHashOptionalAmount(t *testing.T) {
|
||||
// Creation an error that is a non-pointer will allow us to skip the
|
||||
// type assertion for the Serializable interface. As a result, the
|
||||
// amount body won't be written.
|
||||
onionError := FailUnknownPaymentHash{}
|
||||
onionError := &FailUnknownPaymentHash{}
|
||||
|
||||
var b bytes.Buffer
|
||||
if err := EncodeFailure(&b, onionError, 0); err != nil {
|
||||
@ -189,7 +189,7 @@ func TestFailUnknownPaymentHashOptionalAmount(t *testing.T) {
|
||||
t.Fatalf("unable to decode error: %v", err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(onionError, onionError) {
|
||||
if !reflect.DeepEqual(onionError, onionError2) {
|
||||
t.Fatalf("expected %v, got %v", spew.Sdump(onionError),
|
||||
spew.Sdump(onionError2))
|
||||
}
|
||||
|
@ -386,7 +386,9 @@ type testGraphInstance struct {
|
||||
// a deterministical way and added to the channel graph. A list of nodes is
|
||||
// not required and derived from the channel data. The goal is to keep
|
||||
// instantiating a test channel graph as light weight as possible.
|
||||
func createTestGraphFromChannels(testChannels []*testChannel) (*testGraphInstance, error) {
|
||||
func createTestGraphFromChannels(testChannels []*testChannel, source string) (
|
||||
*testGraphInstance, error) {
|
||||
|
||||
// We'll use this fake address for the IP address of all the nodes in
|
||||
// our tests. This value isn't needed for path finding so it doesn't
|
||||
// need to be unique.
|
||||
@ -444,13 +446,13 @@ func createTestGraphFromChannels(testChannels []*testChannel) (*testGraphInstanc
|
||||
return dbNode, nil
|
||||
}
|
||||
|
||||
var source *channeldb.LightningNode
|
||||
if source, err = addNodeWithAlias("roasbeef"); err != nil {
|
||||
// Add the source node.
|
||||
dbNode, err := addNodeWithAlias(source)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Set the source node
|
||||
if err := graph.SetSourceNode(source); err != nil {
|
||||
if err = graph.SetSourceNode(dbNode); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@ -464,7 +466,10 @@ func createTestGraphFromChannels(testChannels []*testChannel) (*testGraphInstanc
|
||||
|
||||
_, exists := aliasMap[alias]
|
||||
if !exists {
|
||||
addNodeWithAlias(alias)
|
||||
_, err := addNodeWithAlias(alias)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -619,7 +624,9 @@ func TestFindLowestFeePath(t *testing.T) {
|
||||
}),
|
||||
}
|
||||
|
||||
testGraphInstance, err := createTestGraphFromChannels(testChannels)
|
||||
testGraphInstance, err := createTestGraphFromChannels(
|
||||
testChannels, "roasbeef",
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create graph: %v", err)
|
||||
}
|
||||
@ -1367,7 +1374,7 @@ func TestRouteFailMaxHTLC(t *testing.T) {
|
||||
}),
|
||||
}
|
||||
|
||||
graph, err := createTestGraphFromChannels(testChannels)
|
||||
graph, err := createTestGraphFromChannels(testChannels, "roasbeef")
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create graph: %v", err)
|
||||
}
|
||||
@ -1862,7 +1869,9 @@ func TestRestrictOutgoingChannel(t *testing.T) {
|
||||
}),
|
||||
}
|
||||
|
||||
testGraphInstance, err := createTestGraphFromChannels(testChannels)
|
||||
testGraphInstance, err := createTestGraphFromChannels(
|
||||
testChannels, "roasbeef",
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create graph: %v", err)
|
||||
}
|
||||
@ -1957,7 +1966,9 @@ func testCltvLimit(t *testing.T, limit uint32, expectedChannel uint64) {
|
||||
}),
|
||||
}
|
||||
|
||||
testGraphInstance, err := createTestGraphFromChannels(testChannels)
|
||||
testGraphInstance, err := createTestGraphFromChannels(
|
||||
testChannels, "roasbeef",
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create graph: %v", err)
|
||||
}
|
||||
@ -2121,7 +2132,9 @@ func testProbabilityRouting(t *testing.T, p10, p11, p20, minProbability float64,
|
||||
}, 20),
|
||||
}
|
||||
|
||||
testGraphInstance, err := createTestGraphFromChannels(testChannels)
|
||||
testGraphInstance, err := createTestGraphFromChannels(
|
||||
testChannels, "roasbeef",
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create graph: %v", err)
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ import (
|
||||
type errNoRoute struct {
|
||||
// lastError is the error encountered during the last payment attempt,
|
||||
// if at least one attempt has been made.
|
||||
lastError *htlcswitch.ForwardingError
|
||||
lastError error
|
||||
}
|
||||
|
||||
// Error returns a string representation of the error.
|
||||
@ -37,7 +37,7 @@ type paymentLifecycle struct {
|
||||
finalCLTVDelta uint16
|
||||
attempt *channeldb.PaymentAttemptInfo
|
||||
circuit *sphinx.Circuit
|
||||
lastError *htlcswitch.ForwardingError
|
||||
lastError error
|
||||
}
|
||||
|
||||
// resumePayment resumes the paymentLifecycle from the current state.
|
||||
@ -341,25 +341,16 @@ func (p *paymentLifecycle) sendPaymentAttempt(firstHop lnwire.ShortChannelID,
|
||||
// handleSendError inspects the given error from the Switch and determines
|
||||
// whether we should make another payment attempt.
|
||||
func (p *paymentLifecycle) handleSendError(sendErr error) error {
|
||||
var reason channeldb.FailureReason
|
||||
|
||||
// If an internal, non-forwarding error occurred, we can stop trying.
|
||||
fErr, ok := sendErr.(*htlcswitch.ForwardingError)
|
||||
if !ok {
|
||||
reason = channeldb.FailureReasonError
|
||||
} else {
|
||||
var final bool
|
||||
final, reason = p.router.processSendError(
|
||||
p.paySession, &p.attempt.Route, fErr,
|
||||
)
|
||||
final, reason := p.router.processSendError(
|
||||
p.paySession, &p.attempt.Route, sendErr,
|
||||
)
|
||||
if !final {
|
||||
// Save the forwarding error so it can be returned if
|
||||
// this turns out to be the last attempt.
|
||||
p.lastError = sendErr
|
||||
|
||||
if !final {
|
||||
// Save the forwarding error so it can be returned if
|
||||
// this turns out to be the last attempt.
|
||||
p.lastError = fErr
|
||||
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Debugf("Payment %x failed: final_outcome=%v, raw_err=%v",
|
||||
|
@ -1812,22 +1812,58 @@ func (r *ChannelRouter) sendPayment(
|
||||
// to continue with an alternative route. This is indicated by the boolean
|
||||
// return value.
|
||||
func (r *ChannelRouter) processSendError(paySession PaymentSession,
|
||||
rt *route.Route, fErr *htlcswitch.ForwardingError) (
|
||||
bool, channeldb.FailureReason) {
|
||||
rt *route.Route, sendErr error) (bool, channeldb.FailureReason) {
|
||||
|
||||
errSource := fErr.ErrorSource
|
||||
errVertex := route.NewVertex(errSource)
|
||||
// If the failure message could not be decrypted, attribute the failure
|
||||
// to our own outgoing channel.
|
||||
//
|
||||
// TODO(joostager): Penalize all channels in the route.
|
||||
if sendErr == htlcswitch.ErrUnreadableFailureMessage {
|
||||
sendErr = &htlcswitch.ForwardingError{
|
||||
FailureSourceIdx: 0,
|
||||
FailureMessage: lnwire.NewTemporaryChannelFailure(nil),
|
||||
}
|
||||
}
|
||||
|
||||
log.Tracef("node=%x reported failure when sending htlc", errVertex)
|
||||
// If an internal, non-forwarding error occurred, we can stop trying.
|
||||
fErr, ok := sendErr.(*htlcswitch.ForwardingError)
|
||||
if !ok {
|
||||
return true, channeldb.FailureReasonError
|
||||
}
|
||||
|
||||
var (
|
||||
failureSourceIdx = fErr.FailureSourceIdx
|
||||
|
||||
failureVertex route.Vertex
|
||||
failureSource *btcec.PublicKey
|
||||
err error
|
||||
)
|
||||
|
||||
// For any non-self failure, look up the source pub key in the hops
|
||||
// slice. Otherwise return the self node pubkey.
|
||||
if failureSourceIdx > 0 {
|
||||
failureVertex = rt.Hops[failureSourceIdx-1].PubKeyBytes
|
||||
failureSource, err = btcec.ParsePubKey(failureVertex[:], btcec.S256())
|
||||
if err != nil {
|
||||
log.Errorf("Cannot parse pubkey %v: %v",
|
||||
failureVertex, err)
|
||||
|
||||
return true, channeldb.FailureReasonError
|
||||
}
|
||||
} else {
|
||||
failureVertex = r.selfNode.PubKeyBytes
|
||||
failureSource, err = r.selfNode.PubKey()
|
||||
if err != nil {
|
||||
log.Errorf("Cannot parse self pubkey: %v", err)
|
||||
return true, channeldb.FailureReasonError
|
||||
}
|
||||
}
|
||||
log.Tracef("Node %x (index %v) reported failure when sending htlc",
|
||||
failureVertex, failureSourceIdx)
|
||||
|
||||
// Always determine chan id ourselves, because a channel
|
||||
// update with id may not be available.
|
||||
failedEdge, failedAmt, err := getFailedEdge(
|
||||
rt, route.Vertex(errVertex),
|
||||
)
|
||||
if err != nil {
|
||||
return true, channeldb.FailureReasonError
|
||||
}
|
||||
failedEdge, failedAmt := getFailedEdge(rt, failureSourceIdx)
|
||||
|
||||
// processChannelUpdateAndRetry is a closure that
|
||||
// handles a failure message containing a channel
|
||||
@ -1919,8 +1955,8 @@ func (r *ChannelRouter) processSendError(paySession PaymentSession,
|
||||
// that sent us this error, as it doesn't now what the
|
||||
// correct block height is.
|
||||
case *lnwire.FailExpiryTooSoon:
|
||||
r.applyChannelUpdate(&onionErr.Update, errSource)
|
||||
paySession.ReportVertexFailure(errVertex)
|
||||
r.applyChannelUpdate(&onionErr.Update, failureSource)
|
||||
paySession.ReportVertexFailure(failureVertex)
|
||||
return false, 0
|
||||
|
||||
// If we hit an instance of onion payload corruption or an invalid
|
||||
@ -1941,7 +1977,7 @@ func (r *ChannelRouter) processSendError(paySession PaymentSession,
|
||||
// routing.
|
||||
case *lnwire.FailAmountBelowMinimum:
|
||||
processChannelUpdateAndRetry(
|
||||
&onionErr.Update, errSource,
|
||||
&onionErr.Update, failureSource,
|
||||
)
|
||||
return false, 0
|
||||
|
||||
@ -1950,7 +1986,7 @@ func (r *ChannelRouter) processSendError(paySession PaymentSession,
|
||||
// newly updated fees.
|
||||
case *lnwire.FailFeeInsufficient:
|
||||
processChannelUpdateAndRetry(
|
||||
&onionErr.Update, errSource,
|
||||
&onionErr.Update, failureSource,
|
||||
)
|
||||
return false, 0
|
||||
|
||||
@ -1959,7 +1995,7 @@ func (r *ChannelRouter) processSendError(paySession PaymentSession,
|
||||
// apply the new delta value and try it once more.
|
||||
case *lnwire.FailIncorrectCltvExpiry:
|
||||
processChannelUpdateAndRetry(
|
||||
&onionErr.Update, errSource,
|
||||
&onionErr.Update, failureSource,
|
||||
)
|
||||
return false, 0
|
||||
|
||||
@ -1967,7 +2003,7 @@ func (r *ChannelRouter) processSendError(paySession PaymentSession,
|
||||
// forward one is currently disabled, so we'll apply
|
||||
// the update and continue.
|
||||
case *lnwire.FailChannelDisabled:
|
||||
r.applyChannelUpdate(&onionErr.Update, errSource)
|
||||
r.applyChannelUpdate(&onionErr.Update, failureSource)
|
||||
paySession.ReportEdgeFailure(failedEdge, 0)
|
||||
return false, 0
|
||||
|
||||
@ -1975,7 +2011,7 @@ func (r *ChannelRouter) processSendError(paySession PaymentSession,
|
||||
// sufficient capacity, so we'll prune this edge for
|
||||
// now, and continue onwards with our path finding.
|
||||
case *lnwire.FailTemporaryChannelFailure:
|
||||
r.applyChannelUpdate(onionErr.Update, errSource)
|
||||
r.applyChannelUpdate(onionErr.Update, failureSource)
|
||||
paySession.ReportEdgeFailure(failedEdge, failedAmt)
|
||||
return false, 0
|
||||
|
||||
@ -1983,14 +2019,14 @@ func (r *ChannelRouter) processSendError(paySession PaymentSession,
|
||||
// required features, then we'll note this error and
|
||||
// continue.
|
||||
case *lnwire.FailRequiredNodeFeatureMissing:
|
||||
paySession.ReportVertexFailure(errVertex)
|
||||
paySession.ReportVertexFailure(failureVertex)
|
||||
return false, 0
|
||||
|
||||
// If the send fail due to a node not having the
|
||||
// required features, then we'll note this error and
|
||||
// continue.
|
||||
case *lnwire.FailRequiredChannelFeatureMissing:
|
||||
paySession.ReportVertexFailure(errVertex)
|
||||
paySession.ReportVertexFailure(failureVertex)
|
||||
return false, 0
|
||||
|
||||
// If the next hop in the route wasn't known or
|
||||
@ -2008,11 +2044,11 @@ func (r *ChannelRouter) processSendError(paySession PaymentSession,
|
||||
// reason, then we'll note this and continue with the
|
||||
// routes.
|
||||
case *lnwire.FailTemporaryNodeFailure:
|
||||
paySession.ReportVertexFailure(errVertex)
|
||||
paySession.ReportVertexFailure(failureVertex)
|
||||
return false, 0
|
||||
|
||||
case *lnwire.FailPermanentNodeFailure:
|
||||
paySession.ReportVertexFailure(errVertex)
|
||||
paySession.ReportVertexFailure(failureVertex)
|
||||
return false, 0
|
||||
|
||||
// If we crafted a route that contains a too long time
|
||||
@ -2025,7 +2061,7 @@ func (r *ChannelRouter) processSendError(paySession PaymentSession,
|
||||
// that as a hint during future path finding through
|
||||
// that node.
|
||||
case *lnwire.FailExpiryTooFar:
|
||||
paySession.ReportVertexFailure(errVertex)
|
||||
paySession.ReportVertexFailure(failureVertex)
|
||||
return false, 0
|
||||
|
||||
// If we get a permanent channel or node failure, then
|
||||
@ -2040,51 +2076,51 @@ func (r *ChannelRouter) processSendError(paySession PaymentSession,
|
||||
}, 0)
|
||||
return false, 0
|
||||
|
||||
// Any other failure or an empty failure will get the node pruned.
|
||||
default:
|
||||
return true, channeldb.FailureReasonError
|
||||
paySession.ReportVertexFailure(failureVertex)
|
||||
return false, 0
|
||||
}
|
||||
}
|
||||
|
||||
// getFailedEdge tries to locate the failing channel given a route and the
|
||||
// pubkey of the node that sent the error. It will assume that the error is
|
||||
// associated with the outgoing channel of the error node. As a second result,
|
||||
// pubkey of the node that sent the failure. It will assume that the failure is
|
||||
// associated with the outgoing channel of the failing node. As a second result,
|
||||
// it returns the amount sent over the edge.
|
||||
func getFailedEdge(route *route.Route, errSource route.Vertex) (edge,
|
||||
lnwire.MilliSatoshi, error) {
|
||||
func getFailedEdge(route *route.Route, failureSource int) (edge,
|
||||
lnwire.MilliSatoshi) {
|
||||
|
||||
hopCount := len(route.Hops)
|
||||
fromNode := route.SourcePubKey
|
||||
amt := route.TotalAmount
|
||||
for i, hop := range route.Hops {
|
||||
toNode := hop.PubKeyBytes
|
||||
|
||||
// Determine if we have a failure from the final hop.
|
||||
//
|
||||
// TODO(joostjager): In this case, certain types of errors are
|
||||
// not expected. For example FailUnknownNextPeer. This could be
|
||||
// a reason to prune the node?
|
||||
finalHopFailing := i == hopCount-1 && errSource == toNode
|
||||
|
||||
// As this error indicates that the target channel was unable to
|
||||
// carry this HTLC (for w/e reason), we'll return the _outgoing_
|
||||
// channel that the source of the error was meant to pass the
|
||||
// HTLC along to.
|
||||
//
|
||||
// If the errSource is the final hop, we assume that the failing
|
||||
// channel is the incoming channel.
|
||||
if errSource == fromNode || finalHopFailing {
|
||||
return edge{
|
||||
from: fromNode,
|
||||
to: toNode,
|
||||
channel: hop.ChannelID,
|
||||
}, amt, nil
|
||||
}
|
||||
|
||||
fromNode = toNode
|
||||
amt = hop.AmtToForward
|
||||
// Determine if we have a failure from the final hop. If it is, we
|
||||
// assume that the failing channel is the incoming channel. In this
|
||||
// function the outgoing channel of the hop indicated by failureSource
|
||||
// is returned, where index zero is the self node. By decrementing
|
||||
// failureSource by one, the outgoing channel of the penultimate hop is
|
||||
// returned, which is the same as the incoming channel of the final
|
||||
// node.
|
||||
//
|
||||
// TODO(joostjager): In this case, certain types of failures are not
|
||||
// expected. For example FailUnknownNextPeer. This could be a reason to
|
||||
// prune the node?
|
||||
if failureSource == len(route.Hops) {
|
||||
failureSource--
|
||||
}
|
||||
|
||||
return edge{}, 0, fmt.Errorf("cannot find error source node in route")
|
||||
// As this failure indicates that the target channel was unable to carry
|
||||
// this HTLC (for w/e reason), we'll return the _outgoing_ channel that
|
||||
// the source of the failure was meant to pass the HTLC along to.
|
||||
if failureSource == 0 {
|
||||
return edge{
|
||||
from: route.SourcePubKey,
|
||||
to: route.Hops[0].PubKeyBytes,
|
||||
channel: route.Hops[0].ChannelID,
|
||||
}, route.TotalAmount
|
||||
}
|
||||
|
||||
return edge{
|
||||
from: route.Hops[failureSource-1].PubKeyBytes,
|
||||
to: route.Hops[failureSource].PubKeyBytes,
|
||||
channel: route.Hops[failureSource].ChannelID,
|
||||
}, route.Hops[failureSource-1].AmtToForward
|
||||
}
|
||||
|
||||
// applyChannelUpdate validates a channel update and if valid, applies it to the
|
||||
|
@ -265,8 +265,6 @@ func TestSendPaymentRouteFailureFallback(t *testing.T) {
|
||||
var preImage [32]byte
|
||||
copy(preImage[:], bytes.Repeat([]byte{9}, 32))
|
||||
|
||||
sourceNode := ctx.router.selfNode
|
||||
|
||||
// We'll modify the SendToSwitch method that's been set within the
|
||||
// router's configuration to ignore the path that has luo ji as the
|
||||
// first hop. This should force the router to instead take the
|
||||
@ -276,12 +274,8 @@ func TestSendPaymentRouteFailureFallback(t *testing.T) {
|
||||
|
||||
roasbeefLuoji := lnwire.NewShortChanIDFromInt(689530843)
|
||||
if firstHop == roasbeefLuoji {
|
||||
pub, err := sourceNode.PubKey()
|
||||
if err != nil {
|
||||
return preImage, err
|
||||
}
|
||||
return [32]byte{}, &htlcswitch.ForwardingError{
|
||||
ErrorSource: pub,
|
||||
FailureSourceIdx: 0,
|
||||
// TODO(roasbeef): temp node failure should be?
|
||||
FailureMessage: &lnwire.FailTemporaryChannelFailure{},
|
||||
}
|
||||
@ -342,7 +336,7 @@ func TestChannelUpdateValidation(t *testing.T) {
|
||||
}, 2),
|
||||
}
|
||||
|
||||
testGraph, err := createTestGraphFromChannels(testChannels)
|
||||
testGraph, err := createTestGraphFromChannels(testChannels, "a")
|
||||
defer testGraph.cleanUp()
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create graph: %v", err)
|
||||
@ -410,17 +404,8 @@ func TestChannelUpdateValidation(t *testing.T) {
|
||||
// The unsigned channel update is attached to the failure message.
|
||||
ctx.router.cfg.Payer.(*mockPaymentAttemptDispatcher).setPaymentResult(
|
||||
func(firstHop lnwire.ShortChannelID) ([32]byte, error) {
|
||||
|
||||
v := ctx.aliases["b"]
|
||||
source, err := btcec.ParsePubKey(
|
||||
v[:], btcec.S256(),
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
return [32]byte{}, &htlcswitch.ForwardingError{
|
||||
ErrorSource: source,
|
||||
FailureSourceIdx: 1,
|
||||
FailureMessage: &lnwire.FailFeeInsufficient{
|
||||
Update: errChanUpdate,
|
||||
},
|
||||
@ -533,9 +518,6 @@ func TestSendPaymentErrorRepeatedFeeInsufficient(t *testing.T) {
|
||||
FeeRate: uint32(edgeUpdateToFail.FeeProportionalMillionths),
|
||||
}
|
||||
|
||||
// The error will be returned by Son Goku.
|
||||
sourceNode := ctx.aliases["songoku"]
|
||||
|
||||
// We'll now modify the SendToSwitch method to return an error for the
|
||||
// outgoing channel to Son goku. This will be a fee related error, so
|
||||
// it should only cause the edge to be pruned after the second attempt.
|
||||
@ -544,15 +526,8 @@ func TestSendPaymentErrorRepeatedFeeInsufficient(t *testing.T) {
|
||||
|
||||
roasbeefSongoku := lnwire.NewShortChanIDFromInt(chanID)
|
||||
if firstHop == roasbeefSongoku {
|
||||
sourceKey, err := btcec.ParsePubKey(
|
||||
sourceNode[:], btcec.S256(),
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
return [32]byte{}, &htlcswitch.ForwardingError{
|
||||
ErrorSource: sourceKey,
|
||||
FailureSourceIdx: 1,
|
||||
|
||||
// Within our error, we'll add a channel update
|
||||
// which is meant to reflect he new fee
|
||||
@ -647,9 +622,6 @@ func TestSendPaymentErrorNonFinalTimeLockErrors(t *testing.T) {
|
||||
FeeRate: uint32(edgeUpdateToFail.FeeProportionalMillionths),
|
||||
}
|
||||
|
||||
// The error will be returned by Son Goku.
|
||||
sourceNode := ctx.aliases["songoku"]
|
||||
|
||||
// We'll now modify the SendToSwitch method to return an error for the
|
||||
// outgoing channel to son goku. Since this is a time lock related
|
||||
// error, we should fail the payment flow all together, as Goku is the
|
||||
@ -658,15 +630,8 @@ func TestSendPaymentErrorNonFinalTimeLockErrors(t *testing.T) {
|
||||
func(firstHop lnwire.ShortChannelID) ([32]byte, error) {
|
||||
|
||||
if firstHop == roasbeefSongoku {
|
||||
sourceKey, err := btcec.ParsePubKey(
|
||||
sourceNode[:], btcec.S256(),
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
return [32]byte{}, &htlcswitch.ForwardingError{
|
||||
ErrorSource: sourceKey,
|
||||
FailureSourceIdx: 1,
|
||||
FailureMessage: &lnwire.FailExpiryTooSoon{
|
||||
Update: errChanUpdate,
|
||||
},
|
||||
@ -719,15 +684,8 @@ func TestSendPaymentErrorNonFinalTimeLockErrors(t *testing.T) {
|
||||
func(firstHop lnwire.ShortChannelID) ([32]byte, error) {
|
||||
|
||||
if firstHop == roasbeefSongoku {
|
||||
sourceKey, err := btcec.ParsePubKey(
|
||||
sourceNode[:], btcec.S256(),
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
return [32]byte{}, &htlcswitch.ForwardingError{
|
||||
ErrorSource: sourceKey,
|
||||
FailureSourceIdx: 1,
|
||||
FailureMessage: &lnwire.FailIncorrectCltvExpiry{
|
||||
Update: errChanUpdate,
|
||||
},
|
||||
@ -776,16 +734,6 @@ func TestSendPaymentErrorPathPruning(t *testing.T) {
|
||||
var preImage [32]byte
|
||||
copy(preImage[:], bytes.Repeat([]byte{9}, 32))
|
||||
|
||||
sourceNode, err := ctx.graph.SourceNode()
|
||||
if err != nil {
|
||||
t.Fatalf("unable to fetch source node: %v", err)
|
||||
}
|
||||
|
||||
sourcePub, err := sourceNode.PubKey()
|
||||
if err != nil {
|
||||
t.Fatalf("unable to fetch source node pub: %v", err)
|
||||
}
|
||||
|
||||
roasbeefLuoji := lnwire.NewShortChanIDFromInt(689530843)
|
||||
|
||||
// First, we'll modify the SendToSwitch method to return an error
|
||||
@ -802,8 +750,8 @@ func TestSendPaymentErrorPathPruning(t *testing.T) {
|
||||
// outgoing link to simulate the channel from luo ji to
|
||||
// roasbeef not having enough capacity.
|
||||
return [32]byte{}, &htlcswitch.ForwardingError{
|
||||
ErrorSource: sourcePub,
|
||||
FailureMessage: &lnwire.FailTemporaryChannelFailure{},
|
||||
FailureSourceIdx: 0,
|
||||
FailureMessage: &lnwire.FailTemporaryChannelFailure{},
|
||||
}
|
||||
}
|
||||
|
||||
@ -812,17 +760,9 @@ func TestSendPaymentErrorPathPruning(t *testing.T) {
|
||||
// prune out the rest of the routes.
|
||||
roasbeefSatoshi := lnwire.NewShortChanIDFromInt(2340213491)
|
||||
if firstHop == roasbeefSatoshi {
|
||||
vertex := ctx.aliases["satoshi"]
|
||||
key, err := btcec.ParsePubKey(
|
||||
vertex[:], btcec.S256(),
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
return [32]byte{}, &htlcswitch.ForwardingError{
|
||||
ErrorSource: key,
|
||||
FailureMessage: &lnwire.FailUnknownNextPeer{},
|
||||
FailureSourceIdx: 1,
|
||||
FailureMessage: &lnwire.FailUnknownNextPeer{},
|
||||
}
|
||||
}
|
||||
|
||||
@ -854,8 +794,8 @@ func TestSendPaymentErrorPathPruning(t *testing.T) {
|
||||
|
||||
if firstHop == roasbeefLuoji {
|
||||
return [32]byte{}, &htlcswitch.ForwardingError{
|
||||
ErrorSource: sourcePub,
|
||||
FailureMessage: &lnwire.FailUnknownNextPeer{},
|
||||
FailureSourceIdx: 0,
|
||||
FailureMessage: &lnwire.FailUnknownNextPeer{},
|
||||
}
|
||||
}
|
||||
|
||||
@ -900,8 +840,8 @@ func TestSendPaymentErrorPathPruning(t *testing.T) {
|
||||
// outgoing link to simulate the channel from luo ji to
|
||||
// roasbeef not having enough capacity.
|
||||
return [32]byte{}, &htlcswitch.ForwardingError{
|
||||
ErrorSource: sourcePub,
|
||||
FailureMessage: &lnwire.FailTemporaryChannelFailure{},
|
||||
FailureSourceIdx: 0,
|
||||
FailureMessage: &lnwire.FailTemporaryChannelFailure{},
|
||||
}
|
||||
}
|
||||
return preImage, nil
|
||||
@ -1039,7 +979,9 @@ func TestIgnoreChannelEdgePolicyForUnknownChannel(t *testing.T) {
|
||||
|
||||
// Setup an initially empty network.
|
||||
testChannels := []*testChannel{}
|
||||
testGraph, err := createTestGraphFromChannels(testChannels)
|
||||
testGraph, err := createTestGraphFromChannels(
|
||||
testChannels, "roasbeef",
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create graph: %v", err)
|
||||
}
|
||||
@ -2027,7 +1969,7 @@ func TestPruneChannelGraphStaleEdges(t *testing.T) {
|
||||
|
||||
// We'll create our test graph and router backed with these test
|
||||
// channels we've created.
|
||||
testGraph, err := createTestGraphFromChannels(testChannels)
|
||||
testGraph, err := createTestGraphFromChannels(testChannels, "a")
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create test graph: %v", err)
|
||||
}
|
||||
@ -2064,6 +2006,14 @@ func TestPruneChannelGraphDoubleDisabled(t *testing.T) {
|
||||
// according to that heuristic.
|
||||
timestamp := time.Now()
|
||||
testChannels := []*testChannel{
|
||||
// Channel from self shouldn't be pruned.
|
||||
symmetricTestChannel(
|
||||
"self", "a", 100000, &testChannelPolicy{
|
||||
LastUpdate: timestamp,
|
||||
Disabled: true,
|
||||
}, 99,
|
||||
),
|
||||
|
||||
// No edges.
|
||||
{
|
||||
Node1: &testChannelEnd{Alias: "a"},
|
||||
@ -2135,7 +2085,7 @@ func TestPruneChannelGraphDoubleDisabled(t *testing.T) {
|
||||
|
||||
// We'll create our test graph and router backed with these test
|
||||
// channels we've created.
|
||||
testGraph, err := createTestGraphFromChannels(testChannels)
|
||||
testGraph, err := createTestGraphFromChannels(testChannels, "self")
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create test graph: %v", err)
|
||||
}
|
||||
@ -2475,6 +2425,120 @@ func TestEmptyRoutesGenerateSphinxPacket(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestUnknownErrorSource tests that if the source of an error is unknown, all
|
||||
// edges along the route will be pruned.
|
||||
func TestUnknownErrorSource(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// Setup a network. It contains two paths to c: a->b->c and an
|
||||
// alternative a->d->c.
|
||||
chanCapSat := btcutil.Amount(100000)
|
||||
testChannels := []*testChannel{
|
||||
symmetricTestChannel("a", "b", chanCapSat, &testChannelPolicy{
|
||||
Expiry: 144,
|
||||
FeeRate: 400,
|
||||
MinHTLC: 1,
|
||||
MaxHTLC: lnwire.NewMSatFromSatoshis(chanCapSat),
|
||||
}, 1),
|
||||
symmetricTestChannel("b", "c", chanCapSat, &testChannelPolicy{
|
||||
Expiry: 144,
|
||||
FeeRate: 400,
|
||||
MinHTLC: 1,
|
||||
MaxHTLC: lnwire.NewMSatFromSatoshis(chanCapSat),
|
||||
}, 3),
|
||||
symmetricTestChannel("a", "d", chanCapSat, &testChannelPolicy{
|
||||
Expiry: 144,
|
||||
FeeRate: 400,
|
||||
FeeBaseMsat: 100000,
|
||||
MinHTLC: 1,
|
||||
MaxHTLC: lnwire.NewMSatFromSatoshis(chanCapSat),
|
||||
}, 2),
|
||||
symmetricTestChannel("d", "c", chanCapSat, &testChannelPolicy{
|
||||
Expiry: 144,
|
||||
FeeRate: 400,
|
||||
FeeBaseMsat: 100000,
|
||||
MinHTLC: 1,
|
||||
MaxHTLC: lnwire.NewMSatFromSatoshis(chanCapSat),
|
||||
}, 4),
|
||||
}
|
||||
|
||||
testGraph, err := createTestGraphFromChannels(testChannels, "a")
|
||||
defer testGraph.cleanUp()
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create graph: %v", err)
|
||||
}
|
||||
|
||||
const startingBlockHeight = 101
|
||||
|
||||
ctx, cleanUp, err := createTestCtxFromGraphInstance(startingBlockHeight,
|
||||
testGraph)
|
||||
|
||||
defer cleanUp()
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create router: %v", err)
|
||||
}
|
||||
|
||||
// Create a payment to node c.
|
||||
payment := LightningPayment{
|
||||
Target: ctx.aliases["c"],
|
||||
Amount: lnwire.NewMSatFromSatoshis(1000),
|
||||
FeeLimit: noFeeLimit,
|
||||
PaymentHash: lntypes.Hash{},
|
||||
}
|
||||
|
||||
// We'll modify the SendToSwitch method so that it simulates hop b as a
|
||||
// node that returns an unparsable failure if approached via the a->b
|
||||
// channel.
|
||||
ctx.router.cfg.Payer.(*mockPaymentAttemptDispatcher).setPaymentResult(
|
||||
func(firstHop lnwire.ShortChannelID) ([32]byte, error) {
|
||||
|
||||
// If channel a->b is used, return an error without
|
||||
// source and message. The sender won't know the origin
|
||||
// of the error.
|
||||
if firstHop.ToUint64() == 1 {
|
||||
return [32]byte{},
|
||||
htlcswitch.ErrUnreadableFailureMessage
|
||||
}
|
||||
|
||||
// Otherwise the payment succeeds.
|
||||
return lntypes.Preimage{}, nil
|
||||
})
|
||||
|
||||
// Send off the payment request to the router. The expectation is that
|
||||
// the route a->b->c is tried first. An unreadable faiure is returned
|
||||
// which should pruning the channel a->b. We expect the payment to
|
||||
// succeed via a->d.
|
||||
_, _, err = ctx.router.SendPayment(&payment)
|
||||
if err != nil {
|
||||
t.Fatalf("expected payment to succeed, but got: %v", err)
|
||||
}
|
||||
|
||||
// Next we modify payment result to return an unknown failure.
|
||||
ctx.router.cfg.Payer.(*mockPaymentAttemptDispatcher).setPaymentResult(
|
||||
func(firstHop lnwire.ShortChannelID) ([32]byte, error) {
|
||||
|
||||
// If channel a->b is used, simulate that the failure
|
||||
// couldn't be decoded (FailureMessage is nil).
|
||||
if firstHop.ToUint64() == 2 {
|
||||
return [32]byte{},
|
||||
&htlcswitch.ForwardingError{
|
||||
FailureSourceIdx: 1,
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise the payment succeeds.
|
||||
return lntypes.Preimage{}, nil
|
||||
})
|
||||
|
||||
// Send off the payment request to the router. We expect the payment to
|
||||
// fail because both routes have been pruned.
|
||||
payment.PaymentHash = lntypes.Hash{1}
|
||||
_, _, err = ctx.router.SendPayment(&payment)
|
||||
if err == nil {
|
||||
t.Fatalf("expected payment to fail")
|
||||
}
|
||||
}
|
||||
|
||||
// assertChannelsPruned ensures that only the given channels are pruned from the
|
||||
// graph out of the set of all channels.
|
||||
func assertChannelsPruned(t *testing.T, graph *channeldb.ChannelGraph,
|
||||
@ -2543,7 +2607,7 @@ func TestRouterPaymentStateMachine(t *testing.T) {
|
||||
}, 2),
|
||||
}
|
||||
|
||||
testGraph, err := createTestGraphFromChannels(testChannels)
|
||||
testGraph, err := createTestGraphFromChannels(testChannels, "a")
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create graph: %v", err)
|
||||
}
|
||||
@ -2938,11 +3002,6 @@ func TestRouterPaymentStateMachine(t *testing.T) {
|
||||
PaymentHash: payHash,
|
||||
}
|
||||
|
||||
errSource, err := btcec.ParsePubKey(hop1[:], btcec.S256())
|
||||
if err != nil {
|
||||
t.Fatalf("unable to fetch source node pub: %v", err)
|
||||
}
|
||||
|
||||
copy(preImage[:], bytes.Repeat([]byte{9}, 32))
|
||||
|
||||
router.cfg.MissionControl = &mockPaymentSessionSource{
|
||||
@ -3020,8 +3079,8 @@ func TestRouterPaymentStateMachine(t *testing.T) {
|
||||
case sendToSwitchResultFailure:
|
||||
select {
|
||||
case sendResult <- &htlcswitch.ForwardingError{
|
||||
ErrorSource: errSource,
|
||||
FailureMessage: &lnwire.FailTemporaryChannelFailure{},
|
||||
FailureSourceIdx: 1,
|
||||
FailureMessage: &lnwire.FailTemporaryChannelFailure{},
|
||||
}:
|
||||
case <-time.After(1 * time.Second):
|
||||
t.Fatalf("unable to send result")
|
||||
@ -3046,8 +3105,8 @@ func TestRouterPaymentStateMachine(t *testing.T) {
|
||||
select {
|
||||
case getPaymentResult <- &htlcswitch.PaymentResult{
|
||||
Error: &htlcswitch.ForwardingError{
|
||||
ErrorSource: errSource,
|
||||
FailureMessage: &lnwire.FailTemporaryChannelFailure{},
|
||||
FailureSourceIdx: 1,
|
||||
FailureMessage: &lnwire.FailTemporaryChannelFailure{},
|
||||
},
|
||||
}:
|
||||
case <-time.After(1 * time.Second):
|
||||
@ -3164,7 +3223,7 @@ func TestSendToRouteStructuredError(t *testing.T) {
|
||||
}, 2),
|
||||
}
|
||||
|
||||
testGraph, err := createTestGraphFromChannels(testChannels)
|
||||
testGraph, err := createTestGraphFromChannels(testChannels, "a")
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create graph: %v", err)
|
||||
}
|
||||
@ -3214,17 +3273,8 @@ func TestSendToRouteStructuredError(t *testing.T) {
|
||||
// The unsigned channel update is attached to the failure message.
|
||||
ctx.router.cfg.Payer.(*mockPaymentAttemptDispatcher).setPaymentResult(
|
||||
func(firstHop lnwire.ShortChannelID) ([32]byte, error) {
|
||||
|
||||
v := ctx.aliases["b"]
|
||||
source, err := btcec.ParsePubKey(
|
||||
v[:], btcec.S256(),
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
return [32]byte{}, &htlcswitch.ForwardingError{
|
||||
ErrorSource: source,
|
||||
FailureSourceIdx: 1,
|
||||
FailureMessage: &lnwire.FailFeeInsufficient{
|
||||
Update: lnwire.ChannelUpdate{},
|
||||
},
|
||||
|
@ -409,8 +409,7 @@ func newServer(listenAddrs []net.Addr, chanDB *channeldb.DB,
|
||||
}
|
||||
|
||||
s.htlcSwitch, err = htlcswitch.New(htlcswitch.Config{
|
||||
DB: chanDB,
|
||||
SelfKey: s.identityPriv.PubKey(),
|
||||
DB: chanDB,
|
||||
LocalChannelClose: func(pubKey []byte,
|
||||
request *htlcswitch.ChanClose) {
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user