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.
This commit is contained in:
Joost Jager 2019-07-29 14:20:06 +02:00
parent 2594abfba1
commit ff0c5a0d5e
No known key found for this signature in database
GPG Key ID: A61B9D4C393C59C7
12 changed files with 415 additions and 190 deletions

@ -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,
},
)
}

@ -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.

@ -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 {

@ -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)

@ -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,
}
}

@ -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

@ -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 {

@ -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

@ -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)

@ -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

@ -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

@ -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,