htlcswitch+routing+routerrpc: return error source as index

This commit is contained in:
Joost Jager 2019-06-11 10:24:19 +02:00
parent 55bef96cf3
commit 2b47632b26
No known key found for this signature in database
GPG Key ID: A61B9D4C393C59C7
11 changed files with 245 additions and 310 deletions

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

@ -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.
@ -256,19 +257,19 @@ type SphinxErrorDecrypter struct {
// NOTE: Part of the ErrorDecrypter interface.
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)
r := bytes.NewReader(failure.Message)
failureMsg, err := lnwire.DecodeFailure(r, 0)
if err != nil {
return nil, err
}
return &ForwardingError{
ErrorSource: source,
FailureSourceIdx: failure.SenderIdx,
FailureMessage: failureMsg,
}, nil
}

@ -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,11 +390,8 @@ func (o *mockDeobfuscator) DecryptError(reason lnwire.OpaqueReason) (*Forwarding
return nil, err
}
priv, _ := btcec.NewPrivateKey(btcec.S256())
pubkey := priv.PubKey()
return &ForwardingError{
ErrorSource: pubkey,
FailureSourceIdx: 1,
FailureMessage: failure,
}, nil
}

@ -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"
@ -112,11 +111,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,7 +770,7 @@ func (s *Switch) handleLocalDispatch(pkt *htlcPacket) error {
if err != nil {
log.Errorf("Link %v not found", pkt.outgoingChanID)
return &ForwardingError{
ErrorSource: s.cfg.SelfKey,
FailureSourceIdx: 0,
FailureMessage: &lnwire.FailUnknownNextPeer{},
}
}
@ -790,7 +784,7 @@ func (s *Switch) handleLocalDispatch(pkt *htlcPacket) error {
// will be returned back to the router.
htlcErr := lnwire.NewTemporaryChannelFailure(nil)
return &ForwardingError{
ErrorSource: s.cfg.SelfKey,
FailureSourceIdx: 0,
ExtraMsg: err.Error(),
FailureMessage: htlcErr,
}
@ -808,7 +802,7 @@ func (s *Switch) handleLocalDispatch(pkt *htlcPacket) error {
"satisfied", pkt.outgoingChanID)
return &ForwardingError{
ErrorSource: s.cfg.SelfKey,
FailureSourceIdx: 0,
FailureMessage: htlcErr,
}
}
@ -823,7 +817,7 @@ func (s *Switch) handleLocalDispatch(pkt *htlcPacket) error {
// will be returned back to the router.
htlcErr := lnwire.NewTemporaryChannelFailure(nil)
return &ForwardingError{
ErrorSource: s.cfg.SelfKey,
FailureSourceIdx: 0,
ExtraMsg: err.Error(),
FailureMessage: htlcErr,
}
@ -967,7 +961,7 @@ func (s *Switch) parseFailedPayment(deobfuscator ErrorDecrypter,
failureMsg = lnwire.NewTemporaryChannelFailure(nil)
}
failure = &ForwardingError{
ErrorSource: s.cfg.SelfKey,
FailureSourceIdx: 0,
ExtraMsg: userErr,
FailureMessage: failureMsg,
}
@ -981,7 +975,7 @@ func (s *Switch) parseFailedPayment(deobfuscator ErrorDecrypter,
"on-chain, then cancelled back (hash=%v, pid=%d)",
paymentHash, paymentID)
failure = &ForwardingError{
ErrorSource: s.cfg.SelfKey,
FailureSourceIdx: 0,
ExtraMsg: userErr,
FailureMessage: lnwire.FailPermanentChannelFailure{},
}
@ -999,7 +993,7 @@ func (s *Switch) parseFailedPayment(deobfuscator ErrorDecrypter,
paymentHash, paymentID, err)
log.Error(userErr)
failure = &ForwardingError{
ErrorSource: s.cfg.SelfKey,
FailureSourceIdx: 0,
ExtraMsg: userErr,
FailureMessage: lnwire.NewTemporaryChannelFailure(nil),
}

@ -610,10 +610,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.
@ -624,6 +620,10 @@ type Failure struct {
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"`
//*
//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 +661,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 +696,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 +1167,110 @@ 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,
// 1635 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x57, 0x5f, 0x73, 0x22, 0xc7,
0x11, 0x37, 0x02, 0x09, 0xd1, 0xfc, 0xd1, 0x6a, 0xa4, 0xd3, 0xed, 0xa1, 0xd3, 0x59, 0x5e, 0x27,
0x67, 0xd5, 0x95, 0x23, 0x39, 0xa4, 0xce, 0xe5, 0xa7, 0xa4, 0x38, 0x18, 0xcc, 0xfa, 0x60, 0x57,
0x1e, 0xe0, 0xec, 0x4b, 0x1e, 0xa6, 0x46, 0xec, 0x08, 0xb6, 0x04, 0xbb, 0x78, 0x77, 0x70, 0x4e,
0x79, 0xc8, 0x5b, 0x5e, 0x52, 0x95, 0xcf, 0x92, 0x7c, 0x82, 0x7c, 0x8f, 0x7c, 0x95, 0x3c, 0xa5,
0x66, 0x66, 0x81, 0x05, 0xa1, 0x8b, 0x9f, 0xc4, 0xfe, 0xfa, 0xd7, 0x7f, 0xa6, 0x7b, 0xba, 0xa7,
0x05, 0x27, 0x51, 0x38, 0x17, 0x3c, 0x8a, 0x66, 0xc3, 0x2b, 0xfd, 0xeb, 0x72, 0x16, 0x85, 0x22,
0x44, 0x85, 0x25, 0x5e, 0x2d, 0x44, 0xb3, 0xa1, 0x46, 0xad, 0xff, 0xee, 0x00, 0xea, 0xf1, 0xc0,
0xbb, 0x66, 0xf7, 0x53, 0x1e, 0x08, 0xc2, 0x7f, 0x9a, 0xf3, 0x58, 0x20, 0x04, 0x39, 0x8f, 0xc7,
0xc2, 0xcc, 0x9c, 0x67, 0x2e, 0x4a, 0x44, 0xfd, 0x46, 0x06, 0x64, 0xd9, 0x54, 0x98, 0x3b, 0xe7,
0x99, 0x8b, 0x2c, 0x91, 0x3f, 0xd1, 0x67, 0x50, 0x9a, 0x69, 0x3d, 0x3a, 0x66, 0xf1, 0xd8, 0xcc,
0x2a, 0x76, 0x31, 0xc1, 0xda, 0x2c, 0x1e, 0xa3, 0x0b, 0x30, 0x6e, 0xfd, 0x80, 0x4d, 0xe8, 0x70,
0x22, 0x7e, 0xa6, 0x1e, 0x9f, 0x08, 0x66, 0xe6, 0xce, 0x33, 0x17, 0xbb, 0xa4, 0xa2, 0xf0, 0xc6,
0x44, 0xfc, 0xdc, 0x94, 0x28, 0xfa, 0x02, 0x0e, 0x16, 0xc6, 0x22, 0x1d, 0x85, 0xb9, 0x7b, 0x9e,
0xb9, 0x28, 0x90, 0xca, 0x6c, 0x3d, 0xb6, 0x2f, 0xe0, 0x40, 0xf8, 0x53, 0x1e, 0xce, 0x05, 0x8d,
0xf9, 0x30, 0x0c, 0xbc, 0xd8, 0xdc, 0xd3, 0x16, 0x13, 0xb8, 0xa7, 0x51, 0x64, 0x41, 0xf9, 0x96,
0x73, 0x3a, 0xf1, 0xa7, 0xbe, 0xa0, 0x31, 0x13, 0x66, 0x5e, 0x85, 0x5e, 0xbc, 0xe5, 0xbc, 0x23,
0xb1, 0x1e, 0x13, 0x32, 0xbe, 0x70, 0x2e, 0x46, 0xa1, 0x1f, 0x8c, 0xe8, 0x70, 0xcc, 0x02, 0xea,
0x7b, 0xe6, 0xfe, 0x79, 0xe6, 0x22, 0x47, 0x2a, 0x0b, 0xbc, 0x31, 0x66, 0x81, 0xed, 0xa1, 0x33,
0x00, 0x75, 0x06, 0x65, 0xce, 0x2c, 0x28, 0x8f, 0x05, 0x89, 0x28, 0x5b, 0xa8, 0x06, 0x45, 0x95,
0x60, 0x3a, 0xf6, 0x03, 0x11, 0x9b, 0x70, 0x9e, 0xbd, 0x28, 0xd6, 0x8c, 0xcb, 0x49, 0x20, 0x73,
0x4d, 0xa4, 0xa4, 0xed, 0x07, 0x82, 0xa4, 0x49, 0xd6, 0x37, 0x70, 0xd4, 0x8f, 0xd8, 0xf0, 0x6e,
0x23, 0xf9, 0x9b, 0x69, 0xcd, 0x3c, 0x48, 0xab, 0xf5, 0x57, 0x28, 0x27, 0x4a, 0x3d, 0xc1, 0xc4,
0x3c, 0x46, 0xbf, 0x81, 0xdd, 0x58, 0x30, 0xc1, 0x15, 0xb9, 0x52, 0x7b, 0x7a, 0xb9, 0xac, 0xf6,
0x65, 0x8a, 0xc8, 0x89, 0x66, 0xa1, 0x2a, 0xec, 0xcf, 0x22, 0xee, 0x4f, 0xd9, 0x88, 0xab, 0x82,
0x96, 0xc8, 0xf2, 0x1b, 0x59, 0xb0, 0xab, 0x94, 0x55, 0x39, 0x8b, 0xb5, 0x52, 0xfa, 0x0c, 0x44,
0x8b, 0xac, 0xdf, 0xc3, 0x81, 0xfa, 0x6e, 0x71, 0xfe, 0xb1, 0x2b, 0xf3, 0x14, 0xf2, 0x6c, 0xaa,
0x73, 0xaf, 0xaf, 0xcd, 0x1e, 0x9b, 0xca, 0xb4, 0x5b, 0x1e, 0x18, 0x2b, 0xfd, 0x78, 0x16, 0x06,
0x31, 0x97, 0xa5, 0x90, 0xc6, 0x65, 0x25, 0x64, 0xd9, 0xa6, 0x52, 0x2b, 0xa3, 0xb4, 0x2a, 0x09,
0xde, 0xe2, 0xbc, 0x1b, 0x33, 0x81, 0x5e, 0xea, 0x1b, 0x40, 0x27, 0xe1, 0xf0, 0x4e, 0xde, 0x29,
0x76, 0x9f, 0x98, 0x2f, 0x4b, 0xb8, 0x13, 0x0e, 0xef, 0x9a, 0x12, 0xb4, 0xfe, 0xa4, 0xef, 0x76,
0x3f, 0xd4, 0xb1, 0xff, 0xe2, 0xf4, 0xae, 0x52, 0xb0, 0xf3, 0x78, 0x0a, 0x28, 0x1c, 0xad, 0x19,
0x4f, 0x4e, 0x91, 0xce, 0x6c, 0x66, 0x23, 0xb3, 0x5f, 0x42, 0xfe, 0x96, 0xf9, 0x93, 0x79, 0xb4,
0x30, 0x8c, 0x52, 0x65, 0x6a, 0x69, 0x09, 0x59, 0x50, 0xac, 0xbf, 0xe7, 0x21, 0x9f, 0x80, 0xa8,
0x06, 0xb9, 0x61, 0xe8, 0x2d, 0xaa, 0xfb, 0xe2, 0xa1, 0xda, 0xe2, 0x6f, 0x23, 0xf4, 0x38, 0x51,
0x5c, 0xf4, 0x07, 0xa8, 0xc8, 0x1b, 0x1d, 0xf0, 0x09, 0x9d, 0xcf, 0x3c, 0xb6, 0x2c, 0xa8, 0x99,
0xd2, 0x6e, 0x68, 0xc2, 0x40, 0xc9, 0x49, 0x79, 0x98, 0xfe, 0x44, 0xa7, 0x50, 0x18, 0x8b, 0xc9,
0x50, 0x57, 0x22, 0xa7, 0x9a, 0x62, 0x5f, 0x02, 0xaa, 0x06, 0x16, 0x94, 0xc3, 0xc0, 0x0f, 0x03,
0x1a, 0x8f, 0x19, 0xad, 0xbd, 0xfe, 0x5a, 0x35, 0x6b, 0x89, 0x14, 0x15, 0xd8, 0x1b, 0xb3, 0xda,
0xeb, 0xaf, 0xd1, 0xa7, 0x50, 0x54, 0x2d, 0xc3, 0x3f, 0xcc, 0xfc, 0xe8, 0x5e, 0x75, 0x69, 0x99,
0xa8, 0x2e, 0xc2, 0x0a, 0x41, 0xc7, 0xb0, 0x7b, 0x3b, 0x61, 0xa3, 0x58, 0x75, 0x66, 0x99, 0xe8,
0x0f, 0xf4, 0x15, 0x1c, 0x27, 0x39, 0xa0, 0x71, 0x38, 0x8f, 0x86, 0x9c, 0xfa, 0x81, 0xc7, 0x3f,
0xa8, 0xbe, 0x2c, 0x13, 0x94, 0xc8, 0x7a, 0x4a, 0x64, 0x4b, 0x89, 0xf5, 0x9f, 0x1c, 0x14, 0x53,
0x09, 0x40, 0x25, 0xd8, 0x27, 0xb8, 0x87, 0xc9, 0x3b, 0xdc, 0x34, 0x3e, 0x41, 0x26, 0x1c, 0x0f,
0x9c, 0xb7, 0x8e, 0xfb, 0x83, 0x43, 0xaf, 0xeb, 0xef, 0xbb, 0xd8, 0xe9, 0xd3, 0x76, 0xbd, 0xd7,
0x36, 0x32, 0xe8, 0x39, 0x98, 0xb6, 0xd3, 0x70, 0x09, 0xc1, 0x8d, 0xfe, 0x52, 0x56, 0xef, 0xba,
0x03, 0xa7, 0x6f, 0xec, 0xa0, 0x4f, 0xe1, 0xb4, 0x65, 0x3b, 0xf5, 0x0e, 0x5d, 0x71, 0x1a, 0x9d,
0xfe, 0x3b, 0x8a, 0x7f, 0xbc, 0xb6, 0xc9, 0x7b, 0x23, 0xbb, 0x8d, 0xd0, 0xee, 0x77, 0x1a, 0x0b,
0x0b, 0x39, 0xf4, 0x0c, 0x9e, 0x68, 0x82, 0x56, 0xa1, 0x7d, 0xd7, 0xa5, 0x3d, 0xd7, 0x75, 0x8c,
0x5d, 0x74, 0x08, 0x65, 0xdb, 0x79, 0x57, 0xef, 0xd8, 0x4d, 0x4a, 0x70, 0xbd, 0xd3, 0x35, 0xf6,
0xd0, 0x11, 0x1c, 0x6c, 0xf2, 0xf2, 0xd2, 0xc4, 0x82, 0xe7, 0x3a, 0xb6, 0xeb, 0xd0, 0x77, 0x98,
0xf4, 0x6c, 0xd7, 0x31, 0xf6, 0xd1, 0x09, 0xa0, 0x75, 0x51, 0xbb, 0x5b, 0x6f, 0x18, 0x05, 0xf4,
0x04, 0x0e, 0xd7, 0xf1, 0xb7, 0xf8, 0xbd, 0x01, 0x32, 0x0d, 0x3a, 0x30, 0xfa, 0x06, 0x77, 0xdc,
0x1f, 0x68, 0xd7, 0x76, 0xec, 0xee, 0xa0, 0x6b, 0x14, 0xd1, 0x31, 0x18, 0x2d, 0x8c, 0xa9, 0xed,
0xf4, 0x06, 0xad, 0x96, 0xdd, 0xb0, 0xb1, 0xd3, 0x37, 0x4a, 0xda, 0xf3, 0xb6, 0x83, 0x97, 0xa5,
0x42, 0xa3, 0x5d, 0x77, 0x1c, 0xdc, 0xa1, 0x4d, 0xbb, 0x57, 0x7f, 0xd3, 0xc1, 0x4d, 0xa3, 0x82,
0xce, 0xe0, 0x59, 0x1f, 0x77, 0xaf, 0x5d, 0x52, 0x27, 0xef, 0xe9, 0x42, 0xde, 0xaa, 0xdb, 0x9d,
0x01, 0xc1, 0xc6, 0x01, 0xfa, 0x0c, 0xce, 0x08, 0xfe, 0x7e, 0x60, 0x13, 0xdc, 0xa4, 0x8e, 0xdb,
0xc4, 0xb4, 0x85, 0xeb, 0xfd, 0x01, 0xc1, 0xb4, 0x6b, 0xf7, 0x7a, 0xb6, 0xf3, 0xad, 0x61, 0xa0,
0x5f, 0xc1, 0xf9, 0x92, 0xb2, 0x34, 0xb0, 0xc1, 0x3a, 0x94, 0xe7, 0x5b, 0xd4, 0xd3, 0xc1, 0x3f,
0xf6, 0xe9, 0x35, 0xc6, 0xc4, 0x40, 0xa8, 0x0a, 0x27, 0x2b, 0xf7, 0xda, 0x41, 0xe2, 0xfb, 0x48,
0xca, 0xae, 0x31, 0xe9, 0xd6, 0x1d, 0x59, 0xe0, 0x35, 0xd9, 0xb1, 0x0c, 0x7b, 0x25, 0xdb, 0x0c,
0xfb, 0xc9, 0x77, 0xb9, 0xfd, 0x1d, 0x23, 0x6b, 0xfd, 0x33, 0x0b, 0xe5, 0xb5, 0x66, 0x41, 0xcf,
0xa1, 0x10, 0xfb, 0xa3, 0x80, 0x09, 0xd9, 0xce, 0xba, 0xd3, 0x57, 0x80, 0x7a, 0x2d, 0xc6, 0xcc,
0x0f, 0xf4, 0x88, 0xd1, 0x23, 0xb6, 0xa0, 0x10, 0x35, 0x60, 0x9e, 0x42, 0x7e, 0xf1, 0xda, 0x64,
0x55, 0x63, 0xed, 0x0d, 0xf5, 0x2b, 0xf3, 0x1c, 0x0a, 0x72, 0x86, 0xc5, 0x82, 0x4d, 0x67, 0xaa,
0xe7, 0xca, 0x64, 0x05, 0xa0, 0xcf, 0xa1, 0x3c, 0xe5, 0x71, 0xcc, 0x46, 0x9c, 0xea, 0xbe, 0x01,
0xc5, 0x28, 0x25, 0x60, 0x4b, 0xb5, 0xcf, 0xe7, 0xb0, 0xe8, 0xe3, 0x84, 0xb4, 0xab, 0x49, 0x09,
0xa8, 0x49, 0x9b, 0x23, 0x54, 0xb0, 0xa4, 0x3d, 0xd3, 0x23, 0x54, 0x30, 0xf4, 0x0a, 0x0e, 0xf5,
0x0c, 0xf0, 0x03, 0x7f, 0x3a, 0x9f, 0xea, 0x59, 0x90, 0x57, 0x21, 0x1f, 0xa8, 0x59, 0xa0, 0x71,
0x35, 0x12, 0x9e, 0xc1, 0xfe, 0x0d, 0x8b, 0xb9, 0x9c, 0xde, 0x49, 0xaf, 0xe6, 0xe5, 0x77, 0x8b,
0x73, 0x29, 0x92, 0x33, 0x3d, 0x92, 0x53, 0xa8, 0xa0, 0x45, 0xb7, 0x9c, 0x13, 0x99, 0xc7, 0xa5,
0x07, 0xf6, 0x61, 0xe5, 0xa1, 0x98, 0xf2, 0xa0, 0x71, 0xe5, 0xe1, 0x15, 0x1c, 0xf2, 0x0f, 0x22,
0x62, 0x34, 0x9c, 0xb1, 0x9f, 0xe6, 0x9c, 0x7a, 0x4c, 0x30, 0xb3, 0xa4, 0x92, 0x7b, 0xa0, 0x04,
0xae, 0xc2, 0x9b, 0x4c, 0x30, 0xeb, 0x39, 0x54, 0x09, 0x8f, 0xb9, 0xe8, 0xfa, 0x71, 0xec, 0x87,
0x41, 0x23, 0x0c, 0x44, 0x14, 0x4e, 0x92, 0x47, 0xc0, 0x3a, 0x83, 0xd3, 0xad, 0x52, 0x3d, 0xc5,
0xa5, 0xf2, 0xf7, 0x73, 0x1e, 0xdd, 0x6f, 0x57, 0x7e, 0x0b, 0xa7, 0x5b, 0xa5, 0xc9, 0x13, 0xf0,
0x25, 0xec, 0x06, 0xa1, 0xc7, 0x63, 0x33, 0xa3, 0x96, 0x80, 0x93, 0xd4, 0xbc, 0x75, 0x42, 0x8f,
0xb7, 0xfd, 0x58, 0x84, 0xd1, 0x3d, 0xd1, 0x24, 0xeb, 0xdf, 0x19, 0x28, 0xa6, 0x60, 0x74, 0x02,
0x7b, 0xb3, 0xf9, 0xcd, 0x1d, 0xbf, 0x4f, 0x2e, 0x55, 0xf2, 0x85, 0x5e, 0x42, 0x65, 0xc2, 0x62,
0x41, 0xe5, 0xf8, 0xa3, 0xb2, 0x48, 0xc9, 0x9b, 0xb7, 0x81, 0xa2, 0x6f, 0xe0, 0x69, 0x28, 0xc6,
0x3c, 0xd2, 0xeb, 0x4c, 0x3c, 0x1f, 0x0e, 0x79, 0x1c, 0xd3, 0x59, 0x14, 0xde, 0xa8, 0xab, 0xb6,
0x43, 0x1e, 0x13, 0xa3, 0xd7, 0xb0, 0x9f, 0xdc, 0x91, 0xd8, 0xcc, 0xa9, 0xd0, 0x9f, 0x3d, 0x7c,
0x2a, 0x16, 0xd1, 0x2f, 0xa9, 0xd6, 0xbf, 0x32, 0x50, 0x59, 0x17, 0xa2, 0x17, 0xea, 0xf6, 0xab,
0x2b, 0xe8, 0x7b, 0xea, 0x1c, 0x39, 0x92, 0x42, 0x7e, 0xf1, 0x59, 0x6a, 0x70, 0x3c, 0xf5, 0x03,
0x3a, 0xe3, 0x01, 0x9b, 0xf8, 0x7f, 0xe1, 0x74, 0xb1, 0x4c, 0x64, 0x15, 0x7b, 0xab, 0x0c, 0x59,
0x50, 0x5a, 0x3b, 0x74, 0x4e, 0x1d, 0x7a, 0x0d, 0x7b, 0xf5, 0x8f, 0x0c, 0x94, 0xd2, 0x6b, 0x11,
0x2a, 0x43, 0xc1, 0x76, 0x68, 0xab, 0x63, 0x7f, 0xdb, 0xee, 0x1b, 0x9f, 0xc8, 0xcf, 0xde, 0xa0,
0xd1, 0xc0, 0xb8, 0x89, 0x9b, 0x46, 0x06, 0x21, 0xa8, 0xc8, 0x79, 0x80, 0x9b, 0xb4, 0x6f, 0x77,
0xb1, 0x3b, 0x90, 0x8f, 0xc3, 0x11, 0x1c, 0x24, 0x98, 0xe3, 0x52, 0xe2, 0x0e, 0xfa, 0xd8, 0xc8,
0x22, 0x03, 0x4a, 0x09, 0x88, 0x09, 0x71, 0x89, 0x91, 0x93, 0x13, 0x2d, 0x41, 0x1e, 0x3e, 0x34,
0x4d, 0xdc, 0xaf, 0xdb, 0x9d, 0x9e, 0xb1, 0x5b, 0xfb, 0x5b, 0x0e, 0xf6, 0xd4, 0x1a, 0x11, 0xa1,
0x36, 0x14, 0x53, 0xfb, 0x38, 0x3a, 0x4b, 0x55, 0xe0, 0xe1, 0x9e, 0x5e, 0x35, 0xb7, 0xef, 0x79,
0xf3, 0xf8, 0xab, 0x0c, 0xfa, 0x0e, 0x4a, 0xe9, 0xed, 0x12, 0xa5, 0xb7, 0x86, 0x2d, 0x6b, 0xe7,
0x47, 0x6d, 0xbd, 0x05, 0x03, 0xc7, 0xc2, 0x9f, 0xca, 0x2d, 0x21, 0xd9, 0xdb, 0x50, 0x35, 0xc5,
0xdf, 0x58, 0x06, 0xab, 0xa7, 0x5b, 0x65, 0x49, 0x7f, 0x74, 0xf4, 0x11, 0x93, 0xcd, 0xe9, 0xc1,
0x11, 0xd7, 0xd7, 0xb5, 0xea, 0x8b, 0xc7, 0xc4, 0x89, 0x35, 0x0f, 0x8e, 0xb6, 0x74, 0x32, 0xfa,
0x75, 0x3a, 0x82, 0x47, 0xe7, 0x40, 0xf5, 0xe5, 0xff, 0xa3, 0xad, 0xbc, 0x6c, 0x69, 0xf9, 0x35,
0x2f, 0x8f, 0x0f, 0x8c, 0x35, 0x2f, 0x1f, 0x99, 0x1c, 0x6f, 0x7e, 0xfb, 0xc7, 0xab, 0x91, 0x2f,
0xc6, 0xf3, 0x9b, 0xcb, 0x61, 0x38, 0xbd, 0x9a, 0xf8, 0xa3, 0xb1, 0x08, 0xfc, 0x60, 0x14, 0x70,
0xf1, 0xe7, 0x30, 0xba, 0xbb, 0x9a, 0x04, 0xde, 0x95, 0xda, 0x44, 0xaf, 0x96, 0xe6, 0x6e, 0xf6,
0xd4, 0xff, 0x71, 0xbf, 0xfb, 0x5f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x2f, 0xaa, 0x9f, 0x4e, 0xf7,
0x0d, 0x00, 0x00,
}
// Reference imports to suppress errors if they are not otherwise used.

@ -199,11 +199,7 @@ message Failure {
/// 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 +215,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;
}

@ -399,7 +399,7 @@ func marshallError(sendError error) (*Failure, error) {
return nil, errors.New("unknown wire error")
}
response.FailureSourcePubkey = fErr.ErrorSource.SerializeCompressed()
response.FailureSourceIndex = uint32(fErr.FailureSourceIdx)
return response, nil
}

@ -1815,19 +1815,39 @@ func (r *ChannelRouter) processSendError(paySession PaymentSession,
rt *route.Route, fErr *htlcswitch.ForwardingError) (
bool, channeldb.FailureReason) {
errSource := fErr.ErrorSource
errVertex := route.NewVertex(errSource)
var (
failureSourceIdx = fErr.FailureSourceIdx
log.Tracef("node=%x reported failure when sending htlc", errVertex)
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 +1939,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 +1961,7 @@ func (r *ChannelRouter) processSendError(paySession PaymentSession,
// routing.
case *lnwire.FailAmountBelowMinimum:
processChannelUpdateAndRetry(
&onionErr.Update, errSource,
&onionErr.Update, failureSource,
)
return false, 0
@ -1950,7 +1970,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 +1979,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 +1987,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 +1995,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 +2003,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 +2028,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 +2045,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
@ -2046,45 +2066,43 @@ func (r *ChannelRouter) processSendError(paySession PaymentSession,
}
// 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.
// 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 errors are
// not expected. For example FailUnknownNextPeer. This could be
// a reason to prune the node?
finalHopFailing := i == hopCount-1 && errSource == toNode
// 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--
}
// 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 {
// 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: fromNode,
to: toNode,
channel: hop.ChannelID,
}, amt, nil
from: route.SourcePubKey,
to: route.Hops[0].PubKeyBytes,
channel: route.Hops[0].ChannelID,
}, route.TotalAmount
}
fromNode = toNode
amt = hop.AmtToForward
}
return edge{}, 0, fmt.Errorf("cannot find error source node in route")
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{},
}
@ -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,7 +750,7 @@ 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,
FailureSourceIdx: 0,
FailureMessage: &lnwire.FailTemporaryChannelFailure{},
}
}
@ -812,16 +760,8 @@ 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,
FailureSourceIdx: 1,
FailureMessage: &lnwire.FailUnknownNextPeer{},
}
}
@ -854,7 +794,7 @@ func TestSendPaymentErrorPathPruning(t *testing.T) {
if firstHop == roasbeefLuoji {
return [32]byte{}, &htlcswitch.ForwardingError{
ErrorSource: sourcePub,
FailureSourceIdx: 0,
FailureMessage: &lnwire.FailUnknownNextPeer{},
}
}
@ -900,7 +840,7 @@ 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,
FailureSourceIdx: 0,
FailureMessage: &lnwire.FailTemporaryChannelFailure{},
}
}
@ -2948,11 +2888,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{
@ -3030,7 +2965,7 @@ func TestRouterPaymentStateMachine(t *testing.T) {
case sendToSwitchResultFailure:
select {
case sendResult <- &htlcswitch.ForwardingError{
ErrorSource: errSource,
FailureSourceIdx: 1,
FailureMessage: &lnwire.FailTemporaryChannelFailure{},
}:
case <-time.After(1 * time.Second):
@ -3056,7 +2991,7 @@ func TestRouterPaymentStateMachine(t *testing.T) {
select {
case getPaymentResult <- &htlcswitch.PaymentResult{
Error: &htlcswitch.ForwardingError{
ErrorSource: errSource,
FailureSourceIdx: 1,
FailureMessage: &lnwire.FailTemporaryChannelFailure{},
},
}:
@ -3224,17 +3159,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{},
},

@ -410,7 +410,6 @@ func newServer(listenAddrs []net.Addr, chanDB *channeldb.DB,
s.htlcSwitch, err = htlcswitch.New(htlcswitch.Config{
DB: chanDB,
SelfKey: s.identityPriv.PubKey(),
LocalChannelClose: func(pubKey []byte,
request *htlcswitch.ChanClose) {