From 2594abfba124b36161cd90d979dab9f1150c4650 Mon Sep 17 00:00:00 2001 From: Joost Jager Date: Wed, 14 Aug 2019 14:06:53 +0200 Subject: [PATCH 1/2] routing/test: remove unused parameter in mission control test --- routing/missioncontrol_test.go | 25 +++++++------------------ 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/routing/missioncontrol_test.go b/routing/missioncontrol_test.go index cbc7194d..14091923 100644 --- a/routing/missioncontrol_test.go +++ b/routing/missioncontrol_test.go @@ -103,8 +103,8 @@ func (ctx *mcTestContext) expectP(amt lnwire.MilliSatoshi, expected float64) { } // reportFailure reports a failure by using a test route. -func (ctx *mcTestContext) reportFailure(t time.Time, - amt lnwire.MilliSatoshi, failure lnwire.FailureMessage) { +func (ctx *mcTestContext) reportFailure(amt lnwire.MilliSatoshi, + failure lnwire.FailureMessage) { mcTestRoute.Hops[0].AmtToForward = amt @@ -127,10 +127,7 @@ func TestMissionControl(t *testing.T) { ctx.expectP(1000, 0.8) // Expect probability to be zero after reporting the edge as failed. - ctx.reportFailure( - testTime, 1000, - lnwire.NewTemporaryChannelFailure(nil), - ) + ctx.reportFailure(1000, lnwire.NewTemporaryChannelFailure(nil)) ctx.expectP(1000, 0) // As we reported with a min penalization amt, a lower amt than reported @@ -143,10 +140,7 @@ func TestMissionControl(t *testing.T) { // Edge fails again, this time without a min penalization amt. The edge // should be penalized regardless of amount. - ctx.reportFailure( - ctx.now, 0, - lnwire.NewTemporaryChannelFailure(nil), - ) + ctx.reportFailure(0, lnwire.NewTemporaryChannelFailure(nil)) ctx.expectP(1000, 0) ctx.expectP(500, 0) @@ -160,10 +154,7 @@ func TestMissionControl(t *testing.T) { // A node level failure should bring probability of every channel back // to zero. - ctx.reportFailure( - ctx.now, 0, - lnwire.NewExpiryTooSoon(lnwire.ChannelUpdate{}), - ) + ctx.reportFailure(0, lnwire.NewExpiryTooSoon(lnwire.ChannelUpdate{})) ctx.expectP(1000, 0) // Check whether history snapshot looks sane. @@ -186,16 +177,14 @@ func TestMissionControlChannelUpdate(t *testing.T) { // Report a policy related failure. Because it is the first, we don't // expect a penalty. ctx.reportFailure( - ctx.now, 0, - lnwire.NewFeeInsufficient(0, lnwire.ChannelUpdate{}), + 0, lnwire.NewFeeInsufficient(0, lnwire.ChannelUpdate{}), ) ctx.expectP(0, 0.8) // Report another failure for the same channel. We expect it to be // pruned. ctx.reportFailure( - ctx.now, 0, - lnwire.NewFeeInsufficient(0, lnwire.ChannelUpdate{}), + 0, lnwire.NewFeeInsufficient(0, lnwire.ChannelUpdate{}), ) ctx.expectP(0, 0) } From ff0c5a0d5eeed32a2561e90f19c164ac6992ae9b Mon Sep 17 00:00:00 2001 From: Joost Jager Date: Mon, 29 Jul 2019 14:20:06 +0200 Subject: [PATCH 2/2] routing: process successes in mission control This commit modifies paymentLifecycle so that it not only feeds failures into mission control, but successes as well. This allows for more accurate probability estimates. Previously, the success probability for a successful pair and a pair with no history was equal. There was no force that pushed towards previously successful routes. --- cmd/lncli/cmd_query_mission_control.go | 20 +- lnrpc/routerrpc/router.pb.go | 248 +++++++++++++------------ lnrpc/routerrpc/router.proto | 9 +- lnrpc/routerrpc/router_server.go | 9 +- routing/missioncontrol.go | 100 +++++++--- routing/missioncontrol_test.go | 17 +- routing/mock_test.go | 6 + routing/pathfind.go | 2 +- routing/payment_lifecycle.go | 9 + routing/result_interpretation.go | 97 ++++++++-- routing/result_interpretation_test.go | 84 +++++++-- routing/router.go | 4 + 12 files changed, 415 insertions(+), 190 deletions(-) diff --git a/cmd/lncli/cmd_query_mission_control.go b/cmd/lncli/cmd_query_mission_control.go index d073c5f0..3c13a09b 100644 --- a/cmd/lncli/cmd_query_mission_control.go +++ b/cmd/lncli/cmd_query_mission_control.go @@ -38,10 +38,11 @@ func queryMissionControl(ctx *cli.Context) error { } type displayPairHistory struct { - NodeFrom, NodeTo string - LastFailTime int64 - SuccessProb float32 - MinPenalizeAmtSat int64 + NodeFrom, NodeTo string + LastAttemptSuccessful bool + Timestamp int64 + SuccessProb float32 + MinPenalizeAmtSat int64 } displayResp := struct { @@ -64,11 +65,12 @@ func queryMissionControl(ctx *cli.Context) error { displayResp.Pairs = append( displayResp.Pairs, displayPairHistory{ - NodeFrom: hex.EncodeToString(n.NodeFrom), - NodeTo: hex.EncodeToString(n.NodeTo), - LastFailTime: n.LastFailTime, - SuccessProb: n.SuccessProb, - MinPenalizeAmtSat: n.MinPenalizeAmtSat, + NodeFrom: hex.EncodeToString(n.NodeFrom), + NodeTo: hex.EncodeToString(n.NodeTo), + LastAttemptSuccessful: n.LastAttemptSuccessful, + Timestamp: n.Timestamp, + SuccessProb: n.SuccessProb, + MinPenalizeAmtSat: n.MinPenalizeAmtSat, }, ) } diff --git a/lnrpc/routerrpc/router.pb.go b/lnrpc/routerrpc/router.pb.go index 86331e85..86a69c2c 100644 --- a/lnrpc/routerrpc/router.pb.go +++ b/lnrpc/routerrpc/router.pb.go @@ -1108,15 +1108,17 @@ type PairHistory struct { NodeFrom []byte `protobuf:"bytes,1,opt,name=node_from,proto3" json:"node_from,omitempty"` /// The destination node pubkey of the pair. NodeTo []byte `protobuf:"bytes,2,opt,name=node_to,proto3" json:"node_to,omitempty"` - /// Time stamp of last failure. - LastFailTime int64 `protobuf:"varint,3,opt,name=last_fail_time,proto3" json:"last_fail_time,omitempty"` - /// Minimum penalization amount. + /// Time stamp of last result. + Timestamp int64 `protobuf:"varint,3,opt,name=timestamp,proto3" json:"timestamp,omitempty"` + /// Minimum penalization amount (only applies to failed attempts). MinPenalizeAmtSat int64 `protobuf:"varint,4,opt,name=min_penalize_amt_sat,proto3" json:"min_penalize_amt_sat,omitempty"` /// Estimation of success probability for this pair. - SuccessProb float32 `protobuf:"fixed32,5,opt,name=success_prob,proto3" json:"success_prob,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + SuccessProb float32 `protobuf:"fixed32,5,opt,name=success_prob,proto3" json:"success_prob,omitempty"` + /// Whether the last payment attempt through this pair was successful. + LastAttemptSuccessful bool `protobuf:"varint,6,opt,name=last_attempt_successful,proto3" json:"last_attempt_successful,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *PairHistory) Reset() { *m = PairHistory{} } @@ -1158,9 +1160,9 @@ func (m *PairHistory) GetNodeTo() []byte { return nil } -func (m *PairHistory) GetLastFailTime() int64 { +func (m *PairHistory) GetTimestamp() int64 { if m != nil { - return m.LastFailTime + return m.Timestamp } return 0 } @@ -1179,6 +1181,13 @@ func (m *PairHistory) GetSuccessProb() float32 { return 0 } +func (m *PairHistory) GetLastAttemptSuccessful() bool { + if m != nil { + return m.LastAttemptSuccessful + } + return false +} + func init() { proto.RegisterEnum("routerrpc.PaymentState", PaymentState_name, PaymentState_value) proto.RegisterEnum("routerrpc.Failure_FailureCode", Failure_FailureCode_name, Failure_FailureCode_value) @@ -1203,116 +1212,117 @@ func init() { func init() { proto.RegisterFile("routerrpc/router.proto", fileDescriptor_7a0613f69d37b0a5) } var fileDescriptor_7a0613f69d37b0a5 = []byte{ - // 1736 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x57, 0x41, 0x73, 0x22, 0xc7, - 0x15, 0x36, 0x02, 0x84, 0x78, 0x80, 0x98, 0x6d, 0x69, 0xb5, 0xb3, 0x68, 0x65, 0xcb, 0xd8, 0x59, - 0xab, 0xb6, 0x1c, 0xc9, 0x21, 0x65, 0x97, 0xcb, 0x87, 0xa4, 0x58, 0x68, 0xac, 0xd9, 0x85, 0x19, - 0xb9, 0x81, 0xb5, 0x37, 0x39, 0x74, 0xb5, 0xa0, 0x05, 0x53, 0x1a, 0x66, 0xf0, 0x4c, 0xa3, 0xac, - 0x72, 0xc8, 0x25, 0x95, 0x63, 0xee, 0xf9, 0x17, 0xf9, 0x15, 0x39, 0xe4, 0x8f, 0x24, 0xbf, 0x22, - 0x55, 0xa9, 0xee, 0x9e, 0x81, 0x01, 0xb1, 0x9b, 0x9c, 0x98, 0xfe, 0xde, 0xd7, 0xaf, 0x5f, 0xf7, - 0xeb, 0xf7, 0xf5, 0x03, 0x8e, 0xc2, 0x60, 0x21, 0x78, 0x18, 0xce, 0x47, 0x17, 0xfa, 0xeb, 0x7c, - 0x1e, 0x06, 0x22, 0x40, 0xc5, 0x25, 0x5e, 0x2b, 0x86, 0xf3, 0x91, 0x46, 0xeb, 0xff, 0xc9, 0x02, - 0xea, 0x73, 0x7f, 0x7c, 0xc5, 0xee, 0x67, 0xdc, 0x17, 0x84, 0xff, 0xbc, 0xe0, 0x91, 0x40, 0x08, - 0x72, 0x63, 0x1e, 0x09, 0x33, 0x73, 0x9a, 0x39, 0x2b, 0x13, 0xf5, 0x8d, 0x0c, 0xc8, 0xb2, 0x99, - 0x30, 0x77, 0x4e, 0x33, 0x67, 0x59, 0x22, 0x3f, 0xd1, 0xa7, 0x50, 0x9e, 0xeb, 0x79, 0x74, 0xca, - 0xa2, 0xa9, 0x99, 0x55, 0xec, 0x52, 0x8c, 0x5d, 0xb2, 0x68, 0x8a, 0xce, 0xc0, 0xb8, 0x71, 0x7d, - 0xe6, 0xd1, 0x91, 0x27, 0xee, 0xe8, 0x98, 0x7b, 0x82, 0x99, 0xb9, 0xd3, 0xcc, 0x59, 0x9e, 0xec, - 0x2b, 0xbc, 0xe5, 0x89, 0xbb, 0xb6, 0x44, 0xd1, 0x17, 0x50, 0x4d, 0x9c, 0x85, 0x3a, 0x0a, 0x33, - 0x7f, 0x9a, 0x39, 0x2b, 0x92, 0xfd, 0xf9, 0x7a, 0x6c, 0x5f, 0x40, 0x55, 0xb8, 0x33, 0x1e, 0x2c, - 0x04, 0x8d, 0xf8, 0x28, 0xf0, 0xc7, 0x91, 0xb9, 0xab, 0x3d, 0xc6, 0x70, 0x5f, 0xa3, 0xa8, 0x0e, - 0x95, 0x1b, 0xce, 0xa9, 0xe7, 0xce, 0x5c, 0x41, 0x23, 0x26, 0xcc, 0x82, 0x0a, 0xbd, 0x74, 0xc3, - 0x79, 0x57, 0x62, 0x7d, 0x26, 0x64, 0x7c, 0xc1, 0x42, 0x4c, 0x02, 0xd7, 0x9f, 0xd0, 0xd1, 0x94, - 0xf9, 0xd4, 0x1d, 0x9b, 0x7b, 0xa7, 0x99, 0xb3, 0x1c, 0xd9, 0x4f, 0xf0, 0xd6, 0x94, 0xf9, 0xd6, - 0x18, 0x9d, 0x00, 0xa8, 0x3d, 0x28, 0x77, 0x66, 0x51, 0xad, 0x58, 0x94, 0x88, 0xf2, 0x85, 0x1a, - 0x50, 0x52, 0x07, 0x4c, 0xa7, 0xae, 0x2f, 0x22, 0x13, 0x4e, 0xb3, 0x67, 0xa5, 0x86, 0x71, 0xee, - 0xf9, 0xf2, 0xac, 0x89, 0xb4, 0x5c, 0xba, 0xbe, 0x20, 0x69, 0x12, 0xc2, 0xb0, 0x27, 0x4f, 0x96, - 0x0a, 0xef, 0xce, 0x2c, 0xa9, 0x09, 0x2f, 0xce, 0x97, 0x59, 0x3a, 0x7f, 0x98, 0x96, 0xf3, 0x36, - 0x8f, 0xc4, 0xc0, 0xbb, 0xc3, 0xbe, 0x08, 0xef, 0x49, 0x61, 0xac, 0x47, 0xb5, 0xef, 0xa0, 0x9c, - 0x36, 0xc8, 0x44, 0xdd, 0xf2, 0x7b, 0x95, 0xbb, 0x1c, 0x91, 0x9f, 0xe8, 0x10, 0xf2, 0x77, 0xcc, - 0x5b, 0x70, 0x95, 0xbc, 0x32, 0xd1, 0x83, 0xef, 0x76, 0xbe, 0xcd, 0xd4, 0xbf, 0x85, 0x83, 0x41, - 0xc8, 0x46, 0xb7, 0x1b, 0xf9, 0xdf, 0xcc, 0x6c, 0xe6, 0x41, 0x66, 0xeb, 0x7f, 0x82, 0x4a, 0x3c, - 0xa9, 0x2f, 0x98, 0x58, 0x44, 0xe8, 0x97, 0x90, 0x8f, 0x04, 0x13, 0x5c, 0x91, 0xf7, 0x1b, 0x4f, - 0x52, 0x5b, 0x49, 0x11, 0x39, 0xd1, 0x2c, 0x54, 0x83, 0xbd, 0x79, 0xc8, 0xdd, 0x19, 0x9b, 0x24, - 0x61, 0x2d, 0xc7, 0xa8, 0x0e, 0x79, 0x35, 0x59, 0xdd, 0xa8, 0x52, 0xa3, 0x9c, 0x3e, 0x46, 0xa2, - 0x4d, 0xf5, 0xdf, 0x40, 0x55, 0x8d, 0x3b, 0x9c, 0x7f, 0xe8, 0xd6, 0x3e, 0x81, 0x02, 0x9b, 0xe9, - 0xf4, 0xeb, 0x9b, 0xbb, 0xcb, 0x66, 0x32, 0xf3, 0xf5, 0x31, 0x18, 0xab, 0xf9, 0xd1, 0x3c, 0xf0, - 0x23, 0x2e, 0x6f, 0x83, 0x74, 0x2e, 0x2f, 0x83, 0xbc, 0x39, 0x33, 0x39, 0x2b, 0xa3, 0x66, 0xed, - 0xc7, 0x78, 0x87, 0xf3, 0x5e, 0xc4, 0x04, 0x7a, 0xae, 0x2f, 0x21, 0xf5, 0x82, 0xd1, 0xad, 0xbc, - 0xd6, 0xec, 0x3e, 0x76, 0x5f, 0x91, 0x70, 0x37, 0x18, 0xdd, 0xb6, 0x25, 0x58, 0xff, 0xbd, 0x2e, - 0xaf, 0x41, 0xa0, 0x63, 0xff, 0xbf, 0x8f, 0x77, 0x75, 0x04, 0x3b, 0xef, 0x3f, 0x02, 0x0a, 0x07, - 0x6b, 0xce, 0xe3, 0x5d, 0xa4, 0x4f, 0x36, 0xb3, 0x71, 0xb2, 0x5f, 0x42, 0xe1, 0x86, 0xb9, 0xde, - 0x22, 0x4c, 0x1c, 0xa3, 0x54, 0x9a, 0x3a, 0xda, 0x42, 0x12, 0x4a, 0xfd, 0x9f, 0x05, 0x28, 0xc4, - 0x20, 0x6a, 0x40, 0x6e, 0x14, 0x8c, 0x93, 0xec, 0x7e, 0xfc, 0x70, 0x5a, 0xf2, 0xdb, 0x0a, 0xc6, - 0x9c, 0x28, 0x2e, 0xfa, 0x2d, 0xec, 0xcb, 0xa2, 0xf2, 0xb9, 0x47, 0x17, 0xf3, 0x31, 0x5b, 0x26, - 0xd4, 0x4c, 0xcd, 0x6e, 0x69, 0xc2, 0x50, 0xd9, 0x49, 0x65, 0x94, 0x1e, 0xa2, 0x63, 0x28, 0x4e, - 0x85, 0x37, 0xd2, 0x99, 0xc8, 0xa9, 0x0b, 0xbd, 0x27, 0x01, 0x95, 0x83, 0x3a, 0x54, 0x02, 0xdf, - 0x0d, 0x7c, 0x1a, 0x4d, 0x19, 0x6d, 0x7c, 0xfd, 0x8d, 0xd2, 0x8b, 0x32, 0x29, 0x29, 0xb0, 0x3f, - 0x65, 0x8d, 0xaf, 0xbf, 0x41, 0x9f, 0x40, 0x49, 0x55, 0x2d, 0x7f, 0x37, 0x77, 0xc3, 0x7b, 0x25, - 0x14, 0x15, 0xa2, 0x0a, 0x19, 0x2b, 0x44, 0x96, 0xc6, 0x8d, 0xc7, 0x26, 0x91, 0x12, 0x87, 0x0a, - 0xd1, 0x03, 0xf4, 0x15, 0x1c, 0xc6, 0x67, 0x40, 0xa3, 0x60, 0x11, 0x8e, 0x38, 0x75, 0xfd, 0x31, - 0x7f, 0xa7, 0xa4, 0xa1, 0x42, 0x50, 0x6c, 0xeb, 0x2b, 0x93, 0x25, 0x2d, 0xf5, 0xbf, 0xe5, 0xa1, - 0x94, 0x3a, 0x00, 0x54, 0x86, 0x3d, 0x82, 0xfb, 0x98, 0xbc, 0xc1, 0x6d, 0xe3, 0x23, 0x74, 0x06, - 0x9f, 0x5b, 0x76, 0xcb, 0x21, 0x04, 0xb7, 0x06, 0xd4, 0x21, 0x74, 0x68, 0xbf, 0xb6, 0x9d, 0x1f, - 0x6d, 0x7a, 0xd5, 0x7c, 0xdb, 0xc3, 0xf6, 0x80, 0xb6, 0xf1, 0xa0, 0x69, 0x75, 0xfb, 0x46, 0x06, - 0x3d, 0x03, 0x73, 0xc5, 0x4c, 0xcc, 0xcd, 0x9e, 0x33, 0xb4, 0x07, 0xc6, 0x0e, 0xfa, 0x04, 0x8e, - 0x3b, 0x96, 0xdd, 0xec, 0xd2, 0x15, 0xa7, 0xd5, 0x1d, 0xbc, 0xa1, 0xf8, 0xa7, 0x2b, 0x8b, 0xbc, - 0x35, 0xb2, 0xdb, 0x08, 0x97, 0x83, 0x6e, 0x2b, 0xf1, 0x90, 0x43, 0x4f, 0xe1, 0xb1, 0x26, 0xe8, - 0x29, 0x74, 0xe0, 0x38, 0xb4, 0xef, 0x38, 0xb6, 0x91, 0x47, 0x8f, 0xa0, 0x62, 0xd9, 0x6f, 0x9a, - 0x5d, 0xab, 0x4d, 0x09, 0x6e, 0x76, 0x7b, 0xc6, 0x2e, 0x3a, 0x80, 0xea, 0x26, 0xaf, 0x20, 0x5d, - 0x24, 0x3c, 0xc7, 0xb6, 0x1c, 0x9b, 0xbe, 0xc1, 0xa4, 0x6f, 0x39, 0xb6, 0xb1, 0x87, 0x8e, 0x00, - 0xad, 0x9b, 0x2e, 0x7b, 0xcd, 0x96, 0x51, 0x44, 0x8f, 0xe1, 0xd1, 0x3a, 0xfe, 0x1a, 0xbf, 0x35, - 0x00, 0x99, 0x70, 0xa8, 0x03, 0xa3, 0x2f, 0x71, 0xd7, 0xf9, 0x91, 0xf6, 0x2c, 0xdb, 0xea, 0x0d, - 0x7b, 0x46, 0x09, 0x1d, 0x82, 0xd1, 0xc1, 0x98, 0x5a, 0x76, 0x7f, 0xd8, 0xe9, 0x58, 0x2d, 0x0b, - 0xdb, 0x03, 0xa3, 0xac, 0x57, 0xde, 0xb6, 0xf1, 0x8a, 0x9c, 0xd0, 0xba, 0x6c, 0xda, 0x36, 0xee, - 0xd2, 0xb6, 0xd5, 0x6f, 0xbe, 0xec, 0xe2, 0xb6, 0xb1, 0x8f, 0x4e, 0xe0, 0xe9, 0x00, 0xf7, 0xae, - 0x1c, 0xd2, 0x24, 0x6f, 0x69, 0x62, 0xef, 0x34, 0xad, 0xee, 0x90, 0x60, 0xa3, 0x8a, 0x3e, 0x85, - 0x13, 0x82, 0x7f, 0x18, 0x5a, 0x04, 0xb7, 0xa9, 0xed, 0xb4, 0x31, 0xed, 0xe0, 0xe6, 0x60, 0x48, - 0x30, 0xed, 0x59, 0xfd, 0xbe, 0x65, 0x7f, 0x6f, 0x18, 0xe8, 0x73, 0x38, 0x5d, 0x52, 0x96, 0x0e, - 0x36, 0x58, 0x8f, 0xe4, 0xfe, 0x92, 0x94, 0xda, 0xf8, 0xa7, 0x01, 0xbd, 0xc2, 0x98, 0x18, 0x08, - 0xd5, 0xe0, 0x68, 0xb5, 0xbc, 0x5e, 0x20, 0x5e, 0xfb, 0x40, 0xda, 0xae, 0x30, 0xe9, 0x35, 0x6d, - 0x99, 0xe0, 0x35, 0xdb, 0xa1, 0x0c, 0x7b, 0x65, 0xdb, 0x0c, 0xfb, 0x31, 0x3a, 0x84, 0x6a, 0xb2, - 0x5a, 0x02, 0xfe, 0xab, 0x80, 0x9e, 0x00, 0x1a, 0xda, 0x04, 0x37, 0xdb, 0x72, 0xf3, 0x4b, 0xc3, - 0xbf, 0x0b, 0xaf, 0x72, 0x7b, 0x3b, 0x46, 0xb6, 0xfe, 0xf7, 0x2c, 0x54, 0xd6, 0x6a, 0x0d, 0x3d, - 0x83, 0x62, 0xe4, 0x4e, 0x7c, 0x26, 0xa4, 0x1a, 0x68, 0xa1, 0x58, 0x01, 0xea, 0xbd, 0x9b, 0x32, - 0xd7, 0xd7, 0x0a, 0xa5, 0x15, 0xba, 0xa8, 0x10, 0xa5, 0x4f, 0x4f, 0xa0, 0x90, 0xbc, 0x97, 0x59, - 0x55, 0x97, 0xbb, 0x23, 0xfd, 0x4e, 0x3e, 0x83, 0xa2, 0x94, 0xc0, 0x48, 0xb0, 0xd9, 0x5c, 0x95, - 0x6c, 0x85, 0xac, 0x00, 0xf4, 0x19, 0x54, 0x66, 0x3c, 0x8a, 0xd8, 0x84, 0x53, 0x5d, 0x76, 0xa0, - 0x18, 0xe5, 0x18, 0xec, 0xa8, 0xea, 0xfb, 0x0c, 0x12, 0x19, 0x88, 0x49, 0x79, 0x4d, 0x8a, 0x41, - 0x4d, 0xda, 0x54, 0x60, 0xc1, 0xe2, 0xea, 0x4e, 0x2b, 0xb0, 0x60, 0xe8, 0x05, 0x3c, 0xd2, 0x12, - 0xe2, 0xfa, 0xee, 0x6c, 0x31, 0xd3, 0x52, 0x52, 0x50, 0x21, 0x57, 0x95, 0x94, 0x68, 0x5c, 0x29, - 0xca, 0x53, 0xd8, 0xbb, 0x66, 0x11, 0x97, 0xe2, 0x1f, 0x97, 0x7a, 0x41, 0x8e, 0x3b, 0x9c, 0x4b, - 0x93, 0x7c, 0x12, 0x42, 0x29, 0x62, 0x45, 0x6d, 0xba, 0xe1, 0x9c, 0xc8, 0x73, 0x5c, 0xae, 0xc0, - 0xde, 0xad, 0x56, 0x28, 0xa5, 0x56, 0xd0, 0xb8, 0x5a, 0xe1, 0x05, 0x3c, 0xe2, 0xef, 0x44, 0xc8, - 0x68, 0x30, 0x67, 0x3f, 0x2f, 0x38, 0x1d, 0x33, 0xc1, 0xcc, 0xb2, 0x3a, 0xdc, 0xaa, 0x32, 0x38, - 0x0a, 0x6f, 0x33, 0xc1, 0xea, 0xcf, 0xa0, 0x46, 0x78, 0xc4, 0x45, 0xcf, 0x8d, 0x22, 0x37, 0xf0, - 0x5b, 0x81, 0x2f, 0xc2, 0xc0, 0x8b, 0xdf, 0x90, 0xfa, 0x09, 0x1c, 0x6f, 0xb5, 0xea, 0x47, 0x40, - 0x4e, 0xfe, 0x61, 0xc1, 0xc3, 0xfb, 0xed, 0x93, 0xef, 0xe1, 0x78, 0xab, 0x35, 0x7e, 0x41, 0xbe, - 0x84, 0xbc, 0x1f, 0x8c, 0x79, 0x64, 0x66, 0x54, 0x57, 0x72, 0x94, 0x92, 0x6b, 0x3b, 0x18, 0xf3, - 0x4b, 0x37, 0x12, 0x41, 0x78, 0x4f, 0x34, 0x49, 0xb2, 0xe7, 0xcc, 0x0d, 0x23, 0x73, 0xe7, 0x01, - 0xfb, 0x8a, 0xb9, 0xe1, 0x92, 0xad, 0x48, 0xf5, 0x3f, 0x67, 0xa0, 0x94, 0x72, 0x82, 0x8e, 0x60, - 0x77, 0xbe, 0xb8, 0x4e, 0x1a, 0x96, 0x32, 0x89, 0x47, 0xe8, 0x39, 0xec, 0x7b, 0x2c, 0x12, 0x54, - 0x6a, 0x2d, 0x95, 0x29, 0x8d, 0x1f, 0xd8, 0x0d, 0x14, 0x9d, 0x03, 0x0a, 0xc4, 0x94, 0x87, 0x34, - 0x5a, 0x8c, 0x46, 0x3c, 0x8a, 0xe8, 0x3c, 0x0c, 0xae, 0xd5, 0x9d, 0xdc, 0x21, 0x5b, 0x2c, 0xaf, - 0x72, 0x7b, 0x39, 0x23, 0x5f, 0xff, 0x47, 0x06, 0x4a, 0xa9, 0xe0, 0xe4, 0xad, 0x95, 0x9b, 0xa1, - 0x37, 0x61, 0x30, 0x4b, 0x6a, 0x61, 0x09, 0x20, 0x13, 0x0a, 0x6a, 0x20, 0x82, 0xb8, 0x10, 0x92, - 0xe1, 0x96, 0x28, 0xb3, 0x5b, 0xa3, 0x6c, 0xc0, 0xe1, 0xcc, 0xf5, 0xe9, 0x9c, 0xfb, 0xcc, 0x73, - 0xff, 0xc8, 0x69, 0xd2, 0x93, 0xe4, 0x14, 0x7b, 0xab, 0x0d, 0xd5, 0xa1, 0xbc, 0xb6, 0xa7, 0xbc, - 0xda, 0xd3, 0x1a, 0xf6, 0xe2, 0xaf, 0x19, 0x28, 0xa7, 0xbb, 0x2b, 0x54, 0x81, 0xa2, 0x65, 0xd3, - 0x4e, 0xd7, 0xfa, 0xfe, 0x72, 0x60, 0x7c, 0x24, 0x87, 0xfd, 0x61, 0xab, 0x85, 0x71, 0x1b, 0xb7, - 0x8d, 0x0c, 0x42, 0xb0, 0x2f, 0x85, 0x01, 0xb7, 0xe9, 0xc0, 0xea, 0x61, 0x67, 0x28, 0xdf, 0x94, - 0x03, 0xa8, 0xc6, 0x98, 0xed, 0x50, 0xe2, 0x0c, 0x07, 0xd8, 0xc8, 0x22, 0x03, 0xca, 0x31, 0x88, - 0x09, 0x71, 0x88, 0x91, 0x93, 0x42, 0x18, 0x23, 0x0f, 0xdf, 0xa7, 0xe4, 0xf9, 0xca, 0x37, 0xfe, - 0x92, 0x83, 0x5d, 0xd5, 0x8d, 0x84, 0xe8, 0x12, 0x4a, 0xa9, 0x16, 0x16, 0x9d, 0x7c, 0xb0, 0xb5, - 0xad, 0x99, 0xdb, 0xdb, 0xc5, 0x45, 0xf4, 0x55, 0x06, 0xbd, 0x82, 0x72, 0xba, 0x49, 0x45, 0xe9, - 0xe6, 0x63, 0x4b, 0xf7, 0xfa, 0x41, 0x5f, 0xaf, 0xc1, 0xc0, 0x91, 0x70, 0x67, 0xb2, 0xd9, 0x88, - 0xdb, 0x3f, 0x54, 0x4b, 0xf1, 0x37, 0x7a, 0xca, 0xda, 0xf1, 0x56, 0x5b, 0x5c, 0x27, 0x5d, 0xbd, - 0xc5, 0xb8, 0x01, 0x7b, 0xb0, 0xc5, 0xf5, 0xae, 0xaf, 0xf6, 0xf1, 0xfb, 0xcc, 0xb1, 0xb7, 0x31, - 0x1c, 0x6c, 0xa9, 0x68, 0xf4, 0x8b, 0x74, 0x04, 0xef, 0xd5, 0x83, 0xda, 0xf3, 0xff, 0x45, 0x5b, - 0xad, 0xb2, 0xa5, 0xf4, 0xd7, 0x56, 0x79, 0xbf, 0x70, 0xac, 0xad, 0xf2, 0x01, 0x05, 0x79, 0xf9, - 0xab, 0xdf, 0x5d, 0x4c, 0x5c, 0x31, 0x5d, 0x5c, 0x9f, 0x8f, 0x82, 0xd9, 0x85, 0xe7, 0x4e, 0xa6, - 0xc2, 0x77, 0xfd, 0x89, 0xcf, 0xc5, 0x1f, 0x82, 0xf0, 0xf6, 0xc2, 0xf3, 0xc7, 0x17, 0xaa, 0xa1, - 0xbd, 0x58, 0xba, 0xbb, 0xde, 0x55, 0xff, 0x48, 0x7f, 0xfd, 0xdf, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x54, 0xde, 0xd4, 0xfd, 0xc1, 0x0e, 0x00, 0x00, + // 1759 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x57, 0x41, 0x73, 0x22, 0xb9, + 0x15, 0x5e, 0x0c, 0x18, 0x78, 0x80, 0xdd, 0x96, 0x3d, 0x76, 0x0f, 0x1e, 0xef, 0x7a, 0xd9, 0xcd, + 0xac, 0x6b, 0x6a, 0x63, 0x6f, 0x9c, 0xda, 0xad, 0xa9, 0x3d, 0x24, 0xc5, 0x80, 0x58, 0xf7, 0x0c, + 0x74, 0x7b, 0x05, 0xcc, 0xee, 0x24, 0x07, 0x95, 0x0c, 0xb2, 0xe9, 0x72, 0xd3, 0xcd, 0x74, 0x0b, + 0x67, 0x9c, 0x43, 0x2e, 0xa9, 0x1c, 0x73, 0xcf, 0xbf, 0xc8, 0xef, 0xc8, 0x1f, 0x49, 0x7e, 0x41, + 0x8e, 0xa9, 0x4a, 0x49, 0xea, 0x86, 0x06, 0xe3, 0x49, 0x4e, 0xb4, 0xbe, 0xf7, 0xe9, 0x49, 0x7a, + 0x4f, 0xef, 0xd3, 0x03, 0xf6, 0xc3, 0x60, 0x26, 0x78, 0x18, 0x4e, 0x87, 0x67, 0xfa, 0xeb, 0x74, + 0x1a, 0x06, 0x22, 0x40, 0xa5, 0x39, 0x5e, 0x2b, 0x85, 0xd3, 0xa1, 0x46, 0xeb, 0xff, 0xc9, 0x02, + 0xea, 0x71, 0x7f, 0x74, 0xc9, 0xee, 0x27, 0xdc, 0x17, 0x84, 0xbf, 0x9f, 0xf1, 0x48, 0x20, 0x04, + 0xb9, 0x11, 0x8f, 0x84, 0x99, 0x39, 0xce, 0x9c, 0x54, 0x88, 0xfa, 0x46, 0x06, 0x64, 0xd9, 0x44, + 0x98, 0x1b, 0xc7, 0x99, 0x93, 0x2c, 0x91, 0x9f, 0xe8, 0x73, 0xa8, 0x4c, 0xf5, 0x3c, 0x3a, 0x66, + 0xd1, 0xd8, 0xcc, 0x2a, 0x76, 0x39, 0xc6, 0x2e, 0x58, 0x34, 0x46, 0x27, 0x60, 0x5c, 0xbb, 0x3e, + 0xf3, 0xe8, 0xd0, 0x13, 0x77, 0x74, 0xc4, 0x3d, 0xc1, 0xcc, 0xdc, 0x71, 0xe6, 0x24, 0x4f, 0xb6, + 0x14, 0xde, 0xf4, 0xc4, 0x5d, 0x4b, 0xa2, 0xe8, 0x2b, 0xd8, 0x4e, 0x9c, 0x85, 0x7a, 0x17, 0x66, + 0xfe, 0x38, 0x73, 0x52, 0x22, 0x5b, 0xd3, 0xe5, 0xbd, 0x7d, 0x05, 0xdb, 0xc2, 0x9d, 0xf0, 0x60, + 0x26, 0x68, 0xc4, 0x87, 0x81, 0x3f, 0x8a, 0xcc, 0x4d, 0xed, 0x31, 0x86, 0x7b, 0x1a, 0x45, 0x75, + 0xa8, 0x5e, 0x73, 0x4e, 0x3d, 0x77, 0xe2, 0x0a, 0x1a, 0x31, 0x61, 0x16, 0xd4, 0xd6, 0xcb, 0xd7, + 0x9c, 0x77, 0x24, 0xd6, 0x63, 0x42, 0xee, 0x2f, 0x98, 0x89, 0x9b, 0xc0, 0xf5, 0x6f, 0xe8, 0x70, + 0xcc, 0x7c, 0xea, 0x8e, 0xcc, 0xe2, 0x71, 0xe6, 0x24, 0x47, 0xb6, 0x12, 0xbc, 0x39, 0x66, 0xbe, + 0x35, 0x42, 0x47, 0x00, 0xea, 0x0c, 0xca, 0x9d, 0x59, 0x52, 0x2b, 0x96, 0x24, 0xa2, 0x7c, 0xa1, + 0x73, 0x28, 0xab, 0x00, 0xd3, 0xb1, 0xeb, 0x8b, 0xc8, 0x84, 0xe3, 0xec, 0x49, 0xf9, 0xdc, 0x38, + 0xf5, 0x7c, 0x19, 0x6b, 0x22, 0x2d, 0x17, 0xae, 0x2f, 0x48, 0x9a, 0x84, 0x30, 0x14, 0x65, 0x64, + 0xa9, 0xf0, 0xee, 0xcc, 0xb2, 0x9a, 0xf0, 0xe2, 0x74, 0x9e, 0xa5, 0xd3, 0x87, 0x69, 0x39, 0x6d, + 0xf1, 0x48, 0xf4, 0xbd, 0x3b, 0xec, 0x8b, 0xf0, 0x9e, 0x14, 0x46, 0x7a, 0x54, 0xfb, 0x1e, 0x2a, + 0x69, 0x83, 0x4c, 0xd4, 0x2d, 0xbf, 0x57, 0xb9, 0xcb, 0x11, 0xf9, 0x89, 0xf6, 0x20, 0x7f, 0xc7, + 0xbc, 0x19, 0x57, 0xc9, 0xab, 0x10, 0x3d, 0xf8, 0x7e, 0xe3, 0x65, 0xa6, 0xfe, 0x12, 0x76, 0xfb, + 0x21, 0x1b, 0xde, 0xae, 0xe4, 0x7f, 0x35, 0xb3, 0x99, 0x07, 0x99, 0xad, 0xff, 0x09, 0xaa, 0xf1, + 0xa4, 0x9e, 0x60, 0x62, 0x16, 0xa1, 0x5f, 0x42, 0x3e, 0x12, 0x4c, 0x70, 0x45, 0xde, 0x3a, 0x3f, + 0x48, 0x1d, 0x25, 0x45, 0xe4, 0x44, 0xb3, 0x50, 0x0d, 0x8a, 0xd3, 0x90, 0xbb, 0x13, 0x76, 0x93, + 0x6c, 0x6b, 0x3e, 0x46, 0x75, 0xc8, 0xab, 0xc9, 0xea, 0x46, 0x95, 0xcf, 0x2b, 0xe9, 0x30, 0x12, + 0x6d, 0xaa, 0xff, 0x06, 0xb6, 0xd5, 0xb8, 0xcd, 0xf9, 0xc7, 0x6e, 0xed, 0x01, 0x14, 0xd8, 0x44, + 0xa7, 0x5f, 0xdf, 0xdc, 0x4d, 0x36, 0x91, 0x99, 0xaf, 0x8f, 0xc0, 0x58, 0xcc, 0x8f, 0xa6, 0x81, + 0x1f, 0x71, 0x79, 0x1b, 0xa4, 0x73, 0x79, 0x19, 0xe4, 0xcd, 0x99, 0xc8, 0x59, 0x19, 0x35, 0x6b, + 0x2b, 0xc6, 0xdb, 0x9c, 0x77, 0x23, 0x26, 0xd0, 0x73, 0x7d, 0x09, 0xa9, 0x17, 0x0c, 0x6f, 0xe5, + 0xb5, 0x66, 0xf7, 0xb1, 0xfb, 0xaa, 0x84, 0x3b, 0xc1, 0xf0, 0xb6, 0x25, 0xc1, 0xfa, 0xef, 0x75, + 0x79, 0xf5, 0x03, 0xbd, 0xf7, 0xff, 0x3b, 0xbc, 0x8b, 0x10, 0x6c, 0x3c, 0x1e, 0x02, 0x0a, 0xbb, + 0x4b, 0xce, 0xe3, 0x53, 0xa4, 0x23, 0x9b, 0x59, 0x89, 0xec, 0xd7, 0x50, 0xb8, 0x66, 0xae, 0x37, + 0x0b, 0x13, 0xc7, 0x28, 0x95, 0xa6, 0xb6, 0xb6, 0x90, 0x84, 0x52, 0xff, 0x47, 0x01, 0x0a, 0x31, + 0x88, 0xce, 0x21, 0x37, 0x0c, 0x46, 0x49, 0x76, 0x3f, 0x7d, 0x38, 0x2d, 0xf9, 0x6d, 0x06, 0x23, + 0x4e, 0x14, 0x17, 0xfd, 0x16, 0xb6, 0x64, 0x51, 0xf9, 0xdc, 0xa3, 0xb3, 0xe9, 0x88, 0xcd, 0x13, + 0x6a, 0xa6, 0x66, 0x37, 0x35, 0x61, 0xa0, 0xec, 0xa4, 0x3a, 0x4c, 0x0f, 0xd1, 0x21, 0x94, 0xc6, + 0xc2, 0x1b, 0xea, 0x4c, 0xe4, 0xd4, 0x85, 0x2e, 0x4a, 0x40, 0xe5, 0xa0, 0x0e, 0xd5, 0xc0, 0x77, + 0x03, 0x9f, 0x46, 0x63, 0x46, 0xcf, 0xbf, 0xfd, 0x4e, 0xe9, 0x45, 0x85, 0x94, 0x15, 0xd8, 0x1b, + 0xb3, 0xf3, 0x6f, 0xbf, 0x43, 0x9f, 0x41, 0x59, 0x55, 0x2d, 0xff, 0x30, 0x75, 0xc3, 0x7b, 0x25, + 0x14, 0x55, 0xa2, 0x0a, 0x19, 0x2b, 0x44, 0x96, 0xc6, 0xb5, 0xc7, 0x6e, 0x22, 0x25, 0x0e, 0x55, + 0xa2, 0x07, 0xe8, 0x1b, 0xd8, 0x8b, 0x63, 0x40, 0xa3, 0x60, 0x16, 0x0e, 0x39, 0x75, 0xfd, 0x11, + 0xff, 0xa0, 0xa4, 0xa1, 0x4a, 0x50, 0x6c, 0xeb, 0x29, 0x93, 0x25, 0x2d, 0xf5, 0xbf, 0xe5, 0xa1, + 0x9c, 0x0a, 0x00, 0xaa, 0x40, 0x91, 0xe0, 0x1e, 0x26, 0x6f, 0x71, 0xcb, 0xf8, 0x04, 0x9d, 0xc0, + 0x97, 0x96, 0xdd, 0x74, 0x08, 0xc1, 0xcd, 0x3e, 0x75, 0x08, 0x1d, 0xd8, 0x6f, 0x6c, 0xe7, 0x27, + 0x9b, 0x5e, 0x36, 0xde, 0x75, 0xb1, 0xdd, 0xa7, 0x2d, 0xdc, 0x6f, 0x58, 0x9d, 0x9e, 0x91, 0x41, + 0xcf, 0xc0, 0x5c, 0x30, 0x13, 0x73, 0xa3, 0xeb, 0x0c, 0xec, 0xbe, 0xb1, 0x81, 0x3e, 0x83, 0xc3, + 0xb6, 0x65, 0x37, 0x3a, 0x74, 0xc1, 0x69, 0x76, 0xfa, 0x6f, 0x29, 0xfe, 0xf9, 0xd2, 0x22, 0xef, + 0x8c, 0xec, 0x3a, 0xc2, 0x45, 0xbf, 0xd3, 0x4c, 0x3c, 0xe4, 0xd0, 0x53, 0x78, 0xa2, 0x09, 0x7a, + 0x0a, 0xed, 0x3b, 0x0e, 0xed, 0x39, 0x8e, 0x6d, 0xe4, 0xd1, 0x0e, 0x54, 0x2d, 0xfb, 0x6d, 0xa3, + 0x63, 0xb5, 0x28, 0xc1, 0x8d, 0x4e, 0xd7, 0xd8, 0x44, 0xbb, 0xb0, 0xbd, 0xca, 0x2b, 0x48, 0x17, + 0x09, 0xcf, 0xb1, 0x2d, 0xc7, 0xa6, 0x6f, 0x31, 0xe9, 0x59, 0x8e, 0x6d, 0x14, 0xd1, 0x3e, 0xa0, + 0x65, 0xd3, 0x45, 0xb7, 0xd1, 0x34, 0x4a, 0xe8, 0x09, 0xec, 0x2c, 0xe3, 0x6f, 0xf0, 0x3b, 0x03, + 0x90, 0x09, 0x7b, 0x7a, 0x63, 0xf4, 0x15, 0xee, 0x38, 0x3f, 0xd1, 0xae, 0x65, 0x5b, 0xdd, 0x41, + 0xd7, 0x28, 0xa3, 0x3d, 0x30, 0xda, 0x18, 0x53, 0xcb, 0xee, 0x0d, 0xda, 0x6d, 0xab, 0x69, 0x61, + 0xbb, 0x6f, 0x54, 0xf4, 0xca, 0xeb, 0x0e, 0x5e, 0x95, 0x13, 0x9a, 0x17, 0x0d, 0xdb, 0xc6, 0x1d, + 0xda, 0xb2, 0x7a, 0x8d, 0x57, 0x1d, 0xdc, 0x32, 0xb6, 0xd0, 0x11, 0x3c, 0xed, 0xe3, 0xee, 0xa5, + 0x43, 0x1a, 0xe4, 0x1d, 0x4d, 0xec, 0xed, 0x86, 0xd5, 0x19, 0x10, 0x6c, 0x6c, 0xa3, 0xcf, 0xe1, + 0x88, 0xe0, 0x1f, 0x07, 0x16, 0xc1, 0x2d, 0x6a, 0x3b, 0x2d, 0x4c, 0xdb, 0xb8, 0xd1, 0x1f, 0x10, + 0x4c, 0xbb, 0x56, 0xaf, 0x67, 0xd9, 0x3f, 0x18, 0x06, 0xfa, 0x12, 0x8e, 0xe7, 0x94, 0xb9, 0x83, + 0x15, 0xd6, 0x8e, 0x3c, 0x5f, 0x92, 0x52, 0x1b, 0xff, 0xdc, 0xa7, 0x97, 0x18, 0x13, 0x03, 0xa1, + 0x1a, 0xec, 0x2f, 0x96, 0xd7, 0x0b, 0xc4, 0x6b, 0xef, 0x4a, 0xdb, 0x25, 0x26, 0xdd, 0x86, 0x2d, + 0x13, 0xbc, 0x64, 0xdb, 0x93, 0xdb, 0x5e, 0xd8, 0x56, 0xb7, 0xfd, 0x04, 0xed, 0xc1, 0x76, 0xb2, + 0x5a, 0x02, 0xfe, 0xb3, 0x80, 0x0e, 0x00, 0x0d, 0x6c, 0x82, 0x1b, 0x2d, 0x79, 0xf8, 0xb9, 0xe1, + 0x5f, 0x85, 0xd7, 0xb9, 0xe2, 0x86, 0x91, 0xad, 0xff, 0x3d, 0x0b, 0xd5, 0xa5, 0x5a, 0x43, 0xcf, + 0xa0, 0x14, 0xb9, 0x37, 0x3e, 0x13, 0x52, 0x0d, 0xb4, 0x50, 0x2c, 0x00, 0xf5, 0xde, 0x8d, 0x99, + 0xeb, 0x6b, 0x85, 0xd2, 0x0a, 0x5d, 0x52, 0x88, 0xd2, 0xa7, 0x03, 0x28, 0x24, 0xef, 0x65, 0x56, + 0xd5, 0xe5, 0xe6, 0x50, 0xbf, 0x93, 0xcf, 0xa0, 0x24, 0x25, 0x30, 0x12, 0x6c, 0x32, 0x55, 0x25, + 0x5b, 0x25, 0x0b, 0x00, 0x7d, 0x01, 0xd5, 0x09, 0x8f, 0x22, 0x76, 0xc3, 0xa9, 0x2e, 0x3b, 0x50, + 0x8c, 0x4a, 0x0c, 0xb6, 0x55, 0xf5, 0x7d, 0x01, 0x89, 0x0c, 0xc4, 0xa4, 0xbc, 0x26, 0xc5, 0xa0, + 0x26, 0xad, 0x2a, 0xb0, 0x60, 0x71, 0x75, 0xa7, 0x15, 0x58, 0x30, 0xf4, 0x02, 0x76, 0xb4, 0x84, + 0xb8, 0xbe, 0x3b, 0x99, 0x4d, 0xb4, 0x94, 0x14, 0xd4, 0x96, 0xb7, 0x95, 0x94, 0x68, 0x5c, 0x29, + 0xca, 0x53, 0x28, 0x5e, 0xb1, 0x88, 0x4b, 0xf1, 0x8f, 0x4b, 0xbd, 0x20, 0xc7, 0x6d, 0xce, 0xa5, + 0x49, 0x3e, 0x09, 0xa1, 0x14, 0xb1, 0x92, 0x36, 0x5d, 0x73, 0x4e, 0x64, 0x1c, 0xe7, 0x2b, 0xb0, + 0x0f, 0x8b, 0x15, 0xca, 0xa9, 0x15, 0x34, 0xae, 0x56, 0x78, 0x01, 0x3b, 0xfc, 0x83, 0x08, 0x19, + 0x0d, 0xa6, 0xec, 0xfd, 0x8c, 0xd3, 0x11, 0x13, 0xcc, 0xac, 0xa8, 0xe0, 0x6e, 0x2b, 0x83, 0xa3, + 0xf0, 0x16, 0x13, 0xac, 0xfe, 0x0c, 0x6a, 0x84, 0x47, 0x5c, 0x74, 0xdd, 0x28, 0x72, 0x03, 0xbf, + 0x19, 0xf8, 0x22, 0x0c, 0xbc, 0xf8, 0x0d, 0xa9, 0x1f, 0xc1, 0xe1, 0x5a, 0xab, 0x7e, 0x04, 0xe4, + 0xe4, 0x1f, 0x67, 0x3c, 0xbc, 0x5f, 0x3f, 0xf9, 0x1e, 0x0e, 0xd7, 0x5a, 0xe3, 0x17, 0xe4, 0x6b, + 0xc8, 0xfb, 0xc1, 0x88, 0x47, 0x66, 0x46, 0x75, 0x25, 0xfb, 0x29, 0xb9, 0xb6, 0x83, 0x11, 0xbf, + 0x70, 0x23, 0x11, 0x84, 0xf7, 0x44, 0x93, 0x24, 0x7b, 0xca, 0xdc, 0x30, 0x32, 0x37, 0x1e, 0xb0, + 0x2f, 0x99, 0x1b, 0xce, 0xd9, 0x8a, 0x54, 0xff, 0x73, 0x06, 0xca, 0x29, 0x27, 0x68, 0x1f, 0x36, + 0xa7, 0xb3, 0xab, 0xa4, 0x61, 0xa9, 0x90, 0x78, 0x84, 0x9e, 0xc3, 0x96, 0xc7, 0x22, 0x41, 0xa5, + 0xd6, 0x52, 0x99, 0xd2, 0xf8, 0x81, 0x5d, 0x41, 0xd1, 0x29, 0xa0, 0x40, 0x8c, 0x79, 0x48, 0xa3, + 0xd9, 0x70, 0xc8, 0xa3, 0x88, 0x4e, 0xc3, 0xe0, 0x4a, 0xdd, 0xc9, 0x0d, 0xb2, 0xc6, 0xf2, 0x3a, + 0x57, 0xcc, 0x19, 0xf9, 0xfa, 0xbf, 0x33, 0x50, 0x4e, 0x6d, 0x4e, 0xde, 0x5a, 0x79, 0x18, 0x7a, + 0x1d, 0x06, 0x93, 0xa4, 0x16, 0xe6, 0x00, 0x32, 0xa1, 0xa0, 0x06, 0x22, 0x88, 0x0b, 0x21, 0x19, + 0x2e, 0xdf, 0xf6, 0xac, 0xda, 0x60, 0xea, 0xb6, 0x9f, 0xc3, 0xde, 0xc4, 0xf5, 0xe9, 0x94, 0xfb, + 0xcc, 0x73, 0xff, 0xc8, 0x69, 0xd2, 0x89, 0xe4, 0x14, 0x71, 0xad, 0x0d, 0xd5, 0xa1, 0xb2, 0x74, + 0x92, 0xbc, 0x3a, 0xc9, 0x12, 0x86, 0x5e, 0xc2, 0x81, 0x8a, 0x02, 0x13, 0x82, 0x4f, 0xa6, 0x22, + 0x39, 0xe0, 0xf5, 0xcc, 0x53, 0x35, 0x50, 0x24, 0x8f, 0x99, 0x5f, 0xfc, 0x35, 0x03, 0x95, 0x74, + 0x37, 0x86, 0xaa, 0x50, 0xb2, 0x6c, 0xda, 0xee, 0x58, 0x3f, 0x5c, 0xf4, 0x8d, 0x4f, 0xe4, 0xb0, + 0x37, 0x68, 0x36, 0x31, 0x6e, 0xe1, 0x96, 0x91, 0x41, 0x08, 0xb6, 0xa4, 0x90, 0xe0, 0x16, 0xed, + 0x5b, 0x5d, 0xec, 0x0c, 0xe4, 0x1b, 0xb4, 0x0b, 0xdb, 0x31, 0x66, 0x3b, 0x94, 0x38, 0x83, 0x3e, + 0x36, 0xb2, 0xc8, 0x80, 0x4a, 0x0c, 0x62, 0x42, 0x1c, 0x62, 0xe4, 0xa4, 0x70, 0xc6, 0xc8, 0xc3, + 0xf7, 0x2c, 0x79, 0xee, 0xf2, 0xe7, 0x7f, 0xc9, 0xc1, 0xa6, 0xea, 0x5e, 0x42, 0x74, 0x01, 0xe5, + 0x54, 0xcb, 0x8b, 0x8e, 0x3e, 0xda, 0x0a, 0xd7, 0xcc, 0xf5, 0xed, 0xe5, 0x2c, 0xfa, 0x26, 0x83, + 0x5e, 0x43, 0x25, 0xdd, 0xd4, 0xa2, 0x74, 0xb3, 0xb2, 0xa6, 0xdb, 0xfd, 0xa8, 0xaf, 0x37, 0x60, + 0xe0, 0x48, 0xb8, 0x13, 0xd9, 0x9c, 0xc4, 0xed, 0x22, 0xaa, 0xa5, 0xf8, 0x2b, 0x3d, 0x68, 0xed, + 0x70, 0xad, 0x2d, 0xae, 0xab, 0x8e, 0x3e, 0x62, 0xdc, 0xb0, 0x3d, 0x38, 0xe2, 0x72, 0x97, 0x58, + 0xfb, 0xf4, 0x31, 0x73, 0xec, 0x6d, 0x04, 0xbb, 0x6b, 0x14, 0x00, 0xfd, 0x22, 0xbd, 0x83, 0x47, + 0xf5, 0xa3, 0xf6, 0xfc, 0x7f, 0xd1, 0x16, 0xab, 0xac, 0x91, 0x8a, 0xa5, 0x55, 0x1e, 0x17, 0x9a, + 0xa5, 0x55, 0x3e, 0xa2, 0x38, 0xaf, 0x7e, 0xf5, 0xbb, 0xb3, 0x1b, 0x57, 0x8c, 0x67, 0x57, 0xa7, + 0xc3, 0x60, 0x72, 0xe6, 0xb9, 0x37, 0x63, 0xe1, 0xbb, 0xfe, 0x8d, 0xcf, 0xc5, 0x1f, 0x82, 0xf0, + 0xf6, 0xcc, 0xf3, 0x47, 0x67, 0xaa, 0x01, 0x3e, 0x9b, 0xbb, 0xbb, 0xda, 0x54, 0xff, 0x60, 0x7f, + 0xfd, 0xdf, 0x00, 0x00, 0x00, 0xff, 0xff, 0xd5, 0x11, 0xe6, 0x51, 0xf1, 0x0e, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. diff --git a/lnrpc/routerrpc/router.proto b/lnrpc/routerrpc/router.proto index af1c45d1..e7963529 100644 --- a/lnrpc/routerrpc/router.proto +++ b/lnrpc/routerrpc/router.proto @@ -364,14 +364,17 @@ message PairHistory { /// The destination node pubkey of the pair. bytes node_to = 2 [json_name="node_to"]; - /// Time stamp of last failure. - int64 last_fail_time = 3 [json_name = "last_fail_time"]; + /// Time stamp of last result. + int64 timestamp = 3 [json_name = "timestamp"]; - /// Minimum penalization amount. + /// Minimum penalization amount (only applies to failed attempts). int64 min_penalize_amt_sat = 4 [json_name = "min_penalize_amt_sat"]; /// Estimation of success probability for this pair. float success_prob = 5 [json_name = "success_prob"]; + + /// Whether the last payment attempt through this pair was successful. + bool last_attempt_successful = 6 [json_name = "last_attempt_successful"]; } service Router { diff --git a/lnrpc/routerrpc/router_server.go b/lnrpc/routerrpc/router_server.go index 1f9bc248..f2fe0c68 100644 --- a/lnrpc/routerrpc/router_server.go +++ b/lnrpc/routerrpc/router_server.go @@ -473,13 +473,14 @@ func (s *Server) QueryMissionControl(ctx context.Context, pair := p rpcPair := PairHistory{ - NodeFrom: pair.Pair.From[:], - NodeTo: pair.Pair.To[:], - LastFailTime: pair.LastFail.Unix(), + NodeFrom: pair.Pair.From[:], + NodeTo: pair.Pair.To[:], + Timestamp: pair.Timestamp.Unix(), MinPenalizeAmtSat: int64( pair.MinPenalizeAmt.ToSatoshis(), ), - SuccessProb: float32(pair.SuccessProb), + SuccessProb: float32(pair.SuccessProb), + LastAttemptSuccessful: pair.LastAttemptSuccessful, } rpcPairs = append(rpcPairs, &rpcPair) diff --git a/routing/missioncontrol.go b/routing/missioncontrol.go index 65e342e1..cebb7ea9 100644 --- a/routing/missioncontrol.go +++ b/routing/missioncontrol.go @@ -43,6 +43,10 @@ const ( // DefaultMaxMcHistory is the default maximum history size. DefaultMaxMcHistory = 1000 + + // prevSuccessProbability is the assumed probability for node pairs that + // successfully relayed the previous attempt. + prevSuccessProbability = 0.95 ) // MissionControl contains state which summarizes the past attempts of HTLC @@ -55,8 +59,8 @@ const ( // since the last failure is used to estimate a success probability that is fed // into the path finding process for subsequent payment attempts. type MissionControl struct { - // lastPairFailure tracks the last payment failure per node pair. - lastPairFailure map[DirectedNodePair]pairFailure + // lastPairResult tracks the last payment result per node pair. + lastPairResult map[DirectedNodePair]timedPairResult // lastNodeFailure tracks the last node level failure per node. lastNodeFailure map[route.Vertex]time.Time @@ -97,14 +101,12 @@ type MissionControlConfig struct { MaxMcHistory int } -// pairFailure describes a payment failure for a node pair. -type pairFailure struct { - // timestamp is the time when this failure result was obtained. +// timedPairResult describes a timestamped pair result. +type timedPairResult struct { + // timestamp is the time when this result was obtained. timestamp time.Time - // minPenalizeAmt is the minimum amount for which to take this failure - // into account. - minPenalizeAmt lnwire.MilliSatoshi + pairResult } // MissionControlSnapshot contains a snapshot of the current state of mission @@ -138,8 +140,8 @@ type MissionControlPairSnapshot struct { // Pair is the node pair of which the state is described. Pair DirectedNodePair - // LastFail is the time of last failure. - LastFail time.Time + // Timestamp is the time of last result. + Timestamp time.Time // MinPenalizeAmt is the minimum amount for which the channel will be // penalized. @@ -147,6 +149,10 @@ type MissionControlPairSnapshot struct { // SuccessProb is the success probability estimation for this channel. SuccessProb float64 + + // LastAttemptSuccessful indicates whether the last payment attempt + // through this pair was successful. + LastAttemptSuccessful bool } // paymentResult is the information that becomes available when a payment @@ -174,7 +180,7 @@ func NewMissionControl(db *bbolt.DB, cfg *MissionControlConfig) ( } mc := &MissionControl{ - lastPairFailure: make(map[DirectedNodePair]pairFailure), + lastPairResult: make(map[DirectedNodePair]timedPairResult), lastNodeFailure: make(map[route.Vertex]time.Time), lastSecondChance: make(map[DirectedNodePair]time.Time), now: time.Now, @@ -220,7 +226,7 @@ func (m *MissionControl) ResetHistory() error { return err } - m.lastPairFailure = make(map[DirectedNodePair]pairFailure) + m.lastPairResult = make(map[DirectedNodePair]timedPairResult) m.lastNodeFailure = make(map[route.Vertex]time.Time) m.lastSecondChance = make(map[DirectedNodePair]time.Time) @@ -271,12 +277,16 @@ func (m *MissionControl) getPairProbability(fromNode, // Retrieve the last pair outcome. pair := NewDirectedNodePair(fromNode, toNode) - lastPairResult, ok := m.lastPairFailure[pair] + lastPairResult, ok := m.lastPairResult[pair] // Only look at the last pair outcome if it happened after the last node // level failure. Otherwise the node level failure is the most recent // and used as the basis for calculation of the probability. if ok && lastPairResult.timestamp.After(lastFail) { + if lastPairResult.success { + return prevSuccessProbability + } + // Take into account a minimum penalize amount. For balance // errors, a failure may be reported with such a minimum to // prevent too aggresive penalization. We only take into account @@ -330,7 +340,7 @@ func (m *MissionControl) GetHistorySnapshot() *MissionControlSnapshot { log.Debugf("Requesting history snapshot from mission control: "+ "node_failure_count=%v, pair_result_count=%v", - len(m.lastNodeFailure), len(m.lastPairFailure)) + len(m.lastNodeFailure), len(m.lastPairResult)) nodes := make([]MissionControlNodeSnapshot, 0, len(m.lastNodeFailure)) for v, h := range m.lastNodeFailure { @@ -343,18 +353,19 @@ func (m *MissionControl) GetHistorySnapshot() *MissionControlSnapshot { }) } - pairs := make([]MissionControlPairSnapshot, 0, len(m.lastPairFailure)) + pairs := make([]MissionControlPairSnapshot, 0, len(m.lastPairResult)) - for v, h := range m.lastPairFailure { + for v, h := range m.lastPairResult { // Show probability assuming amount meets min // penalization amount. prob := m.getPairProbability(v.From, v.To, h.minPenalizeAmt) pair := MissionControlPairSnapshot{ - Pair: v, - MinPenalizeAmt: h.minPenalizeAmt, - LastFail: h.timestamp, - SuccessProb: prob, + Pair: v, + MinPenalizeAmt: h.minPenalizeAmt, + Timestamp: h.timestamp, + SuccessProb: prob, + LastAttemptSuccessful: h.success, } pairs = append(pairs, pair) @@ -379,7 +390,6 @@ func (m *MissionControl) ReportPaymentFail(paymentID uint64, rt *route.Route, timestamp := m.now() - // TODO(joostjager): Use actual payment initiation time for timeFwd. result := &paymentResult{ success: false, timeFwd: timestamp, @@ -390,6 +400,33 @@ func (m *MissionControl) ReportPaymentFail(paymentID uint64, rt *route.Route, route: rt, } + return m.processPaymentResult(result) +} + +// ReportPaymentSuccess reports a successful payment to mission control as input +// for future probability estimates. +func (m *MissionControl) ReportPaymentSuccess(paymentID uint64, + rt *route.Route) error { + + timestamp := m.now() + + result := &paymentResult{ + timeFwd: timestamp, + timeReply: timestamp, + id: paymentID, + success: true, + route: rt, + } + + _, err := m.processPaymentResult(result) + return err +} + +// processPaymentResult stores a payment result in the mission control store and +// updates mission control's in-memory state. +func (m *MissionControl) processPaymentResult(result *paymentResult) ( + *channeldb.FailureReason, error) { + // Store complete result in database. if err := m.store.AddResult(result); err != nil { return nil, err @@ -409,7 +446,8 @@ func (m *MissionControl) applyPaymentResult( // Interpret result. i := interpretResult( - result.route, result.failureSourceIdx, result.failure, + result.route, result.success, result.failureSourceIdx, + result.failure, ) // Update mission control state using the interpretation. @@ -432,13 +470,19 @@ func (m *MissionControl) applyPaymentResult( m.lastNodeFailure[*i.nodeFailure] = result.timeReply } - for pair, minPenalizeAmt := range i.pairResults { - log.Debugf("Reporting pair failure to Mission Control: "+ - "pair=%v, minPenalizeAmt=%v", pair, minPenalizeAmt) + for pair, pairResult := range i.pairResults { + if pairResult.success { + log.Debugf("Reporting pair success to Mission "+ + "Control: pair=%v", pair) + } else { + log.Debugf("Reporting pair failure to Mission "+ + "Control: pair=%v, minPenalizeAmt=%v", + pair, pairResult.minPenalizeAmt) + } - m.lastPairFailure[pair] = pairFailure{ - minPenalizeAmt: minPenalizeAmt, - timestamp: result.timeReply, + m.lastPairResult[pair] = timedPairResult{ + timestamp: result.timeReply, + pairResult: pairResult, } } diff --git a/routing/missioncontrol_test.go b/routing/missioncontrol_test.go index 14091923..df96e314 100644 --- a/routing/missioncontrol_test.go +++ b/routing/missioncontrol_test.go @@ -114,6 +114,16 @@ func (ctx *mcTestContext) reportFailure(amt lnwire.MilliSatoshi, ) } +// reportSuccess reports a success by using a test route. +func (ctx *mcTestContext) reportSuccess() { + err := ctx.mc.ReportPaymentSuccess(ctx.pid, mcTestRoute) + if err != nil { + ctx.t.Fatal(err) + } + + ctx.pid++ +} + // TestMissionControl tests mission control probability estimation. func TestMissionControl(t *testing.T) { ctx := createMcTestContext(t) @@ -164,9 +174,12 @@ func TestMissionControl(t *testing.T) { len(history.Nodes)) } - if len(history.Pairs) != 1 { - t.Fatal("unexpected number of channels") + if len(history.Pairs) != 2 { + t.Fatalf("expected 2 pairs, but got %v", len(history.Pairs)) } + + // Test reporting a success. + ctx.reportSuccess() } // TestMissionControlChannelUpdate tests that the first channel update is not diff --git a/routing/mock_test.go b/routing/mock_test.go index 96da1448..d2f7448c 100644 --- a/routing/mock_test.go +++ b/routing/mock_test.go @@ -105,6 +105,12 @@ func (m *mockMissionControl) ReportPaymentFail(paymentID uint64, rt *route.Route return nil, nil } +func (m *mockMissionControl) ReportPaymentSuccess(paymentID uint64, + rt *route.Route) error { + + return nil +} + func (m *mockMissionControl) GetProbability(fromNode, toNode route.Vertex, amt lnwire.MilliSatoshi) float64 { diff --git a/routing/pathfind.go b/routing/pathfind.go index 93efba66..4578f350 100644 --- a/routing/pathfind.go +++ b/routing/pathfind.go @@ -55,7 +55,7 @@ var ( // DefaultAprioriHopProbability is the default a priori probability for // a hop. - DefaultAprioriHopProbability = float64(0.95) + DefaultAprioriHopProbability = float64(0.6) ) // edgePolicyWithSource is a helper struct to keep track of the source node diff --git a/routing/payment_lifecycle.go b/routing/payment_lifecycle.go index 18edfc0a..695a0d49 100644 --- a/routing/payment_lifecycle.go +++ b/routing/payment_lifecycle.go @@ -161,6 +161,15 @@ func (p *paymentLifecycle) resumePayment() ([32]byte, *route.Route, error) { log.Debugf("Payment %x succeeded with pid=%v", p.payment.PaymentHash, p.attempt.PaymentID) + // Report success to mission control. + err = p.router.cfg.MissionControl.ReportPaymentSuccess( + p.attempt.PaymentID, &p.attempt.Route, + ) + if err != nil { + log.Errorf("Error reporting payment success to mc: %v", + err) + } + // In case of success we atomically store the db payment and // move the payment to the success state. err = p.router.cfg.Control.Success(p.payment.PaymentHash, result.Preimage) diff --git a/routing/result_interpretation.go b/routing/result_interpretation.go index 00703c28..74c74014 100644 --- a/routing/result_interpretation.go +++ b/routing/result_interpretation.go @@ -1,6 +1,8 @@ package routing import ( + "fmt" + "github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/routing/route" @@ -12,17 +14,36 @@ var ( reasonIncorrectDetails = channeldb.FailureReasonIncorrectPaymentDetails ) +// pairResult contains the result of the interpretation of a payment attempt for +// a specific node pair. +type pairResult struct { + // minPenalizeAmt is the minimum amount for which a penalty should be + // applied based on this result. Only applies to fail results. + minPenalizeAmt lnwire.MilliSatoshi + + // success indicates whether the payment attempt was successful through + // this pair. + success bool +} + +// String returns the human-readable representation of a pair result. +func (p pairResult) String() string { + if p.success { + return "success" + } + + return fmt.Sprintf("failed (minPenalizeAmt=%v)", p.minPenalizeAmt) +} + // interpretedResult contains the result of the interpretation of a payment -// outcome. +// attempt. type interpretedResult struct { // nodeFailure points to a node pubkey if all channels of that node are // responsible for the result. nodeFailure *route.Vertex - // pairResults contains a map of node pairs that could be responsible - // for the failure. The map values are the minimum amounts for which a - // future penalty should be applied. - pairResults map[DirectedNodePair]lnwire.MilliSatoshi + // pairResults contains a map of node pairs for which we have a result. + pairResults map[DirectedNodePair]pairResult // finalFailureReason is set to a non-nil value if it makes no more // sense to start another payment attempt. It will contain the reason @@ -37,18 +58,28 @@ type interpretedResult struct { // interpretResult interprets a payment outcome and returns an object that // contains information required to update mission control. -func interpretResult(rt *route.Route, failureSrcIdx *int, +func interpretResult(rt *route.Route, success bool, failureSrcIdx *int, failure lnwire.FailureMessage) *interpretedResult { i := &interpretedResult{ - pairResults: make(map[DirectedNodePair]lnwire.MilliSatoshi), + pairResults: make(map[DirectedNodePair]pairResult), } - i.processFail(rt, failureSrcIdx, failure) - + if success { + i.processSuccess(rt) + } else { + i.processFail(rt, failureSrcIdx, failure) + } return i } +// processSuccess processes a successful payment attempt. +func (i *interpretedResult) processSuccess(route *route.Route) { + // For successes, all nodes must have acted in the right way. Therefore + // we mark all of them with a success result. + i.successPairRange(route, 0, len(route.Hops)-1) +} + // processFail processes a failed payment attempt. func (i *interpretedResult) processFail( rt *route.Route, errSourceIdx *int, @@ -141,10 +172,20 @@ func (i *interpretedResult) processPaymentOutcomeFinal( // from its predecessor. i.failPair(route, n-1) + // The other hops relayed corectly, so assign those pairs a + // success result. + if n > 2 { + i.successPairRange(route, 0, n-2) + } + // We are using wrong payment hash or amount, fail the payment. case *lnwire.FailIncorrectPaymentAmount, *lnwire.FailIncorrectDetails: + // Assign all pairs a success result, as the payment reached the + // destination correctly. + i.successPairRange(route, 0, n-1) + i.finalFailureReason = &reasonIncorrectDetails // The HTLC that was extended to the final hop expires too soon. Fail @@ -162,6 +203,12 @@ func (i *interpretedResult) processPaymentOutcomeFinal( // final hop. They indicate that something is wrong at the // recipient, so we do apply a penalty. i.failNode(route, n) + + // Other channels in the route forwarded correctly. + if n > 2 { + i.successPairRange(route, 0, n-2) + } + i.finalFailureReason = &reasonError } } @@ -182,6 +229,10 @@ func (i *interpretedResult) processPaymentOutcomeIntermediate( i.failPairBalance( route, errorSourceIdx, ) + + // All nodes up to the failing pair must have forwarded + // successfully. + i.successPairRange(route, 0, errorSourceIdx-1) } reportIncoming := func() { @@ -197,6 +248,12 @@ func (i *interpretedResult) processPaymentOutcomeIntermediate( i.failPair( route, errorSourceIdx-1, ) + + // All nodes up to the failing pair must have forwarded + // successfully. + if errorSourceIdx > 2 { + i.successPairRange(route, 0, errorSourceIdx-2) + } } reportAll := func() { @@ -330,8 +387,8 @@ func (i *interpretedResult) failPair( pair, _ := getPair(rt, idx) // Report pair in both directions without a minimum penalization amount. - i.pairResults[pair] = 0 - i.pairResults[pair.Reverse()] = 0 + i.pairResults[pair] = pairResult{} + i.pairResults[pair.Reverse()] = pairResult{} } // failPairBalance marks a pair as failed with a minimum penalization amount. @@ -340,7 +397,23 @@ func (i *interpretedResult) failPairBalance( pair, amt := getPair(rt, channelIdx) - i.pairResults[pair] = amt + i.pairResults[pair] = pairResult{ + minPenalizeAmt: amt, + } +} + +// successPairRange marks the node pairs from node fromIdx to node toIdx as +// succeeded. +func (i *interpretedResult) successPairRange( + rt *route.Route, fromIdx, toIdx int) { + + for idx := fromIdx; idx <= toIdx; idx++ { + pair, _ := getPair(rt, idx) + + i.pairResults[pair] = pairResult{ + success: true, + } + } } // getPair returns a node pair from the route and the amount passed between that diff --git a/routing/result_interpretation_test.go b/routing/result_interpretation_test.go index 86b65aa4..7d95ad64 100644 --- a/routing/result_interpretation_test.go +++ b/routing/result_interpretation_test.go @@ -50,6 +50,7 @@ func getTestPair(from, to int) DirectedNodePair { type resultTestCase struct { name string route *route.Route + success bool failureSrcIdx int failure lnwire.FailureMessage @@ -66,8 +67,13 @@ var resultTestCases = []resultTestCase{ failure: lnwire.NewTemporaryChannelFailure(nil), expectedResult: &interpretedResult{ - pairResults: map[DirectedNodePair]lnwire.MilliSatoshi{ - getTestPair(1, 2): 99, + pairResults: map[DirectedNodePair]pairResult{ + getTestPair(0, 1): { + success: true, + }, + getTestPair(1, 2): { + minPenalizeAmt: 99, + }, }, }, }, @@ -80,13 +86,67 @@ var resultTestCases = []resultTestCase{ failure: lnwire.NewExpiryTooSoon(lnwire.ChannelUpdate{}), expectedResult: &interpretedResult{ - pairResults: map[DirectedNodePair]lnwire.MilliSatoshi{ - getTestPair(0, 1): 0, - getTestPair(1, 0): 0, - getTestPair(1, 2): 0, - getTestPair(2, 1): 0, - getTestPair(2, 3): 0, - getTestPair(3, 2): 0, + pairResults: map[DirectedNodePair]pairResult{ + getTestPair(0, 1): {}, + getTestPair(1, 0): {}, + getTestPair(1, 2): {}, + getTestPair(2, 1): {}, + getTestPair(2, 3): {}, + getTestPair(3, 2): {}, + }, + }, + }, + + // Tests an incorrect payment details result. This should be a final + // failure, but mark all pairs along the route as successful. + { + name: "fail incorrect details", + route: &routeTwoHop, + failureSrcIdx: 2, + failure: lnwire.NewFailIncorrectDetails(97), + + expectedResult: &interpretedResult{ + pairResults: map[DirectedNodePair]pairResult{ + getTestPair(0, 1): { + success: true, + }, + getTestPair(1, 2): { + success: true, + }, + }, + finalFailureReason: &reasonIncorrectDetails, + }, + }, + + // Tests a successful direct payment. + { + name: "success direct", + route: &routeOneHop, + success: true, + + expectedResult: &interpretedResult{ + pairResults: map[DirectedNodePair]pairResult{ + getTestPair(0, 1): { + success: true, + }, + }, + }, + }, + + // Tests a successful two hop payment. + { + name: "success", + route: &routeTwoHop, + success: true, + + expectedResult: &interpretedResult{ + pairResults: map[DirectedNodePair]pairResult{ + getTestPair(0, 1): { + success: true, + }, + getTestPair(1, 2): { + success: true, + }, }, }, }, @@ -121,13 +181,13 @@ var resultTestCases = []resultTestCase{ // TestResultInterpretation executes a list of test cases that test the result // interpretation logic. func TestResultInterpretation(t *testing.T) { - emptyResults := make(map[DirectedNodePair]lnwire.MilliSatoshi) + emptyResults := make(map[DirectedNodePair]pairResult) for _, testCase := range resultTestCases { t.Run(testCase.name, func(t *testing.T) { i := interpretResult( - testCase.route, &testCase.failureSrcIdx, - testCase.failure, + testCase.route, testCase.success, + &testCase.failureSrcIdx, testCase.failure, ) expected := testCase.expectedResult diff --git a/routing/router.go b/routing/router.go index ae62c17b..7f99c99a 100644 --- a/routing/router.go +++ b/routing/router.go @@ -183,6 +183,10 @@ type MissionController interface { failureSourceIdx *int, failure lnwire.FailureMessage) ( *channeldb.FailureReason, error) + // ReportPaymentSuccess reports a successful payment to mission control as input + // for future probability estimates. + ReportPaymentSuccess(paymentID uint64, rt *route.Route) error + // GetProbability is expected to return the success probability of a // payment from fromNode along edge. GetProbability(fromNode, toNode route.Vertex,