Merge pull request #3848 from carlaKC/htlcnotifier-3-addhtlcnotifierrpc

[htlcnotifier 4/4]: lnrpc: Add HTLC Event Subscription
This commit is contained in:
Conner Fromknecht 2020-03-17 16:37:52 -07:00 committed by GitHub
commit b6a0bfcabe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 1229 additions and 90 deletions

@ -79,6 +79,125 @@ func (PaymentState) EnumDescriptor() ([]byte, []int) {
return fileDescriptor_7a0613f69d37b0a5, []int{0}
}
type FailureDetail int32
const (
FailureDetail_UNKNOWN FailureDetail = 0
FailureDetail_NO_DETAIL FailureDetail = 1
FailureDetail_ONION_DECODE FailureDetail = 2
FailureDetail_LINK_NOT_ELIGIBLE FailureDetail = 3
FailureDetail_ON_CHAIN_TIMEOUT FailureDetail = 4
FailureDetail_HTLC_EXCEEDS_MAX FailureDetail = 5
FailureDetail_INSUFFICIENT_BALANCE FailureDetail = 6
FailureDetail_INCOMPLETE_FORWARD FailureDetail = 7
FailureDetail_HTLC_ADD_FAILED FailureDetail = 8
FailureDetail_FORWARDS_DISABLED FailureDetail = 9
FailureDetail_INVOICE_CANCELED FailureDetail = 10
FailureDetail_INVOICE_UNDERPAID FailureDetail = 11
FailureDetail_INVOICE_EXPIRY_TOO_SOON FailureDetail = 12
FailureDetail_INVOICE_NOT_OPEN FailureDetail = 13
FailureDetail_MPP_INVOICE_TIMEOUT FailureDetail = 14
FailureDetail_ADDRESS_MISMATCH FailureDetail = 15
FailureDetail_SET_TOTAL_MISMATCH FailureDetail = 16
FailureDetail_SET_TOTAL_TOO_LOW FailureDetail = 17
FailureDetail_SET_OVERPAID FailureDetail = 18
FailureDetail_UNKNOWN_INVOICE FailureDetail = 19
FailureDetail_INVALID_KEYSEND FailureDetail = 20
FailureDetail_MPP_IN_PROGRESS FailureDetail = 21
FailureDetail_CIRCULAR_ROUTE FailureDetail = 22
)
var FailureDetail_name = map[int32]string{
0: "UNKNOWN",
1: "NO_DETAIL",
2: "ONION_DECODE",
3: "LINK_NOT_ELIGIBLE",
4: "ON_CHAIN_TIMEOUT",
5: "HTLC_EXCEEDS_MAX",
6: "INSUFFICIENT_BALANCE",
7: "INCOMPLETE_FORWARD",
8: "HTLC_ADD_FAILED",
9: "FORWARDS_DISABLED",
10: "INVOICE_CANCELED",
11: "INVOICE_UNDERPAID",
12: "INVOICE_EXPIRY_TOO_SOON",
13: "INVOICE_NOT_OPEN",
14: "MPP_INVOICE_TIMEOUT",
15: "ADDRESS_MISMATCH",
16: "SET_TOTAL_MISMATCH",
17: "SET_TOTAL_TOO_LOW",
18: "SET_OVERPAID",
19: "UNKNOWN_INVOICE",
20: "INVALID_KEYSEND",
21: "MPP_IN_PROGRESS",
22: "CIRCULAR_ROUTE",
}
var FailureDetail_value = map[string]int32{
"UNKNOWN": 0,
"NO_DETAIL": 1,
"ONION_DECODE": 2,
"LINK_NOT_ELIGIBLE": 3,
"ON_CHAIN_TIMEOUT": 4,
"HTLC_EXCEEDS_MAX": 5,
"INSUFFICIENT_BALANCE": 6,
"INCOMPLETE_FORWARD": 7,
"HTLC_ADD_FAILED": 8,
"FORWARDS_DISABLED": 9,
"INVOICE_CANCELED": 10,
"INVOICE_UNDERPAID": 11,
"INVOICE_EXPIRY_TOO_SOON": 12,
"INVOICE_NOT_OPEN": 13,
"MPP_INVOICE_TIMEOUT": 14,
"ADDRESS_MISMATCH": 15,
"SET_TOTAL_MISMATCH": 16,
"SET_TOTAL_TOO_LOW": 17,
"SET_OVERPAID": 18,
"UNKNOWN_INVOICE": 19,
"INVALID_KEYSEND": 20,
"MPP_IN_PROGRESS": 21,
"CIRCULAR_ROUTE": 22,
}
func (x FailureDetail) String() string {
return proto.EnumName(FailureDetail_name, int32(x))
}
func (FailureDetail) EnumDescriptor() ([]byte, []int) {
return fileDescriptor_7a0613f69d37b0a5, []int{1}
}
type HtlcEvent_EventType int32
const (
HtlcEvent_UNKNOWN HtlcEvent_EventType = 0
HtlcEvent_SEND HtlcEvent_EventType = 1
HtlcEvent_RECEIVE HtlcEvent_EventType = 2
HtlcEvent_FORWARD HtlcEvent_EventType = 3
)
var HtlcEvent_EventType_name = map[int32]string{
0: "UNKNOWN",
1: "SEND",
2: "RECEIVE",
3: "FORWARD",
}
var HtlcEvent_EventType_value = map[string]int32{
"UNKNOWN": 0,
"SEND": 1,
"RECEIVE": 2,
"FORWARD": 3,
}
func (x HtlcEvent_EventType) String() string {
return proto.EnumName(HtlcEvent_EventType_name, int32(x))
}
func (HtlcEvent_EventType) EnumDescriptor() ([]byte, []int) {
return fileDescriptor_7a0613f69d37b0a5, []int{18, 0}
}
type SendPaymentRequest struct {
/// The identity pubkey of the payment recipient
Dest []byte `protobuf:"bytes,1,opt,name=dest,proto3" json:"dest,omitempty"`
@ -1118,8 +1237,462 @@ func (m *BuildRouteResponse) GetRoute() *lnrpc.Route {
return nil
}
type SubscribeHtlcEventsRequest struct {
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *SubscribeHtlcEventsRequest) Reset() { *m = SubscribeHtlcEventsRequest{} }
func (m *SubscribeHtlcEventsRequest) String() string { return proto.CompactTextString(m) }
func (*SubscribeHtlcEventsRequest) ProtoMessage() {}
func (*SubscribeHtlcEventsRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_7a0613f69d37b0a5, []int{17}
}
func (m *SubscribeHtlcEventsRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_SubscribeHtlcEventsRequest.Unmarshal(m, b)
}
func (m *SubscribeHtlcEventsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_SubscribeHtlcEventsRequest.Marshal(b, m, deterministic)
}
func (m *SubscribeHtlcEventsRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_SubscribeHtlcEventsRequest.Merge(m, src)
}
func (m *SubscribeHtlcEventsRequest) XXX_Size() int {
return xxx_messageInfo_SubscribeHtlcEventsRequest.Size(m)
}
func (m *SubscribeHtlcEventsRequest) XXX_DiscardUnknown() {
xxx_messageInfo_SubscribeHtlcEventsRequest.DiscardUnknown(m)
}
var xxx_messageInfo_SubscribeHtlcEventsRequest proto.InternalMessageInfo
//*
//HtlcEvent contains the htlc event that was processed. These are served on a
//best-effort basis; events are not persisted, delivery is not guaranteed
//(in the event of a crash in the switch, forward events may be lost) and
//some events may be replayed upon restart. Events consumed from this package
//should be de-duplicated by the htlc's unique combination of incoming and
//outgoing channel id and htlc id. [EXPERIMENTAL]
type HtlcEvent struct {
//*
//The short channel id that the incoming htlc arrived at our node on. This
//value is zero for sends.
IncomingChannelId uint64 `protobuf:"varint,1,opt,name=incoming_channel_id,json=incomingChannelId,proto3" json:"incoming_channel_id,omitempty"`
//*
//The short channel id that the outgoing htlc left our node on. This value
//is zero for receives.
OutgoingChannelId uint64 `protobuf:"varint,2,opt,name=outgoing_channel_id,json=outgoingChannelId,proto3" json:"outgoing_channel_id,omitempty"`
//*
//Incoming id is the index of the incoming htlc in the incoming channel.
//This value is zero for sends.
IncomingHtlcId uint64 `protobuf:"varint,3,opt,name=incoming_htlc_id,json=incomingHtlcId,proto3" json:"incoming_htlc_id,omitempty"`
//*
//Outgoing id is the index of the outgoing htlc in the outgoing channel.
//This value is zero for receives.
OutgoingHtlcId uint64 `protobuf:"varint,4,opt,name=outgoing_htlc_id,json=outgoingHtlcId,proto3" json:"outgoing_htlc_id,omitempty"`
//*
//The time in unix nanoseconds that the event occurred.
TimestampNs uint64 `protobuf:"varint,5,opt,name=timestamp_ns,json=timestampNs,proto3" json:"timestamp_ns,omitempty"`
//*
//The event type indicates whether the htlc was part of a send, receive or
//forward.
EventType HtlcEvent_EventType `protobuf:"varint,6,opt,name=event_type,json=eventType,proto3,enum=routerrpc.HtlcEvent_EventType" json:"event_type,omitempty"`
// Types that are valid to be assigned to Event:
// *HtlcEvent_ForwardEvent
// *HtlcEvent_ForwardFailEvent
// *HtlcEvent_SettleEvent
// *HtlcEvent_LinkFailEvent
Event isHtlcEvent_Event `protobuf_oneof:"event"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *HtlcEvent) Reset() { *m = HtlcEvent{} }
func (m *HtlcEvent) String() string { return proto.CompactTextString(m) }
func (*HtlcEvent) ProtoMessage() {}
func (*HtlcEvent) Descriptor() ([]byte, []int) {
return fileDescriptor_7a0613f69d37b0a5, []int{18}
}
func (m *HtlcEvent) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_HtlcEvent.Unmarshal(m, b)
}
func (m *HtlcEvent) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_HtlcEvent.Marshal(b, m, deterministic)
}
func (m *HtlcEvent) XXX_Merge(src proto.Message) {
xxx_messageInfo_HtlcEvent.Merge(m, src)
}
func (m *HtlcEvent) XXX_Size() int {
return xxx_messageInfo_HtlcEvent.Size(m)
}
func (m *HtlcEvent) XXX_DiscardUnknown() {
xxx_messageInfo_HtlcEvent.DiscardUnknown(m)
}
var xxx_messageInfo_HtlcEvent proto.InternalMessageInfo
func (m *HtlcEvent) GetIncomingChannelId() uint64 {
if m != nil {
return m.IncomingChannelId
}
return 0
}
func (m *HtlcEvent) GetOutgoingChannelId() uint64 {
if m != nil {
return m.OutgoingChannelId
}
return 0
}
func (m *HtlcEvent) GetIncomingHtlcId() uint64 {
if m != nil {
return m.IncomingHtlcId
}
return 0
}
func (m *HtlcEvent) GetOutgoingHtlcId() uint64 {
if m != nil {
return m.OutgoingHtlcId
}
return 0
}
func (m *HtlcEvent) GetTimestampNs() uint64 {
if m != nil {
return m.TimestampNs
}
return 0
}
func (m *HtlcEvent) GetEventType() HtlcEvent_EventType {
if m != nil {
return m.EventType
}
return HtlcEvent_UNKNOWN
}
type isHtlcEvent_Event interface {
isHtlcEvent_Event()
}
type HtlcEvent_ForwardEvent struct {
ForwardEvent *ForwardEvent `protobuf:"bytes,7,opt,name=forward_event,json=forwardEvent,proto3,oneof"`
}
type HtlcEvent_ForwardFailEvent struct {
ForwardFailEvent *ForwardFailEvent `protobuf:"bytes,8,opt,name=forward_fail_event,json=forwardFailEvent,proto3,oneof"`
}
type HtlcEvent_SettleEvent struct {
SettleEvent *SettleEvent `protobuf:"bytes,9,opt,name=settle_event,json=settleEvent,proto3,oneof"`
}
type HtlcEvent_LinkFailEvent struct {
LinkFailEvent *LinkFailEvent `protobuf:"bytes,10,opt,name=link_fail_event,json=linkFailEvent,proto3,oneof"`
}
func (*HtlcEvent_ForwardEvent) isHtlcEvent_Event() {}
func (*HtlcEvent_ForwardFailEvent) isHtlcEvent_Event() {}
func (*HtlcEvent_SettleEvent) isHtlcEvent_Event() {}
func (*HtlcEvent_LinkFailEvent) isHtlcEvent_Event() {}
func (m *HtlcEvent) GetEvent() isHtlcEvent_Event {
if m != nil {
return m.Event
}
return nil
}
func (m *HtlcEvent) GetForwardEvent() *ForwardEvent {
if x, ok := m.GetEvent().(*HtlcEvent_ForwardEvent); ok {
return x.ForwardEvent
}
return nil
}
func (m *HtlcEvent) GetForwardFailEvent() *ForwardFailEvent {
if x, ok := m.GetEvent().(*HtlcEvent_ForwardFailEvent); ok {
return x.ForwardFailEvent
}
return nil
}
func (m *HtlcEvent) GetSettleEvent() *SettleEvent {
if x, ok := m.GetEvent().(*HtlcEvent_SettleEvent); ok {
return x.SettleEvent
}
return nil
}
func (m *HtlcEvent) GetLinkFailEvent() *LinkFailEvent {
if x, ok := m.GetEvent().(*HtlcEvent_LinkFailEvent); ok {
return x.LinkFailEvent
}
return nil
}
// XXX_OneofWrappers is for the internal use of the proto package.
func (*HtlcEvent) XXX_OneofWrappers() []interface{} {
return []interface{}{
(*HtlcEvent_ForwardEvent)(nil),
(*HtlcEvent_ForwardFailEvent)(nil),
(*HtlcEvent_SettleEvent)(nil),
(*HtlcEvent_LinkFailEvent)(nil),
}
}
type HtlcInfo struct {
// The timelock on the incoming htlc.
IncomingTimelock uint32 `protobuf:"varint,1,opt,name=incoming_timelock,json=incomingTimelock,proto3" json:"incoming_timelock,omitempty"`
// The timelock on the outgoing htlc.
OutgoingTimelock uint32 `protobuf:"varint,2,opt,name=outgoing_timelock,json=outgoingTimelock,proto3" json:"outgoing_timelock,omitempty"`
// The amount of the incoming htlc.
IncomingAmtMsat uint64 `protobuf:"varint,3,opt,name=incoming_amt_msat,json=incomingAmtMsat,proto3" json:"incoming_amt_msat,omitempty"`
// The amount of the outgoing htlc.
OutgoingAmtMsat uint64 `protobuf:"varint,4,opt,name=outgoing_amt_msat,json=outgoingAmtMsat,proto3" json:"outgoing_amt_msat,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *HtlcInfo) Reset() { *m = HtlcInfo{} }
func (m *HtlcInfo) String() string { return proto.CompactTextString(m) }
func (*HtlcInfo) ProtoMessage() {}
func (*HtlcInfo) Descriptor() ([]byte, []int) {
return fileDescriptor_7a0613f69d37b0a5, []int{19}
}
func (m *HtlcInfo) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_HtlcInfo.Unmarshal(m, b)
}
func (m *HtlcInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_HtlcInfo.Marshal(b, m, deterministic)
}
func (m *HtlcInfo) XXX_Merge(src proto.Message) {
xxx_messageInfo_HtlcInfo.Merge(m, src)
}
func (m *HtlcInfo) XXX_Size() int {
return xxx_messageInfo_HtlcInfo.Size(m)
}
func (m *HtlcInfo) XXX_DiscardUnknown() {
xxx_messageInfo_HtlcInfo.DiscardUnknown(m)
}
var xxx_messageInfo_HtlcInfo proto.InternalMessageInfo
func (m *HtlcInfo) GetIncomingTimelock() uint32 {
if m != nil {
return m.IncomingTimelock
}
return 0
}
func (m *HtlcInfo) GetOutgoingTimelock() uint32 {
if m != nil {
return m.OutgoingTimelock
}
return 0
}
func (m *HtlcInfo) GetIncomingAmtMsat() uint64 {
if m != nil {
return m.IncomingAmtMsat
}
return 0
}
func (m *HtlcInfo) GetOutgoingAmtMsat() uint64 {
if m != nil {
return m.OutgoingAmtMsat
}
return 0
}
type ForwardEvent struct {
// Info contains details about the htlc that was forwarded.
Info *HtlcInfo `protobuf:"bytes,1,opt,name=info,proto3" json:"info,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ForwardEvent) Reset() { *m = ForwardEvent{} }
func (m *ForwardEvent) String() string { return proto.CompactTextString(m) }
func (*ForwardEvent) ProtoMessage() {}
func (*ForwardEvent) Descriptor() ([]byte, []int) {
return fileDescriptor_7a0613f69d37b0a5, []int{20}
}
func (m *ForwardEvent) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ForwardEvent.Unmarshal(m, b)
}
func (m *ForwardEvent) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ForwardEvent.Marshal(b, m, deterministic)
}
func (m *ForwardEvent) XXX_Merge(src proto.Message) {
xxx_messageInfo_ForwardEvent.Merge(m, src)
}
func (m *ForwardEvent) XXX_Size() int {
return xxx_messageInfo_ForwardEvent.Size(m)
}
func (m *ForwardEvent) XXX_DiscardUnknown() {
xxx_messageInfo_ForwardEvent.DiscardUnknown(m)
}
var xxx_messageInfo_ForwardEvent proto.InternalMessageInfo
func (m *ForwardEvent) GetInfo() *HtlcInfo {
if m != nil {
return m.Info
}
return nil
}
type ForwardFailEvent struct {
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ForwardFailEvent) Reset() { *m = ForwardFailEvent{} }
func (m *ForwardFailEvent) String() string { return proto.CompactTextString(m) }
func (*ForwardFailEvent) ProtoMessage() {}
func (*ForwardFailEvent) Descriptor() ([]byte, []int) {
return fileDescriptor_7a0613f69d37b0a5, []int{21}
}
func (m *ForwardFailEvent) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ForwardFailEvent.Unmarshal(m, b)
}
func (m *ForwardFailEvent) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ForwardFailEvent.Marshal(b, m, deterministic)
}
func (m *ForwardFailEvent) XXX_Merge(src proto.Message) {
xxx_messageInfo_ForwardFailEvent.Merge(m, src)
}
func (m *ForwardFailEvent) XXX_Size() int {
return xxx_messageInfo_ForwardFailEvent.Size(m)
}
func (m *ForwardFailEvent) XXX_DiscardUnknown() {
xxx_messageInfo_ForwardFailEvent.DiscardUnknown(m)
}
var xxx_messageInfo_ForwardFailEvent proto.InternalMessageInfo
type SettleEvent struct {
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *SettleEvent) Reset() { *m = SettleEvent{} }
func (m *SettleEvent) String() string { return proto.CompactTextString(m) }
func (*SettleEvent) ProtoMessage() {}
func (*SettleEvent) Descriptor() ([]byte, []int) {
return fileDescriptor_7a0613f69d37b0a5, []int{22}
}
func (m *SettleEvent) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_SettleEvent.Unmarshal(m, b)
}
func (m *SettleEvent) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_SettleEvent.Marshal(b, m, deterministic)
}
func (m *SettleEvent) XXX_Merge(src proto.Message) {
xxx_messageInfo_SettleEvent.Merge(m, src)
}
func (m *SettleEvent) XXX_Size() int {
return xxx_messageInfo_SettleEvent.Size(m)
}
func (m *SettleEvent) XXX_DiscardUnknown() {
xxx_messageInfo_SettleEvent.DiscardUnknown(m)
}
var xxx_messageInfo_SettleEvent proto.InternalMessageInfo
type LinkFailEvent struct {
// Info contains details about the htlc that we failed.
Info *HtlcInfo `protobuf:"bytes,1,opt,name=info,proto3" json:"info,omitempty"`
// FailureCode is the BOLT error code for the failure.
WireFailure lnrpc.Failure_FailureCode `protobuf:"varint,2,opt,name=wire_failure,json=wireFailure,proto3,enum=lnrpc.Failure_FailureCode" json:"wire_failure,omitempty"`
//*
//FailureDetail provides additional information about the reason for the
//failure. This detail enriches the information provided by the wire message
//and may be 'no detail' if the wire message requires no additional metadata.
FailureDetail FailureDetail `protobuf:"varint,3,opt,name=failure_detail,json=failureDetail,proto3,enum=routerrpc.FailureDetail" json:"failure_detail,omitempty"`
// A string representation of the link failure.
FailureString string `protobuf:"bytes,4,opt,name=failure_string,json=failureString,proto3" json:"failure_string,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *LinkFailEvent) Reset() { *m = LinkFailEvent{} }
func (m *LinkFailEvent) String() string { return proto.CompactTextString(m) }
func (*LinkFailEvent) ProtoMessage() {}
func (*LinkFailEvent) Descriptor() ([]byte, []int) {
return fileDescriptor_7a0613f69d37b0a5, []int{23}
}
func (m *LinkFailEvent) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_LinkFailEvent.Unmarshal(m, b)
}
func (m *LinkFailEvent) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_LinkFailEvent.Marshal(b, m, deterministic)
}
func (m *LinkFailEvent) XXX_Merge(src proto.Message) {
xxx_messageInfo_LinkFailEvent.Merge(m, src)
}
func (m *LinkFailEvent) XXX_Size() int {
return xxx_messageInfo_LinkFailEvent.Size(m)
}
func (m *LinkFailEvent) XXX_DiscardUnknown() {
xxx_messageInfo_LinkFailEvent.DiscardUnknown(m)
}
var xxx_messageInfo_LinkFailEvent proto.InternalMessageInfo
func (m *LinkFailEvent) GetInfo() *HtlcInfo {
if m != nil {
return m.Info
}
return nil
}
func (m *LinkFailEvent) GetWireFailure() lnrpc.Failure_FailureCode {
if m != nil {
return m.WireFailure
}
return lnrpc.Failure_RESERVED
}
func (m *LinkFailEvent) GetFailureDetail() FailureDetail {
if m != nil {
return m.FailureDetail
}
return FailureDetail_UNKNOWN
}
func (m *LinkFailEvent) GetFailureString() string {
if m != nil {
return m.FailureString
}
return ""
}
func init() {
proto.RegisterEnum("routerrpc.PaymentState", PaymentState_name, PaymentState_value)
proto.RegisterEnum("routerrpc.FailureDetail", FailureDetail_name, FailureDetail_value)
proto.RegisterEnum("routerrpc.HtlcEvent_EventType", HtlcEvent_EventType_name, HtlcEvent_EventType_value)
proto.RegisterType((*SendPaymentRequest)(nil), "routerrpc.SendPaymentRequest")
proto.RegisterMapType((map[uint64][]byte)(nil), "routerrpc.SendPaymentRequest.DestCustomRecordsEntry")
proto.RegisterType((*TrackPaymentRequest)(nil), "routerrpc.TrackPaymentRequest")
@ -1138,100 +1711,154 @@ func init() {
proto.RegisterType((*QueryProbabilityResponse)(nil), "routerrpc.QueryProbabilityResponse")
proto.RegisterType((*BuildRouteRequest)(nil), "routerrpc.BuildRouteRequest")
proto.RegisterType((*BuildRouteResponse)(nil), "routerrpc.BuildRouteResponse")
proto.RegisterType((*SubscribeHtlcEventsRequest)(nil), "routerrpc.SubscribeHtlcEventsRequest")
proto.RegisterType((*HtlcEvent)(nil), "routerrpc.HtlcEvent")
proto.RegisterType((*HtlcInfo)(nil), "routerrpc.HtlcInfo")
proto.RegisterType((*ForwardEvent)(nil), "routerrpc.ForwardEvent")
proto.RegisterType((*ForwardFailEvent)(nil), "routerrpc.ForwardFailEvent")
proto.RegisterType((*SettleEvent)(nil), "routerrpc.SettleEvent")
proto.RegisterType((*LinkFailEvent)(nil), "routerrpc.LinkFailEvent")
}
func init() { proto.RegisterFile("routerrpc/router.proto", fileDescriptor_7a0613f69d37b0a5) }
var fileDescriptor_7a0613f69d37b0a5 = []byte{
// 1404 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x57, 0xdb, 0x52, 0xdb, 0xd6,
0x1a, 0xde, 0xf2, 0x09, 0xf3, 0xdb, 0x18, 0x65, 0xb1, 0x27, 0xd1, 0x36, 0x21, 0xf1, 0xd6, 0xce,
0x26, 0x9e, 0x4e, 0x02, 0x09, 0xed, 0x74, 0x32, 0xbd, 0xe8, 0x0c, 0xf8, 0x50, 0x4c, 0xcd, 0x21,
0xcb, 0xe6, 0xa2, 0xcd, 0x85, 0x46, 0x58, 0xcb, 0x58, 0x45, 0xd2, 0x72, 0xb5, 0x96, 0x92, 0xe1,
0x15, 0xfa, 0x22, 0xed, 0x4d, 0xfb, 0x5c, 0x7d, 0x84, 0x5e, 0x76, 0xd6, 0x41, 0x58, 0x36, 0x36,
0xe9, 0x9d, 0xf5, 0xfd, 0xdf, 0x7f, 0x5a, 0xff, 0x09, 0xe0, 0x71, 0x4c, 0x13, 0x4e, 0xe2, 0x78,
0x3a, 0xda, 0x57, 0xbf, 0xf6, 0xa6, 0x31, 0xe5, 0x14, 0xad, 0xdf, 0xe1, 0xf5, 0xf5, 0x78, 0x3a,
0x52, 0xa8, 0xfd, 0x57, 0x11, 0xd0, 0x80, 0x44, 0xde, 0x85, 0x7b, 0x1b, 0x92, 0x88, 0x63, 0xf2,
0x73, 0x42, 0x18, 0x47, 0x08, 0x0a, 0x1e, 0x61, 0xdc, 0x32, 0x1a, 0x46, 0xb3, 0x8a, 0xe5, 0x6f,
0x64, 0x42, 0xde, 0x0d, 0xb9, 0x95, 0x6b, 0x18, 0xcd, 0x3c, 0x16, 0x3f, 0xd1, 0x7f, 0xa0, 0xec,
0x86, 0xdc, 0x09, 0x99, 0xcb, 0xad, 0xaa, 0x84, 0xd7, 0xdc, 0x90, 0x9f, 0x32, 0x97, 0xa3, 0xff,
0x42, 0x75, 0xaa, 0x4c, 0x3a, 0x13, 0x97, 0x4d, 0xac, 0xbc, 0x34, 0x54, 0xd1, 0xd8, 0xb1, 0xcb,
0x26, 0xa8, 0x09, 0xe6, 0xd8, 0x8f, 0xdc, 0xc0, 0x19, 0x05, 0xfc, 0xa3, 0xe3, 0x91, 0x80, 0xbb,
0x56, 0xa1, 0x61, 0x34, 0x8b, 0xb8, 0x26, 0xf1, 0x56, 0xc0, 0x3f, 0xb6, 0x05, 0x8a, 0x5e, 0xc2,
0x66, 0x6a, 0x2c, 0x56, 0x01, 0x5a, 0xc5, 0x86, 0xd1, 0x5c, 0xc7, 0xb5, 0xe9, 0x7c, 0xd8, 0x2f,
0x61, 0x93, 0xfb, 0x21, 0xa1, 0x09, 0x77, 0x18, 0x19, 0xd1, 0xc8, 0x63, 0x56, 0x49, 0x59, 0xd4,
0xf0, 0x40, 0xa1, 0xc8, 0x86, 0x8d, 0x31, 0x21, 0x4e, 0xe0, 0x87, 0x3e, 0x77, 0x44, 0xf8, 0x6b,
0x32, 0xfc, 0xca, 0x98, 0x90, 0xbe, 0xc0, 0x06, 0x2e, 0x47, 0x2f, 0xa0, 0x36, 0xe3, 0xc8, 0x1c,
0x37, 0x24, 0xa9, 0x9a, 0x92, 0x64, 0xa2, 0xaf, 0xc0, 0xa4, 0x09, 0xbf, 0xa6, 0x7e, 0x74, 0xed,
0x8c, 0x26, 0x6e, 0xe4, 0xf8, 0x9e, 0x55, 0x6e, 0x18, 0xcd, 0xc2, 0x51, 0xee, 0x8d, 0x81, 0x6b,
0xa9, 0xac, 0x35, 0x71, 0xa3, 0x9e, 0x87, 0x76, 0x61, 0x33, 0x70, 0x19, 0x77, 0x26, 0x74, 0xea,
0x4c, 0x93, 0xab, 0x1b, 0x72, 0x6b, 0xd5, 0xe4, 0xcb, 0x6c, 0x08, 0xf8, 0x98, 0x4e, 0x2f, 0x24,
0x88, 0x76, 0x00, 0xe4, 0xab, 0x48, 0xe7, 0xd6, 0xba, 0xcc, 0x61, 0x5d, 0x20, 0xd2, 0x31, 0x7a,
0x0b, 0x15, 0x59, 0x4d, 0x67, 0xe2, 0x47, 0x9c, 0x59, 0xd0, 0xc8, 0x37, 0x2b, 0x07, 0xe6, 0x5e,
0x10, 0x89, 0xc2, 0x62, 0x21, 0x39, 0xf6, 0x23, 0x8e, 0x21, 0x4e, 0x7f, 0x32, 0xe4, 0xc1, 0x96,
0xa8, 0xa2, 0x33, 0x4a, 0x18, 0xa7, 0xa1, 0x13, 0x93, 0x11, 0x8d, 0x3d, 0x66, 0x55, 0xa4, 0xea,
0x57, 0x7b, 0x77, 0xcd, 0xb1, 0x77, 0xbf, 0x1b, 0xf6, 0xda, 0x84, 0xf1, 0x96, 0xd4, 0xc3, 0x4a,
0xad, 0x13, 0xf1, 0xf8, 0x16, 0x3f, 0xf2, 0x16, 0x71, 0xf4, 0x0a, 0x90, 0x1b, 0x04, 0xf4, 0x93,
0xc3, 0x48, 0x30, 0x76, 0x74, 0x75, 0xac, 0xcd, 0x86, 0xd1, 0x2c, 0x63, 0x53, 0x4a, 0x06, 0x24,
0x18, 0x6b, 0xf3, 0xe8, 0x6b, 0xd8, 0x90, 0x31, 0x8d, 0x89, 0xcb, 0x93, 0x98, 0x30, 0xcb, 0x6c,
0xe4, 0x9b, 0xb5, 0x83, 0x47, 0x3a, 0x91, 0xae, 0x82, 0x8f, 0x7c, 0x8e, 0xab, 0x82, 0xa7, 0xbf,
0x59, 0xbd, 0x0d, 0x8f, 0x97, 0x87, 0x24, 0x7a, 0x54, 0xbc, 0xa9, 0x68, 0xdb, 0x02, 0x16, 0x3f,
0xd1, 0xbf, 0xa1, 0xf8, 0xd1, 0x0d, 0x12, 0x22, 0xfb, 0xb6, 0x8a, 0xd5, 0xc7, 0x37, 0xb9, 0x77,
0x86, 0xfd, 0x0e, 0xb6, 0x86, 0xb1, 0x3b, 0xba, 0x59, 0x68, 0xfd, 0xc5, 0xce, 0x35, 0xee, 0x75,
0xae, 0xfd, 0x9b, 0x01, 0x1b, 0x5a, 0x6b, 0xc0, 0x5d, 0x9e, 0x30, 0xf4, 0x1a, 0x8a, 0x8c, 0xbb,
0x9c, 0x48, 0x76, 0xed, 0xe0, 0x49, 0xe6, 0x3d, 0x33, 0x44, 0x82, 0x15, 0x0b, 0xd5, 0xa1, 0x3c,
0x8d, 0x89, 0x1f, 0xba, 0xd7, 0x69, 0x5c, 0x77, 0xdf, 0xc8, 0x86, 0xa2, 0x54, 0x96, 0x23, 0x53,
0x39, 0xa8, 0x66, 0xab, 0x8a, 0x95, 0x08, 0x35, 0xa1, 0x38, 0xe1, 0xc1, 0x88, 0x59, 0x05, 0x59,
0x3e, 0xa4, 0x39, 0xc7, 0xc3, 0x7e, 0xeb, 0x90, 0x73, 0x12, 0x4e, 0x39, 0x56, 0x04, 0xfb, 0x5b,
0xd8, 0x94, 0x9a, 0x5d, 0x42, 0x1e, 0x9a, 0xed, 0x27, 0x20, 0x26, 0x57, 0x4e, 0x82, 0x9a, 0xef,
0x92, 0x1b, 0x8a, 0x21, 0xb0, 0x3d, 0x30, 0x67, 0xfa, 0x6c, 0x4a, 0x23, 0x26, 0xbc, 0x9b, 0x22,
0x0c, 0xd1, 0xf1, 0x62, 0x40, 0xe4, 0x68, 0x18, 0x52, 0xab, 0xa6, 0xf1, 0x2e, 0x21, 0x72, 0x38,
0x76, 0xd5, 0x3c, 0x3a, 0x01, 0x1d, 0xdd, 0x88, 0x09, 0x77, 0x6f, 0xb5, 0xf9, 0x0d, 0x01, 0xf7,
0xe9, 0xe8, 0xa6, 0x2d, 0x40, 0xfb, 0x83, 0x5a, 0x42, 0x43, 0xaa, 0xb2, 0xfc, 0xc7, 0x95, 0x98,
0x3d, 0x56, 0x6e, 0xe5, 0x63, 0xd9, 0x1f, 0x60, 0x6b, 0xce, 0xb8, 0xce, 0x22, 0x5b, 0x03, 0x63,
0xa1, 0x06, 0x4d, 0x58, 0x1b, 0xbb, 0x7e, 0x90, 0xc4, 0xa9, 0xe1, 0x5a, 0xda, 0x92, 0x0a, 0xc5,
0xa9, 0xd8, 0x7e, 0x0a, 0x75, 0x4c, 0x18, 0xe1, 0xa7, 0x3e, 0x63, 0x3e, 0x8d, 0x5a, 0x34, 0xe2,
0x31, 0x0d, 0x74, 0x06, 0xf6, 0x0e, 0x6c, 0x2f, 0x95, 0xaa, 0x10, 0x84, 0xf2, 0xfb, 0x84, 0xc4,
0xb7, 0xcb, 0x95, 0xdf, 0xc3, 0xf6, 0x52, 0xa9, 0x8e, 0xff, 0x15, 0x14, 0xa7, 0xae, 0x1f, 0x33,
0x2b, 0x27, 0x7b, 0xe0, 0xf1, 0x5c, 0xcb, 0xf9, 0xf1, 0xb1, 0xcf, 0x38, 0x8d, 0x6f, 0xb1, 0x22,
0x9d, 0x14, 0xca, 0x86, 0x99, 0xb3, 0x7f, 0x31, 0xa0, 0x92, 0x11, 0xa2, 0x6d, 0x58, 0x8f, 0xa8,
0x47, 0x9c, 0x71, 0x4c, 0xc3, 0xf4, 0x11, 0x04, 0xd0, 0x8d, 0x69, 0x28, 0x7a, 0x42, 0x0a, 0x39,
0xd5, 0x3d, 0x5a, 0x12, 0x9f, 0x43, 0x8a, 0x5e, 0xc3, 0xda, 0x44, 0x19, 0x90, 0x6b, 0xb3, 0x72,
0xb0, 0xb5, 0xe0, 0xbb, 0xed, 0x72, 0x17, 0xa7, 0x9c, 0x93, 0x42, 0x39, 0x6f, 0x16, 0x4e, 0x0a,
0xe5, 0x82, 0x59, 0x3c, 0x29, 0x94, 0x8b, 0x66, 0xe9, 0xa4, 0x50, 0x2e, 0x99, 0x6b, 0xf6, 0x9f,
0x06, 0x94, 0x53, 0xb6, 0x88, 0x44, 0x3c, 0xa9, 0x23, 0xfa, 0x42, 0x37, 0x53, 0x59, 0x00, 0x43,
0x3f, 0x24, 0xa8, 0x01, 0x55, 0x29, 0x9c, 0x6f, 0x51, 0x10, 0xd8, 0xa1, 0x6c, 0x53, 0xb9, 0xcf,
0x53, 0x86, 0xec, 0xc7, 0x82, 0xde, 0xe7, 0x8a, 0x92, 0x9e, 0x24, 0x96, 0x8c, 0x46, 0x84, 0x31,
0xe5, 0xa5, 0xa8, 0x28, 0x1a, 0x93, 0x8e, 0x76, 0x61, 0x33, 0xa5, 0xa4, 0xbe, 0x4a, 0xaa, 0x5f,
0x35, 0xac, 0xdd, 0x35, 0xc1, 0xcc, 0xf2, 0xc2, 0xd9, 0x05, 0xa9, 0xcd, 0x88, 0xc2, 0xa9, 0x4a,
0xde, 0xfe, 0x09, 0x9e, 0xc8, 0x52, 0x5e, 0xc4, 0xf4, 0xca, 0xbd, 0xf2, 0x03, 0x9f, 0xdf, 0xa6,
0x4d, 0x2e, 0x12, 0x8f, 0x69, 0xe8, 0x88, 0xb7, 0x4d, 0x4b, 0x20, 0x80, 0x33, 0xea, 0x11, 0x51,
0x02, 0x4e, 0x95, 0x48, 0x97, 0x80, 0x53, 0x29, 0xc8, 0x5e, 0xde, 0xfc, 0xdc, 0xe5, 0xb5, 0x6f,
0xc0, 0xba, 0xef, 0x4b, 0xf7, 0x4c, 0x03, 0x2a, 0xd3, 0x19, 0x2c, 0xdd, 0x19, 0x38, 0x0b, 0x65,
0x6b, 0x9b, 0xfb, 0x7c, 0x6d, 0xed, 0x5f, 0x0d, 0x78, 0x74, 0x94, 0xf8, 0x81, 0x37, 0x37, 0xb8,
0xd9, 0xe8, 0x8c, 0xf9, 0xbf, 0x0b, 0x96, 0x1d, 0xfd, 0xdc, 0xd2, 0xa3, 0xbf, 0xec, 0xb0, 0xe6,
0x57, 0x1e, 0xd6, 0xe7, 0x50, 0x99, 0xdd, 0x54, 0xb5, 0x17, 0xab, 0x18, 0x26, 0xe9, 0x41, 0x65,
0xf6, 0x3b, 0x40, 0xd9, 0x40, 0xf5, 0x83, 0xdc, 0xed, 0x0f, 0x63, 0xe5, 0xfe, 0xf8, 0xe2, 0x0f,
0x03, 0xaa, 0xd9, 0x25, 0x8e, 0x36, 0x60, 0xbd, 0x77, 0xe6, 0x74, 0xfb, 0xbd, 0xef, 0x8e, 0x87,
0xe6, 0xbf, 0xc4, 0xe7, 0xe0, 0xb2, 0xd5, 0xea, 0x74, 0xda, 0x9d, 0xb6, 0x69, 0x20, 0x04, 0xb5,
0xee, 0x61, 0xaf, 0xdf, 0x69, 0x3b, 0xc3, 0xde, 0x69, 0xe7, 0xfc, 0x72, 0x68, 0xe6, 0xd0, 0x16,
0x6c, 0x6a, 0xec, 0xec, 0xdc, 0xc1, 0xe7, 0x97, 0xc3, 0x8e, 0x99, 0x47, 0x26, 0x54, 0x35, 0xd8,
0xc1, 0xf8, 0x1c, 0x9b, 0x05, 0xf4, 0x02, 0x1a, 0x1a, 0xe9, 0x9d, 0xb5, 0xce, 0x31, 0xee, 0xb4,
0x86, 0xce, 0xc5, 0xe1, 0x0f, 0xa7, 0x9d, 0xb3, 0xa1, 0xd3, 0xee, 0x0c, 0x0f, 0x7b, 0xfd, 0x81,
0x59, 0x44, 0xcf, 0x61, 0xfb, 0x8e, 0x35, 0xb8, 0xec, 0x76, 0x7b, 0xad, 0x9e, 0x20, 0x1c, 0x1d,
0xf6, 0x0f, 0xcf, 0x5a, 0x1d, 0xb3, 0x74, 0xf0, 0x7b, 0x11, 0x4a, 0x32, 0x83, 0x18, 0x1d, 0x43,
0x25, 0x73, 0xcf, 0xd1, 0xce, 0x83, 0x77, 0xbe, 0x6e, 0x2d, 0x3f, 0x5b, 0x09, 0x7b, 0x63, 0xa0,
0x13, 0xa8, 0x66, 0xaf, 0x25, 0x7a, 0x96, 0xe1, 0x2e, 0x39, 0xa3, 0x0f, 0xda, 0xfa, 0x1e, 0xcc,
0x0e, 0xe3, 0x7e, 0x28, 0x2e, 0xa2, 0x3e, 0x2e, 0xa8, 0x9e, 0xe1, 0x2f, 0x5c, 0xac, 0xfa, 0xf6,
0x52, 0x99, 0x2e, 0x61, 0x5f, 0xa5, 0xa8, 0xd7, 0xfb, 0xbd, 0x14, 0xe7, 0x6f, 0x4a, 0xfd, 0xd9,
0x2a, 0xb1, 0xb6, 0xe6, 0xc1, 0xd6, 0x92, 0x8d, 0x8d, 0xfe, 0x9f, 0x8d, 0x60, 0xe5, 0xbe, 0xaf,
0xef, 0x7e, 0x8e, 0x36, 0xf3, 0xb2, 0x64, 0xb5, 0xcf, 0x79, 0x59, 0x7d, 0x18, 0xe6, 0xbc, 0x3c,
0x74, 0x21, 0x3e, 0x80, 0xb9, 0xb8, 0x09, 0x90, 0xbd, 0xa8, 0x7b, 0x7f, 0x25, 0xd5, 0xff, 0xf7,
0x20, 0x47, 0x1b, 0xef, 0x01, 0xcc, 0xe6, 0x09, 0x3d, 0xcd, 0xa8, 0xdc, 0xdb, 0x07, 0xf5, 0x9d,
0x15, 0x52, 0x65, 0xea, 0xe8, 0xed, 0x8f, 0xfb, 0xd7, 0x3e, 0x9f, 0x24, 0x57, 0x7b, 0x23, 0x1a,
0xee, 0x07, 0xfe, 0xf5, 0x84, 0x47, 0x7e, 0x74, 0x1d, 0x11, 0xfe, 0x89, 0xc6, 0x37, 0xfb, 0x41,
0xe4, 0xed, 0xcb, 0xb1, 0xdc, 0xbf, 0xb3, 0x72, 0x55, 0x92, 0xff, 0xbd, 0x7c, 0xf9, 0x77, 0x00,
0x00, 0x00, 0xff, 0xff, 0x30, 0x2f, 0x8a, 0x5c, 0xed, 0x0c, 0x00, 0x00,
// 2155 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x58, 0xdd, 0x72, 0xdb, 0xc6,
0x15, 0x36, 0x28, 0x50, 0x22, 0x0f, 0x7f, 0x04, 0xad, 0x1c, 0x99, 0xa5, 0xec, 0x44, 0x41, 0x13,
0x9b, 0xe3, 0x3a, 0x92, 0xa3, 0x76, 0x5a, 0x4f, 0xdb, 0xa4, 0x43, 0x91, 0x90, 0x09, 0x99, 0x02,
0x98, 0x25, 0xe4, 0x9f, 0xfa, 0x62, 0x07, 0x22, 0x97, 0x22, 0x2a, 0x10, 0x60, 0x81, 0xa5, 0x3d,
0xba, 0xec, 0xf4, 0xae, 0x2f, 0xd2, 0x5e, 0xf5, 0x09, 0xfa, 0x2e, 0xbd, 0xed, 0x13, 0x74, 0x7a,
0xd9, 0xd9, 0xc5, 0x82, 0x04, 0x29, 0xca, 0xc9, 0x8d, 0x4d, 0x7c, 0xe7, 0xdb, 0xb3, 0xe7, 0x77,
0xcf, 0xae, 0x60, 0x2f, 0x0a, 0x67, 0x8c, 0x46, 0xd1, 0x74, 0x70, 0x94, 0xfc, 0x3a, 0x9c, 0x46,
0x21, 0x0b, 0x51, 0x71, 0x8e, 0xd7, 0x8b, 0xd1, 0x74, 0x90, 0xa0, 0xfa, 0xff, 0xf2, 0x80, 0xfa,
0x34, 0x18, 0xf6, 0xdc, 0x9b, 0x09, 0x0d, 0x18, 0xa6, 0x7f, 0x9e, 0xd1, 0x98, 0x21, 0x04, 0xea,
0x90, 0xc6, 0xac, 0xa6, 0x1c, 0x28, 0x8d, 0x32, 0x16, 0xbf, 0x91, 0x06, 0x1b, 0xee, 0x84, 0xd5,
0x72, 0x07, 0x4a, 0x63, 0x03, 0xf3, 0x9f, 0xe8, 0x67, 0x50, 0x70, 0x27, 0x8c, 0x4c, 0x62, 0x97,
0xd5, 0xca, 0x02, 0xde, 0x72, 0x27, 0xec, 0x3c, 0x76, 0x19, 0xfa, 0x12, 0xca, 0xd3, 0x44, 0x25,
0x19, 0xbb, 0xf1, 0xb8, 0xb6, 0x21, 0x14, 0x95, 0x24, 0xd6, 0x71, 0xe3, 0x31, 0x6a, 0x80, 0x36,
0xf2, 0x02, 0xd7, 0x27, 0x03, 0x9f, 0x7d, 0x20, 0x43, 0xea, 0x33, 0xb7, 0xa6, 0x1e, 0x28, 0x8d,
0x3c, 0xae, 0x0a, 0xbc, 0xe5, 0xb3, 0x0f, 0x6d, 0x8e, 0xa2, 0x27, 0xb0, 0x9d, 0x2a, 0x8b, 0x12,
0x03, 0x6b, 0xf9, 0x03, 0xa5, 0x51, 0xc4, 0xd5, 0xe9, 0xb2, 0xd9, 0x4f, 0x60, 0x9b, 0x79, 0x13,
0x1a, 0xce, 0x18, 0x89, 0xe9, 0x20, 0x0c, 0x86, 0x71, 0x6d, 0x33, 0xd1, 0x28, 0xe1, 0x7e, 0x82,
0x22, 0x1d, 0x2a, 0x23, 0x4a, 0x89, 0xef, 0x4d, 0x3c, 0x46, 0xb8, 0xf9, 0x5b, 0xc2, 0xfc, 0xd2,
0x88, 0xd2, 0x2e, 0xc7, 0xfa, 0x2e, 0x43, 0x5f, 0x41, 0x75, 0xc1, 0x11, 0x3e, 0x56, 0x04, 0xa9,
0x9c, 0x92, 0x84, 0xa3, 0xcf, 0x40, 0x0b, 0x67, 0xec, 0x2a, 0xf4, 0x82, 0x2b, 0x32, 0x18, 0xbb,
0x01, 0xf1, 0x86, 0xb5, 0xc2, 0x81, 0xd2, 0x50, 0x4f, 0x72, 0xcf, 0x15, 0x5c, 0x4d, 0x65, 0xad,
0xb1, 0x1b, 0x98, 0x43, 0xf4, 0x18, 0xb6, 0x7d, 0x37, 0x66, 0x64, 0x1c, 0x4e, 0xc9, 0x74, 0x76,
0x79, 0x4d, 0x6f, 0x6a, 0x55, 0x11, 0x99, 0x0a, 0x87, 0x3b, 0xe1, 0xb4, 0x27, 0x40, 0xf4, 0x08,
0x40, 0x44, 0x45, 0x6c, 0x5e, 0x2b, 0x0a, 0x1f, 0x8a, 0x1c, 0x11, 0x1b, 0xa3, 0x6f, 0xa1, 0x24,
0xb2, 0x49, 0xc6, 0x5e, 0xc0, 0xe2, 0x1a, 0x1c, 0x6c, 0x34, 0x4a, 0xc7, 0xda, 0xa1, 0x1f, 0xf0,
0xc4, 0x62, 0x2e, 0xe9, 0x78, 0x01, 0xc3, 0x10, 0xa5, 0x3f, 0x63, 0x34, 0x84, 0x5d, 0x9e, 0x45,
0x32, 0x98, 0xc5, 0x2c, 0x9c, 0x90, 0x88, 0x0e, 0xc2, 0x68, 0x18, 0xd7, 0x4a, 0x62, 0xe9, 0xaf,
0x0e, 0xe7, 0xc5, 0x71, 0x78, 0xbb, 0x1a, 0x0e, 0xdb, 0x34, 0x66, 0x2d, 0xb1, 0x0e, 0x27, 0xcb,
0x8c, 0x80, 0x45, 0x37, 0x78, 0x67, 0xb8, 0x8a, 0xa3, 0x67, 0x80, 0x5c, 0xdf, 0x0f, 0x3f, 0x92,
0x98, 0xfa, 0x23, 0x22, 0xb3, 0x53, 0xdb, 0x3e, 0x50, 0x1a, 0x05, 0xac, 0x09, 0x49, 0x9f, 0xfa,
0x23, 0xa9, 0x1e, 0xfd, 0x1a, 0x2a, 0xc2, 0xa6, 0x11, 0x75, 0xd9, 0x2c, 0xa2, 0x71, 0x4d, 0x3b,
0xd8, 0x68, 0x54, 0x8f, 0x77, 0xa4, 0x23, 0xa7, 0x09, 0x7c, 0xe2, 0x31, 0x5c, 0xe6, 0x3c, 0xf9,
0x1d, 0xd7, 0xdb, 0xb0, 0xb7, 0xde, 0x24, 0x5e, 0xa3, 0x3c, 0xa6, 0xbc, 0x6c, 0x55, 0xcc, 0x7f,
0xa2, 0xfb, 0x90, 0xff, 0xe0, 0xfa, 0x33, 0x2a, 0xea, 0xb6, 0x8c, 0x93, 0x8f, 0xdf, 0xe6, 0x5e,
0x28, 0xfa, 0x0b, 0xd8, 0x75, 0x22, 0x77, 0x70, 0xbd, 0x52, 0xfa, 0xab, 0x95, 0xab, 0xdc, 0xaa,
0x5c, 0xfd, 0x1f, 0x0a, 0x54, 0xe4, 0xaa, 0x3e, 0x73, 0xd9, 0x2c, 0x46, 0xdf, 0x40, 0x3e, 0x66,
0x2e, 0xa3, 0x82, 0x5d, 0x3d, 0x7e, 0x90, 0x89, 0x67, 0x86, 0x48, 0x71, 0xc2, 0x42, 0x75, 0x28,
0x4c, 0x23, 0xea, 0x4d, 0xdc, 0xab, 0xd4, 0xae, 0xf9, 0x37, 0xd2, 0x21, 0x2f, 0x16, 0x8b, 0x96,
0x29, 0x1d, 0x97, 0xb3, 0x59, 0xc5, 0x89, 0x08, 0x35, 0x20, 0x3f, 0x66, 0xfe, 0x20, 0xae, 0xa9,
0x22, 0x7d, 0x48, 0x72, 0x3a, 0x4e, 0xb7, 0xd5, 0x64, 0x8c, 0x4e, 0xa6, 0x0c, 0x27, 0x04, 0xfd,
0x7b, 0xd8, 0x16, 0x2b, 0x4f, 0x29, 0xfd, 0x54, 0x6f, 0x3f, 0x00, 0xde, 0xb9, 0xa2, 0x13, 0x92,
0xfe, 0xde, 0x74, 0x27, 0xbc, 0x09, 0xf4, 0x21, 0x68, 0x8b, 0xf5, 0xf1, 0x34, 0x0c, 0x62, 0xbe,
0xbb, 0xc6, 0xcd, 0xe0, 0x15, 0xcf, 0x1b, 0x44, 0xb4, 0x86, 0x22, 0x56, 0x55, 0x25, 0x7e, 0x4a,
0xa9, 0x68, 0x8e, 0xc7, 0x49, 0x3f, 0x12, 0x3f, 0x1c, 0x5c, 0xf3, 0x0e, 0x77, 0x6f, 0xa4, 0xfa,
0x0a, 0x87, 0xbb, 0xe1, 0xe0, 0xba, 0xcd, 0x41, 0xfd, 0x7d, 0x72, 0x08, 0x39, 0x61, 0xe2, 0xe5,
0x4f, 0xce, 0xc4, 0x22, 0x58, 0xb9, 0x3b, 0x83, 0xa5, 0xbf, 0x87, 0xdd, 0x25, 0xe5, 0xd2, 0x8b,
0x6c, 0x0e, 0x94, 0x95, 0x1c, 0x34, 0x60, 0x6b, 0xe4, 0x7a, 0xfe, 0x2c, 0x4a, 0x15, 0x57, 0xd3,
0x92, 0x4c, 0x50, 0x9c, 0x8a, 0xf5, 0x87, 0x50, 0xc7, 0x34, 0xa6, 0xec, 0xdc, 0x8b, 0x63, 0x2f,
0x0c, 0x5a, 0x61, 0xc0, 0xa2, 0xd0, 0x97, 0x1e, 0xe8, 0x8f, 0x60, 0x7f, 0xad, 0x34, 0x31, 0x81,
0x2f, 0xfe, 0x61, 0x46, 0xa3, 0x9b, 0xf5, 0x8b, 0x7f, 0x80, 0xfd, 0xb5, 0x52, 0x69, 0xff, 0x33,
0xc8, 0x4f, 0x5d, 0x2f, 0x8a, 0x6b, 0x39, 0x51, 0x03, 0x7b, 0x4b, 0x25, 0xe7, 0x45, 0x1d, 0x2f,
0x66, 0x61, 0x74, 0x83, 0x13, 0xd2, 0x99, 0x5a, 0x50, 0xb4, 0x9c, 0xfe, 0x37, 0x05, 0x4a, 0x19,
0x21, 0xda, 0x87, 0x62, 0x10, 0x0e, 0x29, 0x19, 0x45, 0xe1, 0x24, 0x0d, 0x02, 0x07, 0x4e, 0xa3,
0x70, 0xc2, 0x6b, 0x42, 0x08, 0x59, 0x28, 0x6b, 0x74, 0x93, 0x7f, 0x3a, 0x21, 0xfa, 0x06, 0xb6,
0xc6, 0x89, 0x02, 0x71, 0x6c, 0x96, 0x8e, 0x77, 0x57, 0xf6, 0x6e, 0xbb, 0xcc, 0xc5, 0x29, 0xe7,
0x4c, 0x2d, 0x6c, 0x68, 0xea, 0x99, 0x5a, 0x50, 0xb5, 0xfc, 0x99, 0x5a, 0xc8, 0x6b, 0x9b, 0x67,
0x6a, 0x61, 0x53, 0xdb, 0xd2, 0xff, 0xa3, 0x40, 0x21, 0x65, 0x73, 0x4b, 0x78, 0x48, 0x09, 0xaf,
0x0b, 0x59, 0x4c, 0x05, 0x0e, 0x38, 0xde, 0x84, 0xa2, 0x03, 0x28, 0x0b, 0xe1, 0x72, 0x89, 0x02,
0xc7, 0x9a, 0xa2, 0x4c, 0xc5, 0x79, 0x9e, 0x32, 0x44, 0x3d, 0xaa, 0xf2, 0x3c, 0x4f, 0x28, 0xe9,
0x48, 0x8a, 0x67, 0x83, 0x01, 0x8d, 0xe3, 0x64, 0x97, 0x7c, 0x42, 0x91, 0x98, 0xd8, 0xe8, 0x31,
0x6c, 0xa7, 0x94, 0x74, 0xaf, 0xcd, 0xa4, 0x5e, 0x25, 0x2c, 0xb7, 0x6b, 0x80, 0x96, 0xe5, 0x4d,
0x16, 0x13, 0xa4, 0xba, 0x20, 0xf2, 0x4d, 0x13, 0xe7, 0xf5, 0x3f, 0xc1, 0x03, 0x91, 0xca, 0x5e,
0x14, 0x5e, 0xba, 0x97, 0x9e, 0xef, 0xb1, 0x9b, 0xb4, 0xc8, 0xb9, 0xe3, 0x51, 0x38, 0x21, 0x3c,
0xb6, 0x69, 0x0a, 0x38, 0x60, 0x85, 0x43, 0xca, 0x53, 0xc0, 0xc2, 0x44, 0x24, 0x53, 0xc0, 0x42,
0x21, 0xc8, 0x4e, 0xde, 0x8d, 0xa5, 0xc9, 0xab, 0x5f, 0x43, 0xed, 0xf6, 0x5e, 0xb2, 0x66, 0x0e,
0xa0, 0x34, 0x5d, 0xc0, 0x62, 0x3b, 0x05, 0x67, 0xa1, 0x6c, 0x6e, 0x73, 0x3f, 0x9e, 0x5b, 0xfd,
0xef, 0x0a, 0xec, 0x9c, 0xcc, 0x3c, 0x7f, 0xb8, 0xd4, 0xb8, 0x59, 0xeb, 0x94, 0xe5, 0x7b, 0xc1,
0xba, 0xa1, 0x9f, 0x5b, 0x3b, 0xf4, 0xd7, 0x0d, 0xd6, 0x8d, 0x3b, 0x07, 0xeb, 0x17, 0x50, 0x5a,
0xcc, 0xd4, 0xe4, 0x5c, 0x2c, 0x63, 0x18, 0xa7, 0x03, 0x35, 0xd6, 0x5f, 0x00, 0xca, 0x1a, 0x2a,
0x03, 0x32, 0x3f, 0x3f, 0x94, 0xbb, 0xcf, 0x8f, 0x87, 0x50, 0xef, 0xcf, 0x2e, 0xe3, 0x41, 0xe4,
0x5d, 0xd2, 0x0e, 0xf3, 0x07, 0xc6, 0x07, 0x1a, 0xb0, 0x38, 0xed, 0xd2, 0xff, 0xaa, 0x50, 0x9c,
0xa3, 0xe8, 0x10, 0x76, 0xbd, 0x60, 0x10, 0x4e, 0x52, 0xa3, 0x03, 0xea, 0x73, 0xbb, 0x93, 0x79,
0xb4, 0x93, 0x8a, 0x5a, 0x89, 0xc4, 0x1c, 0x72, 0xfe, 0x92, 0x93, 0x92, 0x9f, 0x4b, 0xf8, 0x59,
0x1f, 0x13, 0x7e, 0x03, 0xb4, 0xb9, 0x7e, 0x7e, 0xc0, 0xcf, 0x83, 0x82, 0xab, 0x29, 0xce, 0x8d,
0x49, 0x98, 0x73, 0xcd, 0x29, 0x53, 0x4d, 0x98, 0x29, 0x2e, 0x99, 0x5f, 0x42, 0x99, 0xf7, 0x43,
0xcc, 0xdc, 0xc9, 0x94, 0x04, 0xb1, 0xe8, 0x0b, 0x15, 0x97, 0xe6, 0x98, 0x15, 0xa3, 0xef, 0x00,
0x28, 0xf7, 0x8f, 0xb0, 0x9b, 0x29, 0x15, 0x2d, 0x51, 0x3d, 0xfe, 0x3c, 0x53, 0x18, 0xf3, 0x00,
0x1c, 0x8a, 0x7f, 0x9d, 0x9b, 0x29, 0xc5, 0x45, 0x9a, 0xfe, 0x44, 0xdf, 0x43, 0x65, 0x14, 0x46,
0x1f, 0xdd, 0x68, 0x48, 0x04, 0x28, 0x8f, 0x8d, 0xec, 0x94, 0x3c, 0x4d, 0xe4, 0x62, 0x79, 0xe7,
0x1e, 0x2e, 0x8f, 0x32, 0xdf, 0xe8, 0x15, 0xa0, 0x74, 0xbd, 0xe8, 0xf2, 0x44, 0x49, 0x41, 0x28,
0xd9, 0xbf, 0xad, 0x84, 0x1f, 0xd2, 0xa9, 0x22, 0x6d, 0xb4, 0x82, 0xa1, 0xdf, 0x41, 0x39, 0xa6,
0x8c, 0xf9, 0x54, 0xaa, 0x29, 0x0a, 0x35, 0x7b, 0x4b, 0x37, 0x20, 0x2e, 0x4e, 0x35, 0x94, 0xe2,
0xc5, 0x27, 0x3a, 0x81, 0x6d, 0xdf, 0x0b, 0xae, 0xb3, 0x66, 0x80, 0x58, 0x5f, 0xcb, 0xac, 0xef,
0x7a, 0xc1, 0x75, 0xd6, 0x86, 0x8a, 0x9f, 0x05, 0xf4, 0xdf, 0x43, 0x71, 0x1e, 0x25, 0x54, 0x82,
0xad, 0x0b, 0xeb, 0x95, 0x65, 0xbf, 0xb1, 0xb4, 0x7b, 0xa8, 0x00, 0x6a, 0xdf, 0xb0, 0xda, 0x9a,
0xc2, 0x61, 0x6c, 0xb4, 0x0c, 0xf3, 0xb5, 0xa1, 0xe5, 0xf8, 0xc7, 0xa9, 0x8d, 0xdf, 0x34, 0x71,
0x5b, 0xdb, 0x38, 0xd9, 0x82, 0xbc, 0xd8, 0x57, 0xff, 0x97, 0x02, 0x05, 0x91, 0xc1, 0x60, 0x14,
0xa2, 0x5f, 0xc0, 0xbc, 0xb8, 0xc4, 0xe1, 0xc6, 0x07, 0xae, 0xa8, 0xba, 0x0a, 0x9e, 0x17, 0x8c,
0x23, 0x71, 0x4e, 0x9e, 0x97, 0xc6, 0x9c, 0x9c, 0x4b, 0xc8, 0xa9, 0x60, 0x4e, 0x7e, 0x9a, 0xd1,
0xbc, 0x74, 0xe4, 0xa8, 0x78, 0x3b, 0x15, 0xa4, 0x27, 0xec, 0xd3, 0x8c, 0xe2, 0xa5, 0x93, 0x58,
0xc5, 0xdb, 0xa9, 0x40, 0x72, 0xf5, 0xdf, 0x40, 0x39, 0x9b, 0x73, 0xf4, 0x04, 0x54, 0x2f, 0x18,
0x85, 0xb2, 0x11, 0x77, 0x57, 0x8a, 0x8b, 0x3b, 0x89, 0x05, 0x41, 0x47, 0xa0, 0xad, 0xe6, 0x59,
0xaf, 0x40, 0x29, 0x93, 0x34, 0xfd, 0xdf, 0x0a, 0x54, 0x96, 0x92, 0xf0, 0x93, 0xb5, 0xa3, 0xef,
0xa0, 0xfc, 0xd1, 0x8b, 0x28, 0xc9, 0x8e, 0xff, 0xea, 0x71, 0x7d, 0x79, 0xfc, 0xa7, 0xff, 0xb7,
0xc2, 0x21, 0xc5, 0x25, 0xce, 0x97, 0x00, 0xfa, 0x03, 0x54, 0xe5, 0x4a, 0x32, 0xa4, 0xcc, 0xf5,
0x7c, 0x11, 0xaa, 0xea, 0x52, 0x79, 0x48, 0x6e, 0x5b, 0xc8, 0x71, 0x65, 0x94, 0xfd, 0x44, 0x5f,
0x2f, 0x14, 0xc4, 0x2c, 0xf2, 0x82, 0x2b, 0x11, 0xbf, 0xe2, 0x9c, 0xd6, 0x17, 0xe0, 0xd3, 0x7f,
0x2a, 0x50, 0xce, 0x5e, 0x2c, 0x51, 0x05, 0x8a, 0xa6, 0x45, 0x4e, 0xbb, 0xe6, 0xcb, 0x8e, 0xa3,
0xdd, 0xe3, 0x9f, 0xfd, 0x8b, 0x56, 0xcb, 0x30, 0xda, 0x06, 0x2f, 0x27, 0x04, 0xd5, 0xd3, 0xa6,
0xd9, 0x35, 0xda, 0xc4, 0x31, 0xcf, 0x0d, 0xfb, 0xc2, 0xd1, 0x72, 0x68, 0x17, 0xb6, 0x25, 0x66,
0xd9, 0x04, 0xdb, 0x17, 0x8e, 0xa1, 0x6d, 0x20, 0x0d, 0xca, 0x12, 0x34, 0x30, 0xb6, 0xb1, 0xa6,
0xa2, 0xaf, 0xe0, 0x40, 0x22, 0xa6, 0xd5, 0xb2, 0x31, 0x36, 0x5a, 0x0e, 0xe9, 0x35, 0xdf, 0x9d,
0x1b, 0x96, 0x43, 0xda, 0x86, 0xd3, 0x34, 0xbb, 0x7d, 0x2d, 0x8f, 0xbe, 0x80, 0xfd, 0x39, 0xab,
0x7f, 0x71, 0x7a, 0x6a, 0xb6, 0x4c, 0x4e, 0x38, 0x69, 0x76, 0x9b, 0x56, 0xcb, 0xd0, 0x36, 0x9f,
0xfe, 0x45, 0x85, 0xca, 0x92, 0xe3, 0xcb, 0x95, 0x5f, 0x81, 0xa2, 0x65, 0x4b, 0x7d, 0x9a, 0xc2,
0xcd, 0xb0, 0x2d, 0xd3, 0xb6, 0x48, 0xdb, 0x68, 0xd9, 0x6d, 0xde, 0x03, 0x9f, 0xc1, 0x4e, 0xd7,
0xb4, 0x5e, 0x11, 0xcb, 0x76, 0x88, 0xd1, 0x35, 0x5f, 0x9a, 0x27, 0x5d, 0x6e, 0xef, 0x7d, 0xd0,
0x6c, 0x8b, 0xb4, 0x3a, 0x4d, 0xd3, 0x9a, 0xbb, 0xa6, 0x72, 0x94, 0x5f, 0x85, 0x89, 0xf1, 0x96,
0x47, 0xa0, 0x4f, 0xce, 0x9b, 0x6f, 0xb5, 0x3c, 0xaa, 0xc1, 0xfd, 0xf5, 0xc6, 0xa1, 0x3d, 0x40,
0xdc, 0xb9, 0xf3, 0x5e, 0xd7, 0x70, 0x0c, 0x92, 0xf6, 0xda, 0x16, 0x0f, 0x91, 0xd0, 0xd3, 0x6c,
0xb7, 0x49, 0xe2, 0x9e, 0x56, 0xe0, 0x96, 0x48, 0x46, 0x9f, 0xb4, 0xcd, 0x7e, 0xf3, 0x84, 0xc3,
0x45, 0xbe, 0xa7, 0x69, 0xbd, 0xb6, 0xcd, 0x96, 0x41, 0x5a, 0x5c, 0x2d, 0x47, 0x81, 0x93, 0x53,
0xf4, 0xc2, 0x6a, 0x1b, 0xb8, 0xd7, 0x34, 0xdb, 0x5a, 0x09, 0xed, 0xc3, 0x83, 0x14, 0x36, 0xde,
0xf6, 0x4c, 0xfc, 0x8e, 0x38, 0xb6, 0x4d, 0xfa, 0xb6, 0x6d, 0x69, 0xe5, 0xac, 0x26, 0xee, 0xad,
0xdd, 0x33, 0x2c, 0xad, 0x82, 0x1e, 0xc0, 0xee, 0x79, 0xaf, 0x47, 0x52, 0x49, 0xea, 0x6c, 0x95,
0xd3, 0x9b, 0xed, 0x36, 0x36, 0xfa, 0x7d, 0x72, 0x6e, 0xf6, 0xcf, 0x9b, 0x4e, 0xab, 0xa3, 0x6d,
0x73, 0x97, 0xfa, 0x86, 0x43, 0x1c, 0xdb, 0x69, 0x76, 0x17, 0xb8, 0xc6, 0x0d, 0x5a, 0xe0, 0x7c,
0xd3, 0xae, 0xfd, 0x46, 0xdb, 0xe1, 0x01, 0xe7, 0xb0, 0xfd, 0x5a, 0x9a, 0x88, 0xb8, 0xef, 0x32,
0x3d, 0xe9, 0x9e, 0xda, 0x2e, 0x07, 0x4d, 0xeb, 0x75, 0xb3, 0x6b, 0xb6, 0xc9, 0x2b, 0xe3, 0x9d,
0x38, 0xab, 0xee, 0x73, 0x30, 0xb1, 0x8c, 0xf4, 0xb0, 0xfd, 0x92, 0x1b, 0xa2, 0x7d, 0xc6, 0x2b,
0xae, 0x65, 0xe2, 0xd6, 0x45, 0xb7, 0x89, 0x65, 0x71, 0xed, 0x1d, 0xff, 0x75, 0x13, 0x36, 0xc5,
0x64, 0x8d, 0x50, 0x87, 0x37, 0xec, 0xfc, 0x9d, 0x89, 0x1e, 0x7d, 0xf2, 0xfd, 0x59, 0xaf, 0xad,
0x7f, 0x4e, 0xcd, 0xe2, 0xe7, 0x0a, 0x3a, 0x83, 0x72, 0xf6, 0x15, 0x87, 0xb2, 0x63, 0x69, 0xcd,
0xf3, 0xee, 0x93, 0xba, 0x5e, 0x81, 0x66, 0xc4, 0xcc, 0x9b, 0xf0, 0x97, 0x9a, 0x7c, 0xf4, 0xa0,
0x7a, 0x86, 0xbf, 0xf2, 0x92, 0xaa, 0xef, 0xaf, 0x95, 0xc9, 0xab, 0x45, 0x37, 0x71, 0x51, 0x3e,
0x3b, 0x6e, 0xb9, 0xb8, 0xfc, 0xd6, 0xa9, 0x7f, 0x7e, 0x97, 0x58, 0x6a, 0x1b, 0xc2, 0xee, 0x9a,
0x97, 0x04, 0xfa, 0x3a, 0x6b, 0xc1, 0x9d, 0xef, 0x90, 0xfa, 0xe3, 0x1f, 0xa3, 0x2d, 0x76, 0x59,
0xf3, 0xe4, 0x58, 0xda, 0xe5, 0xee, 0x07, 0xcb, 0xd2, 0x2e, 0x9f, 0x7a, 0xb9, 0xbc, 0x07, 0x6d,
0xf5, 0x86, 0x8a, 0xf4, 0xd5, 0xb5, 0xb7, 0xaf, 0xca, 0xf5, 0x9f, 0x7f, 0x92, 0x23, 0x95, 0x9b,
0x00, 0x8b, 0x7b, 0x1e, 0x7a, 0x98, 0x59, 0x72, 0xeb, 0x9e, 0x5a, 0x7f, 0x74, 0x87, 0x54, 0xaa,
0x72, 0x60, 0x77, 0xcd, 0xc5, 0x6f, 0x29, 0x1a, 0x77, 0x5f, 0x0c, 0xeb, 0xf7, 0xd7, 0xdd, 0x8f,
0x9e, 0x2b, 0x27, 0xdf, 0xfe, 0xf1, 0xe8, 0xca, 0x63, 0xe3, 0xd9, 0xe5, 0xe1, 0x20, 0x9c, 0x1c,
0xf9, 0xde, 0xd5, 0x98, 0x05, 0x5e, 0x70, 0x15, 0x50, 0xf6, 0x31, 0x8c, 0xae, 0x8f, 0xfc, 0x60,
0x78, 0x24, 0x86, 0xcd, 0xd1, 0x7c, 0xf9, 0xe5, 0xa6, 0xf8, 0x5b, 0xdd, 0x2f, 0xff, 0x1f, 0x00,
0x00, 0xff, 0xff, 0xe9, 0x0c, 0xc3, 0x27, 0xdb, 0x13, 0x00, 0x00,
}
// Reference imports to suppress errors if they are not otherwise used.
@ -1281,6 +1908,10 @@ type RouterClient interface {
//keys. It retrieves the relevant channel policies from the graph in order to
//calculate the correct fees and time locks.
BuildRoute(ctx context.Context, in *BuildRouteRequest, opts ...grpc.CallOption) (*BuildRouteResponse, error)
//*
//SubscribeHtlcEvents creates a uni-directional stream from the server to
//the client which delivers a stream of htlc events.
SubscribeHtlcEvents(ctx context.Context, in *SubscribeHtlcEventsRequest, opts ...grpc.CallOption) (Router_SubscribeHtlcEventsClient, error)
}
type routerClient struct {
@ -1409,6 +2040,38 @@ func (c *routerClient) BuildRoute(ctx context.Context, in *BuildRouteRequest, op
return out, nil
}
func (c *routerClient) SubscribeHtlcEvents(ctx context.Context, in *SubscribeHtlcEventsRequest, opts ...grpc.CallOption) (Router_SubscribeHtlcEventsClient, error) {
stream, err := c.cc.NewStream(ctx, &_Router_serviceDesc.Streams[2], "/routerrpc.Router/SubscribeHtlcEvents", opts...)
if err != nil {
return nil, err
}
x := &routerSubscribeHtlcEventsClient{stream}
if err := x.ClientStream.SendMsg(in); err != nil {
return nil, err
}
if err := x.ClientStream.CloseSend(); err != nil {
return nil, err
}
return x, nil
}
type Router_SubscribeHtlcEventsClient interface {
Recv() (*HtlcEvent, error)
grpc.ClientStream
}
type routerSubscribeHtlcEventsClient struct {
grpc.ClientStream
}
func (x *routerSubscribeHtlcEventsClient) Recv() (*HtlcEvent, error) {
m := new(HtlcEvent)
if err := x.ClientStream.RecvMsg(m); err != nil {
return nil, err
}
return m, nil
}
// RouterServer is the server API for Router service.
type RouterServer interface {
//*
@ -1446,6 +2109,10 @@ type RouterServer interface {
//keys. It retrieves the relevant channel policies from the graph in order to
//calculate the correct fees and time locks.
BuildRoute(context.Context, *BuildRouteRequest) (*BuildRouteResponse, error)
//*
//SubscribeHtlcEvents creates a uni-directional stream from the server to
//the client which delivers a stream of htlc events.
SubscribeHtlcEvents(*SubscribeHtlcEventsRequest, Router_SubscribeHtlcEventsServer) error
}
func RegisterRouterServer(s *grpc.Server, srv RouterServer) {
@ -1602,6 +2269,27 @@ func _Router_BuildRoute_Handler(srv interface{}, ctx context.Context, dec func(i
return interceptor(ctx, in, info, handler)
}
func _Router_SubscribeHtlcEvents_Handler(srv interface{}, stream grpc.ServerStream) error {
m := new(SubscribeHtlcEventsRequest)
if err := stream.RecvMsg(m); err != nil {
return err
}
return srv.(RouterServer).SubscribeHtlcEvents(m, &routerSubscribeHtlcEventsServer{stream})
}
type Router_SubscribeHtlcEventsServer interface {
Send(*HtlcEvent) error
grpc.ServerStream
}
type routerSubscribeHtlcEventsServer struct {
grpc.ServerStream
}
func (x *routerSubscribeHtlcEventsServer) Send(m *HtlcEvent) error {
return x.ServerStream.SendMsg(m)
}
var _Router_serviceDesc = grpc.ServiceDesc{
ServiceName: "routerrpc.Router",
HandlerType: (*RouterServer)(nil),
@ -1642,6 +2330,11 @@ var _Router_serviceDesc = grpc.ServiceDesc{
Handler: _Router_TrackPayment_Handler,
ServerStreams: true,
},
{
StreamName: "SubscribeHtlcEvents",
Handler: _Router_SubscribeHtlcEvents_Handler,
ServerStreams: true,
},
},
Metadata: "routerrpc/router.proto",
}

@ -333,6 +333,135 @@ message BuildRouteResponse {
lnrpc.Route route = 1;
}
message SubscribeHtlcEventsRequest{}
/**
HtlcEvent contains the htlc event that was processed. These are served on a
best-effort basis; events are not persisted, delivery is not guaranteed
(in the event of a crash in the switch, forward events may be lost) and
some events may be replayed upon restart. Events consumed from this package
should be de-duplicated by the htlc's unique combination of incoming and
outgoing channel id and htlc id. [EXPERIMENTAL]
*/
message HtlcEvent{
/**
The short channel id that the incoming htlc arrived at our node on. This
value is zero for sends.
*/
uint64 incoming_channel_id = 1;
/**
The short channel id that the outgoing htlc left our node on. This value
is zero for receives.
*/
uint64 outgoing_channel_id = 2;
/**
Incoming id is the index of the incoming htlc in the incoming channel.
This value is zero for sends.
*/
uint64 incoming_htlc_id = 3;
/**
Outgoing id is the index of the outgoing htlc in the outgoing channel.
This value is zero for receives.
*/
uint64 outgoing_htlc_id = 4;
/**
The time in unix nanoseconds that the event occurred.
*/
uint64 timestamp_ns = 5;
enum EventType{
UNKNOWN = 0;
SEND = 1;
RECEIVE = 2;
FORWARD = 3;
}
/**
The event type indicates whether the htlc was part of a send, receive or
forward.
*/
EventType event_type = 6;
oneof event {
ForwardEvent forward_event = 7;
ForwardFailEvent forward_fail_event = 8;
SettleEvent settle_event = 9;
LinkFailEvent link_fail_event = 10;
}
}
message HtlcInfo{
// The timelock on the incoming htlc.
uint32 incoming_timelock = 1;
// The timelock on the outgoing htlc.
uint32 outgoing_timelock = 2;
// The amount of the incoming htlc.
uint64 incoming_amt_msat = 3;
// The amount of the outgoing htlc.
uint64 outgoing_amt_msat = 4;
}
message ForwardEvent{
// Info contains details about the htlc that was forwarded.
HtlcInfo info = 1;
}
message ForwardFailEvent{}
message SettleEvent{}
message LinkFailEvent{
// Info contains details about the htlc that we failed.
HtlcInfo info = 1;
// FailureCode is the BOLT error code for the failure.
lnrpc.Failure.FailureCode wire_failure = 2;
/**
FailureDetail provides additional information about the reason for the
failure. This detail enriches the information provided by the wire message
and may be 'no detail' if the wire message requires no additional metadata.
*/
FailureDetail failure_detail = 3;
// A string representation of the link failure.
string failure_string = 4;
}
enum FailureDetail {
UNKNOWN = 0;
NO_DETAIL = 1;
ONION_DECODE = 2;
LINK_NOT_ELIGIBLE = 3;
ON_CHAIN_TIMEOUT = 4;
HTLC_EXCEEDS_MAX = 5;
INSUFFICIENT_BALANCE =6;
INCOMPLETE_FORWARD = 7;
HTLC_ADD_FAILED = 8;
FORWARDS_DISABLED = 9;
INVOICE_CANCELED = 10;
INVOICE_UNDERPAID = 11;
INVOICE_EXPIRY_TOO_SOON = 12;
INVOICE_NOT_OPEN = 13;
MPP_INVOICE_TIMEOUT = 14;
ADDRESS_MISMATCH = 15;
SET_TOTAL_MISMATCH = 16;
SET_TOTAL_TOO_LOW = 17;
SET_OVERPAID = 18;
UNKNOWN_INVOICE = 19;
INVALID_KEYSEND = 20;
MPP_IN_PROGRESS = 21;
CIRCULAR_ROUTE = 22;
}
service Router {
/**
SendPayment attempts to route a payment described by the passed
@ -387,4 +516,10 @@ service Router {
calculate the correct fees and time locks.
*/
rpc BuildRoute (BuildRouteRequest) returns (BuildRouteResponse);
/**
SubscribeHtlcEvents creates a uni-directional stream from the server to
the client which delivers a stream of htlc events.
*/
rpc SubscribeHtlcEvents (SubscribeHtlcEventsRequest) returns (stream HtlcEvent);
}

@ -20,6 +20,7 @@ import (
"github.com/lightningnetwork/lnd/record"
"github.com/lightningnetwork/lnd/routing"
"github.com/lightningnetwork/lnd/routing/route"
"github.com/lightningnetwork/lnd/subscribe"
"github.com/lightningnetwork/lnd/zpay32"
)
@ -68,6 +69,10 @@ type RouterBackend struct {
// DefaultFinalCltvDelta is the default value used as final cltv delta
// when an RPC caller doesn't specify a value.
DefaultFinalCltvDelta uint16
// SubscribeHtlcEvents returns a subscription client for the node's
// htlc events.
SubscribeHtlcEvents func() (*subscribe.Client, error)
}
// MissionControl defines the mission control dependencies of routerrpc.

@ -9,6 +9,7 @@ import (
"io/ioutil"
"os"
"path/filepath"
"sync/atomic"
"github.com/btcsuite/btcutil"
"github.com/lightningnetwork/lnd/channeldb"
@ -32,6 +33,8 @@ const (
)
var (
errServerShuttingDown = errors.New("routerrpc server shutting down")
// macaroonOps are the set of capabilities that our minted macaroon (if
// it doesn't already exist) will have.
macaroonOps = []bakery.Op{
@ -79,6 +82,10 @@ var (
Entity: "offchain",
Action: "read",
}},
"/routerrpc.Router/SubscribeHtlcEvents": {{
Entity: "offchain",
Action: "read",
}},
}
// DefaultRouterMacFilename is the default name of the router macaroon
@ -90,7 +97,12 @@ var (
// Server is a stand alone sub RPC server which exposes functionality that
// allows clients to route arbitrary payment through the Lightning Network.
type Server struct {
started int32 // To be used atomically.
shutdown int32 // To be used atomically.
cfg *Config
quit chan struct{}
}
// A compile time check to ensure that Server fully implements the RouterServer
@ -150,7 +162,8 @@ func New(cfg *Config) (*Server, lnrpc.MacaroonPerms, error) {
}
routerServer := &Server{
cfg: cfg,
cfg: cfg,
quit: make(chan struct{}),
}
return routerServer, macPermissions, nil
@ -160,6 +173,10 @@ func New(cfg *Config) (*Server, lnrpc.MacaroonPerms, error) {
//
// NOTE: This is part of the lnrpc.SubServer interface.
func (s *Server) Start() error {
if atomic.AddInt32(&s.started, 1) != 1 {
return nil
}
return nil
}
@ -167,6 +184,11 @@ func (s *Server) Start() error {
//
// NOTE: This is part of the lnrpc.SubServer interface.
func (s *Server) Stop() error {
if atomic.AddInt32(&s.shutdown, 1) != 1 {
return nil
}
close(s.quit)
return nil
}
@ -513,6 +535,9 @@ func (s *Server) trackPayment(paymentHash lntypes.Hash,
return err
}
case <-s.quit:
return errServerShuttingDown
case <-stream.Context().Done():
log.Debugf("Payment status stream %v canceled", paymentHash)
return stream.Context().Err()
@ -592,3 +617,42 @@ func (s *Server) BuildRoute(ctx context.Context,
return routeResp, nil
}
// SubscribeHtlcEvents creates a uni-directional stream from the server to
// the client which delivers a stream of htlc events.
func (s *Server) SubscribeHtlcEvents(req *SubscribeHtlcEventsRequest,
stream Router_SubscribeHtlcEventsServer) error {
htlcClient, err := s.cfg.RouterBackend.SubscribeHtlcEvents()
if err != nil {
return err
}
defer htlcClient.Cancel()
for {
select {
case event := <-htlcClient.Updates():
rpcEvent, err := rpcHtlcEvent(event)
if err != nil {
return err
}
if err := stream.Send(rpcEvent); err != nil {
return err
}
// If the stream's context is cancelled, return an error.
case <-stream.Context().Done():
log.Debugf("htlc event stream cancelled")
return stream.Context().Err()
// If the subscribe client terminates, exit with an error.
case <-htlcClient.Quit():
return errors.New("htlc event subscription terminated")
// If the server has been signalled to shut down, exit.
case <-s.quit:
return errServerShuttingDown
}
}
}

@ -0,0 +1,241 @@
// +build routerrpc
package routerrpc
import (
"fmt"
"time"
"github.com/lightningnetwork/lnd/htlcswitch"
"github.com/lightningnetwork/lnd/invoices"
"github.com/lightningnetwork/lnd/lnrpc"
)
// rpcHtlcEvent returns a rpc htlc event from a htlcswitch event.
func rpcHtlcEvent(htlcEvent interface{}) (*HtlcEvent, error) {
var (
key htlcswitch.HtlcKey
timestamp time.Time
eventType htlcswitch.HtlcEventType
event isHtlcEvent_Event
)
switch e := htlcEvent.(type) {
case *htlcswitch.ForwardingEvent:
event = &HtlcEvent_ForwardEvent{
ForwardEvent: &ForwardEvent{
Info: rpcInfo(e.HtlcInfo),
},
}
key = e.HtlcKey
eventType = e.HtlcEventType
timestamp = e.Timestamp
case *htlcswitch.ForwardingFailEvent:
event = &HtlcEvent_ForwardFailEvent{
ForwardFailEvent: &ForwardFailEvent{},
}
key = e.HtlcKey
eventType = e.HtlcEventType
timestamp = e.Timestamp
case *htlcswitch.LinkFailEvent:
failureCode, failReason, err := rpcFailReason(
e.LinkError,
)
if err != nil {
return nil, err
}
event = &HtlcEvent_LinkFailEvent{
LinkFailEvent: &LinkFailEvent{
Info: rpcInfo(e.HtlcInfo),
WireFailure: failureCode,
FailureDetail: failReason,
FailureString: e.LinkError.Error(),
},
}
key = e.HtlcKey
eventType = e.HtlcEventType
timestamp = e.Timestamp
case *htlcswitch.SettleEvent:
event = &HtlcEvent_SettleEvent{
SettleEvent: &SettleEvent{},
}
key = e.HtlcKey
eventType = e.HtlcEventType
timestamp = e.Timestamp
default:
return nil, fmt.Errorf("unknown event type: %T", e)
}
rpcEvent := &HtlcEvent{
IncomingChannelId: key.IncomingCircuit.ChanID.ToUint64(),
OutgoingChannelId: key.OutgoingCircuit.ChanID.ToUint64(),
IncomingHtlcId: key.IncomingCircuit.HtlcID,
OutgoingHtlcId: key.OutgoingCircuit.HtlcID,
TimestampNs: uint64(timestamp.UnixNano()),
Event: event,
}
// Convert the htlc event type to a rpc event.
switch eventType {
case htlcswitch.HtlcEventTypeSend:
rpcEvent.EventType = HtlcEvent_SEND
case htlcswitch.HtlcEventTypeReceive:
rpcEvent.EventType = HtlcEvent_RECEIVE
case htlcswitch.HtlcEventTypeForward:
rpcEvent.EventType = HtlcEvent_FORWARD
default:
return nil, fmt.Errorf("unknown event type: %v", eventType)
}
return rpcEvent, nil
}
// rpcInfo returns a rpc struct containing the htlc information from the
// switch's htlc info struct.
func rpcInfo(info htlcswitch.HtlcInfo) *HtlcInfo {
return &HtlcInfo{
IncomingTimelock: info.IncomingTimeLock,
OutgoingTimelock: info.OutgoingTimeLock,
IncomingAmtMsat: uint64(info.IncomingAmt),
OutgoingAmtMsat: uint64(info.OutgoingAmt),
}
}
// rpcFailReason maps a lnwire failure message and failure detail to a rpc
// failure code and detail.
func rpcFailReason(linkErr *htlcswitch.LinkError) (lnrpc.Failure_FailureCode,
FailureDetail, error) {
wireErr, err := marshallError(linkErr)
if err != nil {
return 0, 0, err
}
switch failureDetail := linkErr.FailureDetail.(type) {
case invoices.FailResolutionResult:
fd, err := rpcFailureResolution(failureDetail)
return wireErr.GetCode(), fd, err
case htlcswitch.OutgoingFailure:
fd, err := rpcOutgoingFailure(failureDetail)
return wireErr.GetCode(), fd, err
default:
return 0, 0, fmt.Errorf("unknown failure "+
"detail type: %T", linkErr.FailureDetail)
}
}
// rpcFailureResolution maps an invoice failure resolution to a rpc failure
// detail. Invoice failures have no zero resolution results (every failure
// is accompanied with a result), so we error if we fail to match the result
// type.
func rpcFailureResolution(invoiceFailure invoices.FailResolutionResult) (
FailureDetail, error) {
switch invoiceFailure {
case invoices.ResultReplayToCanceled:
return FailureDetail_INVOICE_CANCELED, nil
case invoices.ResultInvoiceAlreadyCanceled:
return FailureDetail_INVOICE_CANCELED, nil
case invoices.ResultAmountTooLow:
return FailureDetail_INVOICE_UNDERPAID, nil
case invoices.ResultExpiryTooSoon:
return FailureDetail_INVOICE_EXPIRY_TOO_SOON, nil
case invoices.ResultCanceled:
return FailureDetail_INVOICE_CANCELED, nil
case invoices.ResultInvoiceNotOpen:
return FailureDetail_INVOICE_NOT_OPEN, nil
case invoices.ResultMppTimeout:
return FailureDetail_MPP_INVOICE_TIMEOUT, nil
case invoices.ResultAddressMismatch:
return FailureDetail_ADDRESS_MISMATCH, nil
case invoices.ResultHtlcSetTotalMismatch:
return FailureDetail_SET_TOTAL_MISMATCH, nil
case invoices.ResultHtlcSetTotalTooLow:
return FailureDetail_SET_TOTAL_TOO_LOW, nil
case invoices.ResultHtlcSetOverpayment:
return FailureDetail_SET_OVERPAID, nil
case invoices.ResultInvoiceNotFound:
return FailureDetail_UNKNOWN_INVOICE, nil
case invoices.ResultKeySendError:
return FailureDetail_INVALID_KEYSEND, nil
case invoices.ResultMppInProgress:
return FailureDetail_MPP_IN_PROGRESS, nil
default:
return 0, fmt.Errorf("unknown fail resolution: %v",
invoiceFailure.FailureString())
}
}
// rpcOutgoingFailure maps an outgoing failure to a rpc FailureDetail. If the
// failure detail is FailureDetailNone, which indicates that the failure was
// a wire message which required no further failure detail, we return a no
// detail failure detail to indicate that there was no additional information.
func rpcOutgoingFailure(failureDetail htlcswitch.OutgoingFailure) (
FailureDetail, error) {
switch failureDetail {
case htlcswitch.OutgoingFailureNone:
return FailureDetail_NO_DETAIL, nil
case htlcswitch.OutgoingFailureDecodeError:
return FailureDetail_ONION_DECODE, nil
case htlcswitch.OutgoingFailureLinkNotEligible:
return FailureDetail_LINK_NOT_ELIGIBLE, nil
case htlcswitch.OutgoingFailureOnChainTimeout:
return FailureDetail_ON_CHAIN_TIMEOUT, nil
case htlcswitch.OutgoingFailureHTLCExceedsMax:
return FailureDetail_HTLC_EXCEEDS_MAX, nil
case htlcswitch.OutgoingFailureInsufficientBalance:
return FailureDetail_INSUFFICIENT_BALANCE, nil
case htlcswitch.OutgoingFailureCircularRoute:
return FailureDetail_CIRCULAR_ROUTE, nil
case htlcswitch.OutgoingFailureIncompleteForward:
return FailureDetail_INCOMPLETE_FORWARD, nil
case htlcswitch.OutgoingFailureDownstreamHtlcAdd:
return FailureDetail_HTLC_ADD_FAILED, nil
case htlcswitch.OutgoingFailureForwardsDisabled:
return FailureDetail_FORWARDS_DISABLED, nil
default:
return 0, fmt.Errorf("unknown outgoing failure "+
"detail: %v", failureDetail.FailureString())
}
}

@ -567,6 +567,7 @@ func newRPCServer(s *server, macService *macaroons.Service,
Tower: s.controlTower,
MaxTotalTimelock: cfg.MaxOutgoingCltvExpiry,
DefaultFinalCltvDelta: uint16(cfg.Bitcoin.TimeLockDelta),
SubscribeHtlcEvents: s.htlcNotifier.SubscribeHtlcEvents,
}
genInvoiceFeatures := func() *lnwire.FeatureVector {