diff --git a/go.mod b/go.mod index 5f39f0b9e..ef704a0f8 100644 --- a/go.mod +++ b/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 diff --git a/go.sum b/go.sum index ef56979b0..1c69b0767 100644 --- a/go.sum +++ b/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= diff --git a/htlcswitch/failure.go b/htlcswitch/failure.go index a17517bb7..8309f477c 100644 --- a/htlcswitch/failure.go +++ b/htlcswitch/failure.go @@ -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 } diff --git a/htlcswitch/link.go b/htlcswitch/link.go index 15c65ec4a..b5c66e376 100644 --- a/htlcswitch/link.go +++ b/htlcswitch/link.go @@ -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", diff --git a/htlcswitch/mock.go b/htlcswitch/mock.go index 1f681264a..b5ebfcf8e 100644 --- a/htlcswitch/mock.go +++ b/htlcswitch/mock.go @@ -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 +} diff --git a/htlcswitch/switch.go b/htlcswitch/switch.go index ee2c090a2..8bcd278ee 100644 --- a/htlcswitch/switch.go +++ b/htlcswitch/switch.go @@ -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 diff --git a/htlcswitch/switch_test.go b/htlcswitch/switch_test.go index 6a0a24e9d..13f6acc37 100644 --- a/htlcswitch/switch_test.go +++ b/htlcswitch/switch_test.go @@ -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") + } +} diff --git a/lnrpc/routerrpc/router.pb.go b/lnrpc/routerrpc/router.pb.go index 6249d28bc..cba7914d7 100644 --- a/lnrpc/routerrpc/router.pb.go +++ b/lnrpc/routerrpc/router.pb.go @@ -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. diff --git a/lnrpc/routerrpc/router.proto b/lnrpc/routerrpc/router.proto index b2e513176..18f08444a 100644 --- a/lnrpc/routerrpc/router.proto +++ b/lnrpc/routerrpc/router.proto @@ -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; } diff --git a/lnrpc/routerrpc/router_server.go b/lnrpc/routerrpc/router_server.go index 6291a5479..fc5779693 100644 --- a/lnrpc/routerrpc/router_server.go +++ b/lnrpc/routerrpc/router_server.go @@ -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 } diff --git a/lnwire/onion_error.go b/lnwire/onion_error.go index 7e04cc95c..6ea01d52c 100644 --- a/lnwire/onion_error.go +++ b/lnwire/onion_error.go @@ -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() } diff --git a/lnwire/onion_error_test.go b/lnwire/onion_error_test.go index e05bd2a18..9ecb9f1a9 100644 --- a/lnwire/onion_error_test.go +++ b/lnwire/onion_error_test.go @@ -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)) } diff --git a/routing/pathfind_test.go b/routing/pathfind_test.go index 8a5cf0687..88adade42 100644 --- a/routing/pathfind_test.go +++ b/routing/pathfind_test.go @@ -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) } diff --git a/routing/payment_lifecycle.go b/routing/payment_lifecycle.go index cec91e9dd..32f6883ea 100644 --- a/routing/payment_lifecycle.go +++ b/routing/payment_lifecycle.go @@ -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", diff --git a/routing/router.go b/routing/router.go index 00e4d94b0..87bb5c753 100644 --- a/routing/router.go +++ b/routing/router.go @@ -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 diff --git a/routing/router_test.go b/routing/router_test.go index 4a9d885e4..c50dba1c4 100644 --- a/routing/router_test.go +++ b/routing/router_test.go @@ -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{}, }, diff --git a/server.go b/server.go index ed1681885..88204d812 100644 --- a/server.go +++ b/server.go @@ -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) {