Merge pull request #3493 from joostjager/small-successes

routing: track amt ranges in mission control
This commit is contained in:
Joost Jager 2019-11-22 14:46:30 +01:00 committed by GitHub
commit 43d2e7528e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 354 additions and 242 deletions

@ -32,10 +32,10 @@ func queryMissionControl(ctx *cli.Context) error {
} }
type displayPairHistory struct { type displayPairHistory struct {
NodeFrom, NodeTo string NodeFrom, NodeTo string
LastAttemptSuccessful bool SuccessTime, FailTime int64
Timestamp int64 FailAmtSat, FailAmtMsat int64
MinPenalizeAmtSat int64 SuccessAmtSat, SuccessAmtMsat int64
} }
displayResp := struct { displayResp := struct {
@ -46,11 +46,14 @@ func queryMissionControl(ctx *cli.Context) error {
displayResp.Pairs = append( displayResp.Pairs = append(
displayResp.Pairs, displayResp.Pairs,
displayPairHistory{ displayPairHistory{
NodeFrom: hex.EncodeToString(n.NodeFrom), NodeFrom: hex.EncodeToString(n.NodeFrom),
NodeTo: hex.EncodeToString(n.NodeTo), NodeTo: hex.EncodeToString(n.NodeTo),
LastAttemptSuccessful: n.History.LastAttemptSuccessful, FailTime: n.History.FailTime,
Timestamp: n.History.Timestamp, SuccessTime: n.History.SuccessTime,
MinPenalizeAmtSat: n.History.MinPenalizeAmtSat, FailAmtSat: n.History.FailAmtSat,
FailAmtMsat: n.History.FailAmtMsat,
SuccessAmtSat: n.History.SuccessAmtSat,
SuccessAmtMsat: n.History.SuccessAmtMsat,
}, },
) )
} }

@ -1157,15 +1157,25 @@ func (m *PairHistory) GetHistory() *PairData {
} }
type PairData struct { type PairData struct {
/// Time stamp of last result. /// Time of last failure.
Timestamp int64 `protobuf:"varint,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"` FailTime int64 `protobuf:"varint,1,opt,name=fail_time,proto3" json:"fail_time,omitempty"`
/// Minimum penalization amount (only applies to failed attempts). //*
MinPenalizeAmtSat int64 `protobuf:"varint,2,opt,name=min_penalize_amt_sat,proto3" json:"min_penalize_amt_sat,omitempty"` //Lowest amount that failed to forward rounded to whole sats. This may be
/// Whether the last payment attempt through this pair was successful. //set to zero if the failure is independent of amount.
LastAttemptSuccessful bool `protobuf:"varint,3,opt,name=last_attempt_successful,proto3" json:"last_attempt_successful,omitempty"` FailAmtSat int64 `protobuf:"varint,2,opt,name=fail_amt_sat,proto3" json:"fail_amt_sat,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"` //*
XXX_unrecognized []byte `json:"-"` //Lowest amount that failed to forward in millisats. This may be
XXX_sizecache int32 `json:"-"` //set to zero if the failure is independent of amount.
FailAmtMsat int64 `protobuf:"varint,4,opt,name=fail_amt_msat,proto3" json:"fail_amt_msat,omitempty"`
/// Time of last success.
SuccessTime int64 `protobuf:"varint,5,opt,name=success_time,proto3" json:"success_time,omitempty"`
/// Highest amount that we could successfully forward rounded to whole sats.
SuccessAmtSat int64 `protobuf:"varint,6,opt,name=success_amt_sat,proto3" json:"success_amt_sat,omitempty"`
/// Highest amount that we could successfully forward in millisats.
SuccessAmtMsat int64 `protobuf:"varint,7,opt,name=success_amt_msat,proto3" json:"success_amt_msat,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
} }
func (m *PairData) Reset() { *m = PairData{} } func (m *PairData) Reset() { *m = PairData{} }
@ -1193,25 +1203,46 @@ func (m *PairData) XXX_DiscardUnknown() {
var xxx_messageInfo_PairData proto.InternalMessageInfo var xxx_messageInfo_PairData proto.InternalMessageInfo
func (m *PairData) GetTimestamp() int64 { func (m *PairData) GetFailTime() int64 {
if m != nil { if m != nil {
return m.Timestamp return m.FailTime
} }
return 0 return 0
} }
func (m *PairData) GetMinPenalizeAmtSat() int64 { func (m *PairData) GetFailAmtSat() int64 {
if m != nil { if m != nil {
return m.MinPenalizeAmtSat return m.FailAmtSat
} }
return 0 return 0
} }
func (m *PairData) GetLastAttemptSuccessful() bool { func (m *PairData) GetFailAmtMsat() int64 {
if m != nil { if m != nil {
return m.LastAttemptSuccessful return m.FailAmtMsat
} }
return false return 0
}
func (m *PairData) GetSuccessTime() int64 {
if m != nil {
return m.SuccessTime
}
return 0
}
func (m *PairData) GetSuccessAmtSat() int64 {
if m != nil {
return m.SuccessAmtSat
}
return 0
}
func (m *PairData) GetSuccessAmtMsat() int64 {
if m != nil {
return m.SuccessAmtMsat
}
return 0
} }
type QueryProbabilityRequest struct { type QueryProbabilityRequest struct {
@ -1465,132 +1496,133 @@ func init() {
func init() { proto.RegisterFile("routerrpc/router.proto", fileDescriptor_7a0613f69d37b0a5) } func init() { proto.RegisterFile("routerrpc/router.proto", fileDescriptor_7a0613f69d37b0a5) }
var fileDescriptor_7a0613f69d37b0a5 = []byte{ var fileDescriptor_7a0613f69d37b0a5 = []byte{
// 1993 bytes of a gzipped FileDescriptorProto // 2011 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x58, 0x4f, 0x73, 0x1a, 0xc9, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x58, 0x5d, 0x73, 0x1a, 0xc9,
0x15, 0xdf, 0x11, 0x20, 0xe0, 0x01, 0xd2, 0xa8, 0xa5, 0x95, 0xc7, 0x48, 0x5a, 0x6b, 0xc7, 0x8e, 0xd5, 0xde, 0x11, 0x20, 0xe0, 0x00, 0x62, 0xd4, 0x92, 0x65, 0x8c, 0xac, 0xb5, 0x76, 0xec, 0xd7,
0x57, 0xe5, 0xf2, 0x4a, 0x8e, 0x52, 0xbb, 0xe5, 0xda, 0x43, 0x52, 0x18, 0x86, 0xd5, 0xc8, 0x30, 0xab, 0x72, 0x79, 0x25, 0xbf, 0x4a, 0xed, 0x96, 0x6b, 0x2f, 0x92, 0xc2, 0x30, 0xac, 0x46, 0x86,
0xc8, 0x0d, 0x78, 0xd7, 0xd9, 0x43, 0x57, 0x0b, 0x5a, 0x62, 0x4a, 0xc3, 0x0c, 0x3b, 0xd3, 0x38, 0x41, 0x6e, 0xc0, 0xbb, 0xce, 0x5e, 0x74, 0xb5, 0xa0, 0x25, 0xa6, 0x34, 0x1f, 0xec, 0x4c, 0xe3,
0x56, 0x3e, 0x43, 0x72, 0xcd, 0x57, 0x48, 0x0e, 0xc9, 0x29, 0xdf, 0x29, 0xa9, 0xca, 0x3d, 0xf7, 0x58, 0xff, 0x21, 0xf9, 0x1d, 0xc9, 0x45, 0x72, 0x95, 0xff, 0x94, 0x54, 0xe5, 0x32, 0x55, 0xb9,
0x54, 0x77, 0xcf, 0xc0, 0x80, 0x90, 0x36, 0x27, 0xa6, 0x7f, 0xef, 0x75, 0xbf, 0xee, 0xf7, 0xe7, 0x4f, 0x75, 0xf7, 0x0c, 0x0c, 0x08, 0x79, 0x73, 0xc5, 0xf4, 0x73, 0x9e, 0x3e, 0xa7, 0xbb, 0xcf,
0xd7, 0xaf, 0x81, 0xdd, 0x30, 0x98, 0x72, 0x16, 0x86, 0x93, 0xc1, 0x89, 0xfa, 0x3a, 0x9e, 0x84, 0x47, 0x9f, 0x06, 0xf6, 0xc2, 0x60, 0xc6, 0x59, 0x18, 0x4e, 0x47, 0x27, 0xea, 0xeb, 0x78, 0x1a,
0x01, 0x0f, 0x50, 0x71, 0x86, 0x57, 0x8b, 0xe1, 0x64, 0xa0, 0x50, 0xf3, 0x3f, 0x59, 0x40, 0x5d, 0x06, 0x3c, 0x40, 0xc5, 0x39, 0x5e, 0x2f, 0x86, 0xd3, 0x91, 0x42, 0x8d, 0x7f, 0x65, 0x01, 0xf5,
0xe6, 0x0f, 0x2f, 0xe8, 0xed, 0x98, 0xf9, 0x1c, 0xb3, 0x9f, 0xa7, 0x2c, 0xe2, 0x08, 0x41, 0x76, 0x99, 0x3f, 0xbe, 0xa0, 0xb7, 0x1e, 0xf3, 0x39, 0x66, 0xbf, 0xcc, 0x58, 0xc4, 0x11, 0x82, 0xec,
0xc8, 0x22, 0x6e, 0x68, 0x87, 0xda, 0x51, 0x19, 0xcb, 0x6f, 0xa4, 0x43, 0x86, 0x8e, 0xb9, 0xb1, 0x98, 0x45, 0xbc, 0xa6, 0x1d, 0x6a, 0x47, 0x65, 0x2c, 0xbf, 0x91, 0x0e, 0x19, 0xea, 0xf1, 0xda,
0x76, 0xa8, 0x1d, 0x65, 0xb0, 0xf8, 0x44, 0x8f, 0xa1, 0x40, 0xc7, 0x9c, 0x8c, 0x23, 0xca, 0x8d, 0xc6, 0xa1, 0x76, 0x94, 0xc1, 0xe2, 0x13, 0x3d, 0x82, 0x02, 0xf5, 0x38, 0xf1, 0x22, 0xca, 0x6b,
0xb2, 0x84, 0xf3, 0x74, 0xcc, 0xdb, 0x11, 0xe5, 0xe8, 0x4b, 0x28, 0x4f, 0xd4, 0x92, 0x64, 0x44, 0x65, 0x09, 0xe7, 0xa9, 0xc7, 0xbb, 0x11, 0xe5, 0xe8, 0x2b, 0x28, 0x4f, 0x95, 0x4a, 0x32, 0xa1,
0xa3, 0x91, 0x91, 0x91, 0x0b, 0x95, 0x62, 0xec, 0x8c, 0x46, 0x23, 0x74, 0x04, 0xfa, 0x95, 0xeb, 0xd1, 0xa4, 0x96, 0x91, 0x8a, 0x4a, 0x31, 0x76, 0x46, 0xa3, 0x09, 0x3a, 0x02, 0xfd, 0xca, 0xf1,
0x53, 0x8f, 0x0c, 0x3c, 0xfe, 0x91, 0x0c, 0x99, 0xc7, 0xa9, 0x91, 0x3d, 0xd4, 0x8e, 0x72, 0x78, 0xa9, 0x4b, 0x46, 0x2e, 0xff, 0x48, 0xc6, 0xcc, 0xe5, 0xb4, 0x96, 0x3d, 0xd4, 0x8e, 0x72, 0x78,
0x43, 0xe2, 0x75, 0x8f, 0x7f, 0x6c, 0x08, 0x14, 0x7d, 0x05, 0x9b, 0xc9, 0x62, 0xa1, 0xda, 0xa0, 0x4b, 0xe2, 0x4d, 0x97, 0x7f, 0x6c, 0x09, 0x14, 0x7d, 0x0d, 0xd5, 0x44, 0x59, 0xa8, 0x16, 0x58,
0x91, 0x3b, 0xd4, 0x8e, 0x8a, 0x78, 0x63, 0xb2, 0xb8, 0xed, 0xaf, 0x60, 0x93, 0xbb, 0x63, 0x16, 0xcb, 0x1d, 0x6a, 0x47, 0x45, 0xbc, 0x35, 0x5d, 0x5e, 0xf6, 0xd7, 0x50, 0xe5, 0x8e, 0xc7, 0x82,
0x4c, 0x39, 0x89, 0xd8, 0x20, 0xf0, 0x87, 0x91, 0xb1, 0xae, 0x56, 0x8c, 0xe1, 0xae, 0x42, 0x91, 0x19, 0x27, 0x11, 0x1b, 0x05, 0xfe, 0x38, 0xaa, 0x6d, 0x2a, 0x8d, 0x31, 0xdc, 0x57, 0x28, 0x32,
0x09, 0x95, 0x2b, 0xc6, 0x88, 0xe7, 0x8e, 0x5d, 0x4e, 0xc4, 0xf6, 0xf3, 0x72, 0xfb, 0xa5, 0x2b, 0xa0, 0x72, 0xc5, 0x18, 0x71, 0x1d, 0xcf, 0xe1, 0x44, 0x2c, 0x3f, 0x2f, 0x97, 0x5f, 0xba, 0x62,
0xc6, 0x5a, 0x02, 0xeb, 0x52, 0x8e, 0x9e, 0xc1, 0xc6, 0x5c, 0x47, 0x9e, 0xb1, 0x22, 0x95, 0xca, 0xac, 0x23, 0xb0, 0x3e, 0xe5, 0xe8, 0x19, 0x6c, 0x2d, 0x38, 0x72, 0x8f, 0x15, 0x49, 0x2a, 0x27,
0x89, 0x92, 0x3c, 0xe8, 0x4b, 0xd0, 0x83, 0x29, 0xbf, 0x0e, 0x5c, 0xff, 0x9a, 0x0c, 0x46, 0xd4, 0x24, 0xb9, 0xd1, 0x97, 0xa0, 0x07, 0x33, 0x7e, 0x1d, 0x38, 0xfe, 0x35, 0x19, 0x4d, 0xa8, 0x4f,
0x27, 0xee, 0xd0, 0x28, 0x1c, 0x6a, 0x47, 0xd9, 0x37, 0x6b, 0xaf, 0x34, 0xbc, 0x91, 0xc8, 0xea, 0x9c, 0x71, 0xad, 0x70, 0xa8, 0x1d, 0x65, 0xdf, 0x6c, 0xbc, 0xd2, 0xf0, 0x56, 0x22, 0x6b, 0x4e,
0x23, 0xea, 0xdb, 0x43, 0xf4, 0x1c, 0x36, 0x3d, 0x1a, 0x71, 0x32, 0x0a, 0x26, 0x64, 0x32, 0xbd, 0xa8, 0x6f, 0x8d, 0xd1, 0x73, 0xa8, 0xba, 0x34, 0xe2, 0x64, 0x12, 0x4c, 0xc9, 0x74, 0x76, 0x79,
0xbc, 0x61, 0xb7, 0xc6, 0x86, 0xf4, 0x4c, 0x45, 0xc0, 0x67, 0xc1, 0xe4, 0x42, 0x82, 0xe8, 0x00, 0xc3, 0x6e, 0x6b, 0x5b, 0xf2, 0x64, 0x2a, 0x02, 0x3e, 0x0b, 0xa6, 0x17, 0x12, 0x44, 0x07, 0x00,
0x40, 0x7a, 0x45, 0x1a, 0x37, 0x8a, 0xf2, 0x0c, 0x45, 0x81, 0x48, 0xc3, 0xe8, 0x14, 0x4a, 0x32, 0xf2, 0x54, 0xa4, 0xf1, 0x5a, 0x51, 0xee, 0xa1, 0x28, 0x10, 0x69, 0x18, 0x9d, 0x42, 0x49, 0x7a,
0x9a, 0x64, 0xe4, 0xfa, 0x3c, 0x32, 0xe0, 0x30, 0x73, 0x54, 0x3a, 0xd5, 0x8f, 0x3d, 0x5f, 0x04, 0x93, 0x4c, 0x1c, 0x9f, 0x47, 0x35, 0x38, 0xcc, 0x1c, 0x95, 0x4e, 0xf5, 0x63, 0xd7, 0x17, 0x8e,
0x16, 0x0b, 0xc9, 0x99, 0xeb, 0x73, 0x9c, 0x56, 0x42, 0x16, 0x14, 0x44, 0x18, 0x09, 0xf7, 0x3e, 0xc5, 0x42, 0x72, 0xe6, 0xf8, 0x1c, 0xa7, 0x49, 0xc8, 0x84, 0x82, 0x70, 0x23, 0xe1, 0xee, 0xc7,
0x1a, 0x25, 0x39, 0xe1, 0xc5, 0xf1, 0x2c, 0x25, 0x8e, 0xef, 0xe6, 0xc0, 0x71, 0x83, 0x45, 0xbc, 0x5a, 0x49, 0x4e, 0x78, 0x71, 0x3c, 0x0f, 0x89, 0xe3, 0xbb, 0x31, 0x70, 0xdc, 0x62, 0x11, 0x1f,
0xe7, 0x7d, 0xb4, 0x7c, 0x1e, 0xde, 0xe2, 0xfc, 0x50, 0x8d, 0xaa, 0xdf, 0x41, 0x39, 0x2d, 0x10, 0xb8, 0x1f, 0x4d, 0x9f, 0x87, 0xb7, 0x38, 0x3f, 0x56, 0xa3, 0xfa, 0xf7, 0x50, 0x4e, 0x0b, 0x44,
0x59, 0x21, 0x4e, 0x21, 0x12, 0x25, 0x8b, 0xc5, 0x27, 0xda, 0x81, 0xdc, 0x47, 0xea, 0x4d, 0x99, 0x54, 0x88, 0x5d, 0x88, 0x40, 0xc9, 0x62, 0xf1, 0x89, 0x76, 0x21, 0xf7, 0x91, 0xba, 0x33, 0x26,
0xcc, 0x94, 0x32, 0x56, 0x83, 0xef, 0xd6, 0x5e, 0x6b, 0xe6, 0x6b, 0xd8, 0xee, 0x85, 0x74, 0x70, 0x23, 0xa5, 0x8c, 0xd5, 0xe0, 0xfb, 0x8d, 0xd7, 0x9a, 0xf1, 0x1a, 0x76, 0x06, 0x21, 0x1d, 0xdd,
0xb3, 0x94, 0x6c, 0xcb, 0xb9, 0xa2, 0xdd, 0xc9, 0x15, 0xf3, 0x6f, 0x1a, 0x54, 0xe2, 0x59, 0x5d, 0xac, 0x04, 0xdb, 0x6a, 0xac, 0x68, 0x77, 0x62, 0xc5, 0xf8, 0x8b, 0x06, 0x95, 0x78, 0x56, 0x9f,
0x4e, 0xf9, 0x34, 0x42, 0x5f, 0x43, 0x2e, 0xe2, 0x94, 0x33, 0xa9, 0xbd, 0x71, 0xfa, 0x28, 0x75, 0x53, 0x3e, 0x8b, 0xd0, 0x37, 0x90, 0x8b, 0x38, 0xe5, 0x4c, 0xb2, 0xb7, 0x4e, 0x1f, 0xa6, 0xf6,
0x96, 0x94, 0x22, 0xc3, 0x4a, 0x0b, 0x55, 0xa1, 0x30, 0x09, 0x99, 0x3b, 0xa6, 0xd7, 0xc9, 0xbe, 0x92, 0x22, 0x32, 0xac, 0x58, 0xa8, 0x0e, 0x85, 0x69, 0xc8, 0x1c, 0x8f, 0x5e, 0x27, 0xeb, 0x9a,
0x66, 0x63, 0x64, 0x42, 0x4e, 0x4e, 0x96, 0x49, 0x5a, 0x3a, 0x2d, 0xa7, 0xfd, 0x88, 0x95, 0x08, 0x8f, 0x91, 0x01, 0x39, 0x39, 0x59, 0x06, 0x69, 0xe9, 0xb4, 0x9c, 0x3e, 0x47, 0xac, 0x44, 0xe8,
0x1d, 0x41, 0x6e, 0xc4, 0xbd, 0x41, 0x64, 0x64, 0xa5, 0xeb, 0x50, 0xac, 0x73, 0xd6, 0x6b, 0xd5, 0x08, 0x72, 0x13, 0xee, 0x8e, 0xa2, 0x5a, 0x56, 0x1e, 0x1d, 0x8a, 0x39, 0x67, 0x83, 0x4e, 0xb3,
0x6b, 0x9c, 0xb3, 0xf1, 0x84, 0x63, 0xa5, 0x60, 0xfe, 0x16, 0x36, 0xe5, 0xcc, 0x26, 0x63, 0x0f, 0xc1, 0x39, 0xf3, 0xa6, 0x1c, 0x2b, 0x82, 0xf1, 0x5b, 0xa8, 0xca, 0x99, 0x6d, 0xc6, 0x3e, 0x97,
0x55, 0xd3, 0x23, 0x10, 0xb5, 0x22, 0x73, 0x4f, 0x55, 0xd4, 0x3a, 0x1d, 0x8b, 0xb4, 0x33, 0x87, 0x4d, 0x0f, 0x41, 0xe4, 0x8a, 0x8c, 0x3d, 0x95, 0x51, 0x9b, 0xd4, 0x13, 0x61, 0x67, 0x8c, 0x41,
0xa0, 0xcf, 0xe7, 0x47, 0x93, 0xc0, 0x8f, 0x84, 0x75, 0x5d, 0x6c, 0x43, 0xe4, 0x98, 0x48, 0x49, 0x5f, 0xcc, 0x8f, 0xa6, 0x81, 0x1f, 0x09, 0xeb, 0xba, 0x58, 0x86, 0x88, 0x31, 0x11, 0x92, 0x32,
0x99, 0x8c, 0x9a, 0x9c, 0xb5, 0x11, 0xe3, 0x4d, 0xc6, 0x64, 0x3a, 0x3e, 0x57, 0x15, 0x40, 0xbc, 0x18, 0x35, 0x39, 0x6b, 0x2b, 0xc6, 0xdb, 0x8c, 0xc9, 0x70, 0x7c, 0xae, 0x32, 0x80, 0xb8, 0xc1,
0x60, 0x70, 0x23, 0x6a, 0x8a, 0xde, 0xc6, 0xcb, 0x57, 0x04, 0xdc, 0x0a, 0x06, 0x37, 0x0d, 0x01, 0xe8, 0x46, 0xe4, 0x14, 0xbd, 0x8d, 0xd5, 0x57, 0x04, 0xdc, 0x09, 0x46, 0x37, 0x2d, 0x01, 0x1a,
0x9a, 0x3f, 0xa9, 0xb2, 0xef, 0x05, 0xea, 0x94, 0xff, 0x77, 0x24, 0xe6, 0xce, 0x5a, 0xbb, 0xd7, 0x3f, 0xab, 0xb4, 0x1f, 0x04, 0x6a, 0x97, 0xff, 0xb3, 0x27, 0x16, 0x87, 0xb5, 0x71, 0xef, 0x61,
0x59, 0x26, 0x81, 0xed, 0x85, 0xc5, 0xe3, 0x53, 0xa4, 0x63, 0xa0, 0x2d, 0xc5, 0xe0, 0x25, 0xe4, 0x19, 0x04, 0x76, 0x96, 0x94, 0xc7, 0xbb, 0x48, 0xfb, 0x40, 0x5b, 0xf1, 0xc1, 0x4b, 0xc8, 0x5f,
0xaf, 0xa8, 0xeb, 0x4d, 0xc3, 0x64, 0x61, 0x94, 0x0a, 0x68, 0x53, 0x49, 0x70, 0xa2, 0x62, 0xfe, 0x51, 0xc7, 0x9d, 0x85, 0x89, 0x62, 0x94, 0x72, 0x68, 0x5b, 0x49, 0x70, 0x42, 0x31, 0xfe, 0x93,
0x37, 0x0f, 0xf9, 0x18, 0x44, 0xa7, 0x90, 0x1d, 0x04, 0xc3, 0x24, 0x0f, 0xbe, 0xb8, 0x3b, 0x2d, 0x87, 0x7c, 0x0c, 0xa2, 0x53, 0xc8, 0x8e, 0x82, 0x71, 0x12, 0x07, 0x5f, 0xde, 0x9d, 0x96, 0xfc,
0xf9, 0xad, 0x07, 0x43, 0x86, 0xa5, 0x2e, 0xfa, 0x1d, 0x6c, 0x88, 0x5a, 0xf5, 0x99, 0x47, 0xa6, 0x36, 0x83, 0x31, 0xc3, 0x92, 0x8b, 0x7e, 0x07, 0x5b, 0x22, 0x57, 0x7d, 0xe6, 0x92, 0xd9, 0x74,
0x93, 0x21, 0x9d, 0x85, 0xde, 0x48, 0xcd, 0xae, 0x2b, 0x85, 0xbe, 0x94, 0xe3, 0xca, 0x20, 0x3d, 0x4c, 0xe7, 0xae, 0xaf, 0xa5, 0x66, 0x37, 0x15, 0x61, 0x28, 0xe5, 0xb8, 0x32, 0x4a, 0x0f, 0xd1,
0x44, 0x7b, 0x50, 0x14, 0xd1, 0x56, 0x91, 0xc8, 0xca, 0xdc, 0x2f, 0x08, 0x40, 0xc6, 0xc0, 0x84, 0x3e, 0x14, 0x85, 0xb7, 0x95, 0x27, 0xb2, 0x32, 0xf6, 0x0b, 0x02, 0x90, 0x3e, 0x30, 0xa0, 0x12,
0x4a, 0xe0, 0xbb, 0x81, 0x4f, 0xa2, 0x11, 0x25, 0xa7, 0xdf, 0x7c, 0x2b, 0xc9, 0xaa, 0x8c, 0x4b, 0xf8, 0x4e, 0xe0, 0x93, 0x68, 0x42, 0xc9, 0xe9, 0xb7, 0xdf, 0xc9, 0x62, 0x55, 0xc6, 0x25, 0x09,
0x12, 0xec, 0x8e, 0xe8, 0xe9, 0x37, 0xdf, 0xa2, 0x27, 0x50, 0x92, 0x05, 0xce, 0x3e, 0x4d, 0xdc, 0xf6, 0x27, 0xf4, 0xf4, 0xdb, 0xef, 0xd0, 0x13, 0x28, 0xc9, 0x04, 0x67, 0x9f, 0xa6, 0x4e, 0x78,
0xf0, 0x56, 0xb2, 0x54, 0x05, 0xcb, 0x9a, 0xb7, 0x24, 0x22, 0xaa, 0xe8, 0xca, 0xa3, 0xd7, 0x91, 0x2b, 0xab, 0x54, 0x05, 0xcb, 0x9c, 0x37, 0x25, 0x22, 0xb2, 0xe8, 0xca, 0xa5, 0xd7, 0x91, 0xac,
0x64, 0xa6, 0x0a, 0x56, 0x03, 0xf4, 0x0a, 0x76, 0x62, 0x1f, 0x90, 0x28, 0x98, 0x86, 0x03, 0x46, 0x4c, 0x15, 0xac, 0x06, 0xe8, 0x15, 0xec, 0xc6, 0x67, 0x40, 0xa2, 0x60, 0x16, 0x8e, 0x18, 0x71,
0x5c, 0x7f, 0xc8, 0x3e, 0x49, 0xc6, 0xa9, 0x60, 0x14, 0xcb, 0xba, 0x52, 0x64, 0x0b, 0x09, 0xda, 0xfc, 0x31, 0xfb, 0x24, 0x2b, 0x4e, 0x05, 0xa3, 0x58, 0xd6, 0x97, 0x22, 0x4b, 0x48, 0xd0, 0x1e,
0x85, 0xf5, 0x11, 0x73, 0xaf, 0x47, 0x8a, 0x45, 0x2a, 0x38, 0x1e, 0x99, 0x7f, 0xcf, 0x41, 0x29, 0x6c, 0x4e, 0x98, 0x73, 0x3d, 0x51, 0x55, 0xa4, 0x82, 0xe3, 0x91, 0xf1, 0xd7, 0x1c, 0x94, 0x52,
0xe5, 0x18, 0x54, 0x86, 0x02, 0xb6, 0xba, 0x16, 0x7e, 0x6f, 0x35, 0xf4, 0xcf, 0xd0, 0x11, 0x3c, 0x07, 0x83, 0xca, 0x50, 0xc0, 0x66, 0xdf, 0xc4, 0xef, 0xcd, 0x96, 0xfe, 0x05, 0x3a, 0x82, 0x67,
0xb3, 0x9d, 0x7a, 0x07, 0x63, 0xab, 0xde, 0x23, 0x1d, 0x4c, 0xfa, 0xce, 0x5b, 0xa7, 0xf3, 0x83, 0x96, 0xdd, 0xec, 0x61, 0x6c, 0x36, 0x07, 0xa4, 0x87, 0xc9, 0xd0, 0x7e, 0x6b, 0xf7, 0x7e, 0xb4,
0x43, 0x2e, 0x6a, 0x1f, 0xda, 0x96, 0xd3, 0x23, 0x0d, 0xab, 0x57, 0xb3, 0x5b, 0x5d, 0x5d, 0x43, 0xc9, 0x45, 0xe3, 0x43, 0xd7, 0xb4, 0x07, 0xa4, 0x65, 0x0e, 0x1a, 0x56, 0xa7, 0xaf, 0x6b, 0xe8,
0xfb, 0x60, 0xcc, 0x35, 0x13, 0x71, 0xad, 0xdd, 0xe9, 0x3b, 0x3d, 0x7d, 0x0d, 0x3d, 0x81, 0xbd, 0x31, 0xd4, 0x16, 0xcc, 0x44, 0xdc, 0xe8, 0xf6, 0x86, 0xf6, 0x40, 0xdf, 0x40, 0x4f, 0x60, 0xbf,
0xa6, 0xed, 0xd4, 0x5a, 0x64, 0xae, 0x53, 0x6f, 0xf5, 0xde, 0x13, 0xeb, 0xc7, 0x0b, 0x1b, 0x7f, 0x6d, 0xd9, 0x8d, 0x0e, 0x59, 0x70, 0x9a, 0x9d, 0xc1, 0x7b, 0x62, 0xfe, 0x74, 0x61, 0xe1, 0x0f,
0xd0, 0x33, 0xab, 0x14, 0x44, 0x4d, 0x25, 0x2b, 0x64, 0xd1, 0x63, 0xf8, 0x5c, 0x29, 0xa8, 0x29, 0x7a, 0x66, 0x1d, 0x41, 0xe4, 0x54, 0xa2, 0x21, 0x8b, 0x1e, 0xc1, 0x03, 0x45, 0x50, 0x53, 0xc8,
0xa4, 0xd7, 0xe9, 0x90, 0x6e, 0xa7, 0xe3, 0xe8, 0x39, 0xb4, 0x05, 0x15, 0xdb, 0x79, 0x5f, 0x6b, 0xa0, 0xd7, 0x23, 0xfd, 0x5e, 0xcf, 0xd6, 0x73, 0x68, 0x1b, 0x2a, 0x96, 0xfd, 0xbe, 0xd1, 0xb1,
0xd9, 0x0d, 0x82, 0xad, 0x5a, 0xab, 0xad, 0xaf, 0xa3, 0x6d, 0xd8, 0x5c, 0xd6, 0xcb, 0x8b, 0x25, 0x5a, 0x04, 0x9b, 0x8d, 0x4e, 0x57, 0xdf, 0x44, 0x3b, 0x50, 0x5d, 0xe5, 0xe5, 0x85, 0x8a, 0x84,
0x12, 0xbd, 0x8e, 0x63, 0x77, 0x1c, 0xf2, 0xde, 0xc2, 0x5d, 0xbb, 0xe3, 0xe8, 0x05, 0xb4, 0x0b, 0xd7, 0xb3, 0xad, 0x9e, 0x4d, 0xde, 0x9b, 0xb8, 0x6f, 0xf5, 0x6c, 0xbd, 0x80, 0xf6, 0x00, 0x2d,
0x68, 0x51, 0x74, 0xd6, 0xae, 0xd5, 0xf5, 0x22, 0xfa, 0x1c, 0xb6, 0x16, 0xf1, 0xb7, 0xd6, 0x07, 0x8b, 0xce, 0xba, 0x8d, 0xa6, 0x5e, 0x44, 0x0f, 0x60, 0x7b, 0x19, 0x7f, 0x6b, 0x7e, 0xd0, 0x01,
0x1d, 0x90, 0x01, 0x3b, 0x6a, 0x63, 0xe4, 0x8d, 0xd5, 0xea, 0xfc, 0x40, 0xda, 0xb6, 0x63, 0xb7, 0xd5, 0x60, 0x57, 0x2d, 0x8c, 0xbc, 0x31, 0x3b, 0xbd, 0x1f, 0x49, 0xd7, 0xb2, 0xad, 0xee, 0xb0,
0xfb, 0x6d, 0xbd, 0x84, 0x76, 0x40, 0x6f, 0x5a, 0x16, 0xb1, 0x9d, 0x6e, 0xbf, 0xd9, 0xb4, 0xeb, 0xab, 0x97, 0xd0, 0x2e, 0xe8, 0x6d, 0xd3, 0x24, 0x96, 0xdd, 0x1f, 0xb6, 0xdb, 0x56, 0xd3, 0x32,
0xb6, 0xe5, 0xf4, 0xf4, 0xb2, 0xb2, 0xbc, 0xea, 0xe0, 0x15, 0x31, 0xa1, 0x7e, 0x56, 0x73, 0x1c, 0xed, 0x81, 0x5e, 0x56, 0x96, 0xd7, 0x6d, 0xbc, 0x22, 0x26, 0x34, 0xcf, 0x1a, 0xb6, 0x6d, 0x76,
0xab, 0x45, 0x1a, 0x76, 0xb7, 0xf6, 0xa6, 0x65, 0x35, 0xf4, 0x0d, 0x74, 0x00, 0x8f, 0x7b, 0x56, 0x48, 0xcb, 0xea, 0x37, 0xde, 0x74, 0xcc, 0x96, 0xbe, 0x85, 0x0e, 0xe0, 0xd1, 0xc0, 0xec, 0x5e,
0xfb, 0xa2, 0x83, 0x6b, 0xf8, 0x03, 0x49, 0xe4, 0xcd, 0x9a, 0xdd, 0xea, 0x63, 0x4b, 0xdf, 0x44, 0xf4, 0x70, 0x03, 0x7f, 0x20, 0x89, 0xbc, 0xdd, 0xb0, 0x3a, 0x43, 0x6c, 0xea, 0x55, 0xf4, 0x15,
0x5f, 0xc2, 0x01, 0xb6, 0xde, 0xf5, 0x6d, 0x6c, 0x35, 0x88, 0xd3, 0x69, 0x58, 0xa4, 0x69, 0xd5, 0x1c, 0x60, 0xf3, 0xdd, 0xd0, 0xc2, 0x66, 0x8b, 0xd8, 0xbd, 0x96, 0x49, 0xda, 0x66, 0x63, 0x30,
0x7a, 0x7d, 0x6c, 0x91, 0xb6, 0xdd, 0xed, 0xda, 0xce, 0xf7, 0xba, 0x8e, 0x9e, 0xc1, 0xe1, 0x4c, 0xc4, 0x26, 0xe9, 0x5a, 0xfd, 0xbe, 0x65, 0xff, 0xa0, 0xeb, 0xe8, 0x19, 0x1c, 0xce, 0x29, 0x73,
0x65, 0xb6, 0xc0, 0x92, 0xd6, 0x96, 0x38, 0x5f, 0x12, 0x52, 0xc7, 0xfa, 0xb1, 0x47, 0x2e, 0x2c, 0x05, 0x2b, 0xac, 0x6d, 0xb1, 0xbf, 0xc4, 0xa5, 0xb6, 0xf9, 0xd3, 0x80, 0x5c, 0x98, 0x26, 0xd6,
0x0b, 0xeb, 0x08, 0x55, 0x61, 0x77, 0x6e, 0x5e, 0x19, 0x88, 0x6d, 0x6f, 0x0b, 0xd9, 0x85, 0x85, 0x11, 0xaa, 0xc3, 0xde, 0xc2, 0xbc, 0x32, 0x10, 0xdb, 0xde, 0x11, 0xb2, 0x0b, 0x13, 0x77, 0x1b,
0xdb, 0x35, 0x47, 0x04, 0x78, 0x41, 0xb6, 0x23, 0xb6, 0x3d, 0x97, 0x2d, 0x6f, 0xfb, 0x73, 0x84, 0xb6, 0x70, 0xf0, 0x92, 0x6c, 0x57, 0x2c, 0x7b, 0x21, 0x5b, 0x5d, 0xf6, 0x03, 0x84, 0x60, 0x2b,
0x60, 0x23, 0x15, 0x95, 0x66, 0x0d, 0xeb, 0xbb, 0x68, 0x07, 0x36, 0x93, 0x1d, 0x24, 0x8a, 0xff, 0xe5, 0x95, 0x76, 0x03, 0xeb, 0x7b, 0x68, 0x17, 0xaa, 0xc9, 0x0a, 0x12, 0xe2, 0x3f, 0xf2, 0xe8,
0xca, 0xa3, 0x47, 0x80, 0xfa, 0x0e, 0xb6, 0x6a, 0x0d, 0xe1, 0x90, 0x99, 0xe0, 0xdf, 0xf9, 0xf3, 0x21, 0xa0, 0xa1, 0x8d, 0xcd, 0x46, 0x4b, 0x1c, 0xc8, 0x5c, 0xf0, 0xcf, 0xfc, 0x79, 0xb6, 0xb0,
0x6c, 0x61, 0x4d, 0xcf, 0x98, 0xff, 0xcc, 0x40, 0x65, 0xa1, 0x2e, 0xd1, 0x3e, 0x14, 0x23, 0xf7, 0xa1, 0x67, 0x8c, 0xbf, 0x67, 0xa0, 0xb2, 0x94, 0x97, 0xe8, 0x31, 0x14, 0x23, 0xe7, 0xda, 0xa7,
0xda, 0xa7, 0x5c, 0x30, 0x87, 0x22, 0x95, 0x39, 0x20, 0xaf, 0xd1, 0x11, 0x75, 0x7d, 0xc5, 0x66, 0x5c, 0x54, 0x0e, 0x55, 0x54, 0x16, 0x80, 0xbc, 0x46, 0x27, 0xd4, 0xf1, 0x55, 0x35, 0x53, 0x75,
0x8a, 0xf7, 0x8b, 0x12, 0x91, 0x5c, 0xb6, 0x07, 0xf9, 0xe4, 0xca, 0xce, 0xcc, 0xae, 0xec, 0xf5, 0xbf, 0x28, 0x11, 0x59, 0xcb, 0xf6, 0x21, 0x9f, 0x5c, 0xd9, 0x99, 0xf9, 0x95, 0xbd, 0x39, 0x52,
0x81, 0xba, 0xaa, 0xf7, 0xa1, 0x28, 0x28, 0x33, 0xe2, 0x74, 0x3c, 0x91, 0x25, 0x5e, 0xc1, 0x73, 0x57, 0xf5, 0x63, 0x28, 0x8a, 0x92, 0x19, 0x71, 0xea, 0x4d, 0x65, 0x8a, 0x57, 0xf0, 0x02, 0x40,
0x00, 0x3d, 0x85, 0xca, 0x98, 0x45, 0x11, 0xbd, 0x66, 0x44, 0x95, 0x29, 0x48, 0x8d, 0x72, 0x0c, 0x4f, 0xa1, 0xe2, 0xb1, 0x28, 0xa2, 0xd7, 0x8c, 0xa8, 0x34, 0x05, 0xc9, 0x28, 0xc7, 0x60, 0x5b,
0x36, 0x65, 0xb5, 0x3e, 0x85, 0x84, 0x36, 0x62, 0xa5, 0x9c, 0x52, 0x8a, 0x41, 0xa5, 0xb4, 0xcc, 0x66, 0xeb, 0x53, 0x48, 0xca, 0x46, 0x4c, 0xca, 0x29, 0x52, 0x0c, 0x2a, 0xd2, 0x6a, 0xc5, 0xe6,
0xd8, 0x9c, 0xc6, 0x6c, 0x90, 0x66, 0x6c, 0x4e, 0xd1, 0x0b, 0xd8, 0x52, 0x94, 0xe3, 0xfa, 0xee, 0x34, 0xae, 0x06, 0xe9, 0x8a, 0xcd, 0x29, 0x7a, 0x01, 0xdb, 0xaa, 0xe4, 0x38, 0xbe, 0xe3, 0xcd,
0x78, 0x3a, 0x56, 0xd4, 0x93, 0x97, 0xd4, 0xb3, 0x29, 0xa9, 0x47, 0xe1, 0x92, 0x81, 0x1e, 0x43, 0x3c, 0x55, 0x7a, 0xf2, 0xb2, 0xf4, 0x54, 0x65, 0xe9, 0x51, 0xb8, 0xac, 0x40, 0x8f, 0xa0, 0x70,
0xe1, 0x92, 0x46, 0x4c, 0x5c, 0x16, 0x31, 0x35, 0xe4, 0xc5, 0xb8, 0xc9, 0x98, 0x10, 0x89, 0x2b, 0x49, 0x23, 0x26, 0x2e, 0x8b, 0xb8, 0x34, 0xe4, 0xc5, 0xb8, 0xcd, 0x98, 0x10, 0x89, 0x2b, 0x24,
0x24, 0x14, 0xa4, 0xa7, 0x18, 0x21, 0x7f, 0xc5, 0x18, 0x16, 0xbe, 0x9c, 0x59, 0xa0, 0x9f, 0xe6, 0x14, 0x45, 0x4f, 0x55, 0x84, 0xfc, 0x15, 0x63, 0x58, 0x9c, 0xe5, 0xdc, 0x02, 0xfd, 0xb4, 0xb0,
0x16, 0x4a, 0x29, 0x0b, 0x0a, 0x97, 0x16, 0x5e, 0xc0, 0x16, 0xfb, 0xc4, 0x43, 0x4a, 0x82, 0x09, 0x50, 0x4a, 0x59, 0x50, 0xb8, 0xb4, 0xf0, 0x02, 0xb6, 0xd9, 0x27, 0x1e, 0x52, 0x12, 0x4c, 0xe9,
0xfd, 0x79, 0xca, 0xc8, 0x90, 0x72, 0x2a, 0x7b, 0xc0, 0x32, 0xde, 0x94, 0x82, 0x8e, 0xc4, 0x1b, 0x2f, 0x33, 0x46, 0xc6, 0x94, 0x53, 0xd9, 0x03, 0x96, 0x71, 0x55, 0x0a, 0x7a, 0x12, 0x6f, 0x51,
0x94, 0x53, 0x73, 0x1f, 0xaa, 0x98, 0x45, 0x8c, 0xb7, 0xdd, 0x28, 0x72, 0x03, 0xbf, 0x1e, 0xf8, 0x4e, 0x8d, 0xc7, 0x50, 0xc7, 0x2c, 0x62, 0xbc, 0xeb, 0x44, 0x91, 0x13, 0xf8, 0xcd, 0xc0, 0xe7,
0x3c, 0x0c, 0xbc, 0xf8, 0xce, 0x31, 0x0f, 0x60, 0x6f, 0xa5, 0x54, 0x5d, 0x1a, 0x62, 0xf2, 0xbb, 0x61, 0xe0, 0xc6, 0x77, 0x8e, 0x71, 0x00, 0xfb, 0x6b, 0xa5, 0xea, 0xd2, 0x10, 0x93, 0xdf, 0xcd,
0x29, 0x0b, 0x6f, 0x57, 0x4f, 0x7e, 0x07, 0x7b, 0x2b, 0xa5, 0xf1, 0x8d, 0xf3, 0x12, 0x72, 0x13, 0x58, 0x78, 0xbb, 0x7e, 0xf2, 0x3b, 0xd8, 0x5f, 0x2b, 0x8d, 0x6f, 0x9c, 0x97, 0x90, 0x9b, 0x52,
0xea, 0x86, 0x91, 0xb1, 0x26, 0x6f, 0xed, 0xdd, 0x85, 0x26, 0xc1, 0x0d, 0xcf, 0xdc, 0x88, 0x07, 0x27, 0x8c, 0x6a, 0x1b, 0xf2, 0xd6, 0xde, 0x5b, 0x6a, 0x12, 0x9c, 0xf0, 0xcc, 0x89, 0x78, 0x10,
0xe1, 0x2d, 0x56, 0x4a, 0xe7, 0xd9, 0x82, 0xa6, 0xaf, 0x99, 0x7f, 0xd2, 0xa0, 0x94, 0x12, 0x8a, 0xde, 0x62, 0x45, 0x3a, 0xcf, 0x16, 0x34, 0x7d, 0xc3, 0xf8, 0xa3, 0x06, 0xa5, 0x94, 0x50, 0xc4,
0x3c, 0xf0, 0x83, 0x21, 0x23, 0x57, 0x61, 0x30, 0x4e, 0x32, 0x6c, 0x06, 0x20, 0x03, 0xf2, 0x72, 0x81, 0x1f, 0x8c, 0x19, 0xb9, 0x0a, 0x03, 0x2f, 0x89, 0xb0, 0x39, 0x80, 0x6a, 0x90, 0x97, 0x03,
0xc0, 0x83, 0x38, 0xbd, 0x92, 0x21, 0xfa, 0x1a, 0xf2, 0x23, 0xb5, 0x84, 0x8c, 0x52, 0xe9, 0x74, 0x1e, 0xc4, 0xe1, 0x95, 0x0c, 0xd1, 0x37, 0x90, 0x9f, 0x28, 0x15, 0xd2, 0x4b, 0xa5, 0xd3, 0x9d,
0x7b, 0xc9, 0xba, 0xf0, 0x0d, 0x4e, 0x74, 0xce, 0xb3, 0x85, 0x8c, 0x9e, 0x3d, 0xcf, 0x16, 0xb2, 0x15, 0xeb, 0xe2, 0x6c, 0x70, 0xc2, 0x39, 0xcf, 0x16, 0x32, 0x7a, 0xf6, 0x3c, 0x5b, 0xc8, 0xea,
0x7a, 0xee, 0x3c, 0x5b, 0xc8, 0xe9, 0xeb, 0xe7, 0xd9, 0xc2, 0xba, 0x9e, 0x37, 0xff, 0xa2, 0x41, 0xb9, 0xf3, 0x6c, 0x21, 0xa7, 0x6f, 0x9e, 0x67, 0x0b, 0x9b, 0x7a, 0xde, 0xf8, 0xb7, 0x06, 0x85,
0x21, 0xd1, 0x5e, 0xcc, 0x49, 0xd5, 0x00, 0xa4, 0x72, 0xf2, 0x14, 0x76, 0xc6, 0xae, 0x4f, 0x26, 0x84, 0x2d, 0xd6, 0x22, 0x4a, 0x3c, 0x11, 0x91, 0x11, 0x37, 0x00, 0x0b, 0x00, 0x19, 0x50, 0x96,
0xcc, 0xa7, 0x9e, 0xfb, 0x47, 0x46, 0x16, 0xfb, 0x8b, 0x95, 0x32, 0xf4, 0x1a, 0x1e, 0xc9, 0x86, 0x83, 0xe5, 0xbe, 0x62, 0x09, 0x43, 0xcf, 0xa0, 0x32, 0x1f, 0xcf, 0x2f, 0xaf, 0x0c, 0x5e, 0x06,
0x94, 0xaa, 0x26, 0x86, 0x44, 0xd3, 0xc1, 0x80, 0x45, 0xd1, 0xd5, 0xd4, 0x93, 0x25, 0x51, 0xc0, 0x85, 0xa6, 0x68, 0x36, 0x1a, 0xb1, 0x28, 0x52, 0xa6, 0x72, 0x4a, 0x53, 0x1a, 0x43, 0x47, 0x50,
0xf7, 0x89, 0xcd, 0x31, 0x3c, 0x92, 0xae, 0xbf, 0x08, 0x83, 0x4b, 0x7a, 0xe9, 0x7a, 0x2e, 0xbf, 0x4d, 0xc6, 0x89, 0xc1, 0x4d, 0x49, 0x5b, 0x85, 0xd1, 0x0b, 0xd0, 0xd3, 0x90, 0xb7, 0xe8, 0xb7,
0x4d, 0xda, 0x88, 0x7d, 0x28, 0x0a, 0xe7, 0x10, 0x3f, 0xb9, 0x97, 0xcb, 0x78, 0x0e, 0x08, 0x97, 0xef, 0xe0, 0xea, 0x18, 0x0c, 0x0f, 0x1e, 0x4a, 0xb7, 0x5e, 0x84, 0xc1, 0x25, 0xbd, 0x74, 0x5c,
0xf1, 0x40, 0xc9, 0x62, 0x97, 0xc5, 0x43, 0xd1, 0x20, 0xcc, 0xde, 0x13, 0x19, 0xb9, 0xe9, 0xd9, 0x87, 0xdf, 0x26, 0x2d, 0x8a, 0x38, 0x82, 0x30, 0xf0, 0x88, 0x9f, 0xdc, 0xf9, 0x65, 0xbc, 0x00,
0xd8, 0xbc, 0x01, 0xe3, 0xae, 0xb9, 0x38, 0xcc, 0x87, 0x50, 0x9a, 0xcc, 0x61, 0x69, 0x51, 0xc3, 0x84, 0x3b, 0x78, 0xa0, 0x64, 0xb1, 0x3b, 0xe2, 0xa1, 0x68, 0x3e, 0xe6, 0xc6, 0x33, 0xd2, 0xf8,
0x69, 0x28, 0x1d, 0x8c, 0xb5, 0x5f, 0x0e, 0x86, 0xf9, 0x57, 0x0d, 0xb6, 0xde, 0x4c, 0x5d, 0x6f, 0x7c, 0x6c, 0xdc, 0x40, 0xed, 0xae, 0xb9, 0x38, 0x84, 0x0e, 0xa1, 0x34, 0x5d, 0xc0, 0xd2, 0xa2,
0xb8, 0xd0, 0x1d, 0xa5, 0x9f, 0x3b, 0xda, 0xe2, 0x73, 0x67, 0xd5, 0x5b, 0x66, 0x6d, 0xe5, 0x5b, 0x86, 0xd3, 0x50, 0xda, 0xd1, 0x1b, 0xbf, 0xee, 0x68, 0xe3, 0xcf, 0x1a, 0x6c, 0xbf, 0x99, 0x39,
0x66, 0xd5, 0x7b, 0x21, 0x73, 0xef, 0x7b, 0xe1, 0x09, 0x94, 0xe6, 0x4f, 0x05, 0xd5, 0x7c, 0x96, 0xee, 0x78, 0xa9, 0xf3, 0x4a, 0x3f, 0xa5, 0xb4, 0xe5, 0xa7, 0xd4, 0xba, 0x77, 0xd2, 0xc6, 0xda,
0x31, 0x8c, 0x92, 0x77, 0x42, 0x64, 0xbe, 0x06, 0x94, 0xde, 0x68, 0xec, 0x90, 0x59, 0x93, 0xa6, 0x77, 0xd2, 0xba, 0xb7, 0x48, 0xe6, 0xde, 0xb7, 0xc8, 0x13, 0x28, 0x2d, 0x9e, 0x21, 0xaa, 0xb1,
0xdd, 0xdb, 0xa4, 0xbd, 0xf8, 0xb3, 0x06, 0xe5, 0x74, 0xa7, 0x8c, 0x2a, 0x50, 0xb4, 0x1d, 0xd2, 0x2d, 0x63, 0x98, 0x24, 0x6f, 0x90, 0xc8, 0x78, 0x0d, 0x28, 0xbd, 0xd0, 0xf8, 0x40, 0xe6, 0x0d,
0x6c, 0xd9, 0xdf, 0x9f, 0xf5, 0xf4, 0xcf, 0xc4, 0xb0, 0xdb, 0xaf, 0xd7, 0x2d, 0xab, 0x61, 0x35, 0xa0, 0x76, 0x6f, 0x03, 0xf8, 0xe2, 0x4f, 0x1a, 0x94, 0xd3, 0x5d, 0x38, 0xaa, 0x40, 0xd1, 0xb2,
0x74, 0x4d, 0x70, 0xb8, 0xa0, 0x63, 0xab, 0x41, 0x7a, 0x76, 0xdb, 0xea, 0xf4, 0xc5, 0xed, 0xbe, 0x49, 0xbb, 0x63, 0xfd, 0x70, 0x36, 0xd0, 0xbf, 0x10, 0xc3, 0xfe, 0xb0, 0xd9, 0x34, 0xcd, 0x96,
0x0d, 0x9b, 0x31, 0xe6, 0x74, 0x08, 0xee, 0xf4, 0x7b, 0x96, 0x9e, 0x41, 0x3a, 0x94, 0x63, 0xd0, 0xd9, 0xd2, 0x35, 0x71, 0x3f, 0x88, 0x52, 0x6f, 0xb6, 0xc8, 0xc0, 0xea, 0x9a, 0xbd, 0xa1, 0xe8,
0xc2, 0xb8, 0x83, 0xf5, 0xac, 0xb8, 0x92, 0x62, 0xe4, 0x6e, 0xa7, 0x90, 0x34, 0x12, 0xb9, 0xd3, 0x1c, 0x76, 0xa0, 0x1a, 0x63, 0x76, 0x8f, 0xe0, 0xde, 0x70, 0x60, 0xea, 0x19, 0xa4, 0x43, 0x39,
0x7f, 0xe4, 0x60, 0x5d, 0x6e, 0x30, 0x44, 0x67, 0x50, 0x4a, 0xbd, 0x47, 0xd0, 0xc1, 0x83, 0xef, 0x06, 0x4d, 0x8c, 0x7b, 0x58, 0xcf, 0x8a, 0xeb, 0x2e, 0x46, 0xee, 0x76, 0x21, 0x49, 0x93, 0x92,
0x94, 0xaa, 0xb1, 0xba, 0xf5, 0x9f, 0x46, 0xaf, 0x34, 0x74, 0x0e, 0xe5, 0xf4, 0x8b, 0x03, 0xa5, 0x3b, 0xfd, 0x5b, 0x0e, 0x36, 0xe5, 0x02, 0x43, 0x74, 0x06, 0xa5, 0xd4, 0x5b, 0x07, 0x1d, 0x7c,
0xdb, 0xc3, 0x15, 0x4f, 0x91, 0x07, 0xd7, 0x7a, 0x0b, 0xba, 0x15, 0x71, 0x77, 0x2c, 0xda, 0xc1, 0xf6, 0x0d, 0x54, 0xaf, 0xad, 0x7f, 0x56, 0xcc, 0xa2, 0x57, 0x1a, 0x3a, 0x87, 0x72, 0xfa, 0x35,
0xb8, 0x41, 0x47, 0xd5, 0x94, 0xfe, 0x52, 0xd7, 0x5f, 0xdd, 0x5b, 0x29, 0x8b, 0x23, 0xd4, 0x52, 0x83, 0xd2, 0xad, 0xe7, 0x9a, 0x67, 0xce, 0x67, 0x75, 0xbd, 0x05, 0xdd, 0x8c, 0xb8, 0xe3, 0x89,
0x47, 0x8c, 0x5b, 0xe4, 0x3b, 0x47, 0x5c, 0xec, 0xcb, 0xab, 0x5f, 0xdc, 0x27, 0x8e, 0x57, 0x1b, 0x56, 0x33, 0x6e, 0xfe, 0x51, 0x3d, 0xc5, 0x5f, 0x79, 0x51, 0xd4, 0xf7, 0xd7, 0xca, 0x62, 0x0f,
0xc2, 0xf6, 0x0a, 0x0e, 0x45, 0xbf, 0x4a, 0xef, 0xe0, 0x5e, 0x06, 0xae, 0x3e, 0xff, 0x25, 0xb5, 0x75, 0xd4, 0x16, 0xe3, 0xf6, 0xfb, 0xce, 0x16, 0x97, 0x7b, 0xfe, 0xfa, 0x97, 0xf7, 0x89, 0x63,
0xb9, 0x95, 0x15, 0x64, 0xbb, 0x60, 0xe5, 0x7e, 0xaa, 0x5e, 0xb0, 0xf2, 0x10, 0x67, 0xff, 0x04, 0x6d, 0x63, 0xd8, 0x59, 0x53, 0x9f, 0xd1, 0xff, 0xa5, 0x57, 0x70, 0x6f, 0x75, 0xaf, 0x3f, 0xff,
0xfa, 0x72, 0xa1, 0x23, 0x73, 0x79, 0xee, 0x5d, 0xd2, 0xa9, 0x3e, 0x7d, 0x50, 0x27, 0x5e, 0xdc, 0x35, 0xda, 0xc2, 0xca, 0x9a, 0x42, 0xbe, 0x64, 0xe5, 0xfe, 0x6b, 0x60, 0xc9, 0xca, 0xe7, 0xee,
0x06, 0x98, 0x97, 0x0b, 0xda, 0x4f, 0x4d, 0xb9, 0x53, 0xee, 0xd5, 0x83, 0x7b, 0xa4, 0x6a, 0xa9, 0x83, 0x9f, 0x41, 0x5f, 0x4d, 0x74, 0x64, 0xac, 0xce, 0xbd, 0x5b, 0x74, 0xea, 0x4f, 0x3f, 0xcb,
0x37, 0xbf, 0xfe, 0xfd, 0xc9, 0xb5, 0xcb, 0x47, 0xd3, 0xcb, 0xe3, 0x41, 0x30, 0x3e, 0xf1, 0x44, 0x89, 0x95, 0x5b, 0x00, 0x8b, 0x74, 0x41, 0x8f, 0x53, 0x53, 0xee, 0xa4, 0x7b, 0xfd, 0xe0, 0x1e,
0x53, 0xed, 0xbb, 0xfe, 0xb5, 0xcf, 0xf8, 0x1f, 0x82, 0xf0, 0xe6, 0xc4, 0xf3, 0x87, 0x27, 0xb2, 0xa9, 0x52, 0xf5, 0xe6, 0xff, 0x7f, 0x7f, 0x72, 0xed, 0xf0, 0xc9, 0xec, 0xf2, 0x78, 0x14, 0x78,
0xea, 0x4e, 0x66, 0xab, 0x5c, 0xae, 0xcb, 0xff, 0x5c, 0x7e, 0xf3, 0xbf, 0x00, 0x00, 0x00, 0xff, 0x27, 0xae, 0x68, 0xd8, 0x7d, 0xc7, 0xbf, 0xf6, 0x19, 0xff, 0x43, 0x10, 0xde, 0x9c, 0xb8, 0xfe,
0xff, 0x78, 0xac, 0xbb, 0x04, 0xa3, 0x11, 0x00, 0x00, 0xf8, 0x44, 0x66, 0xdd, 0xc9, 0x5c, 0xcb, 0xe5, 0xa6, 0xfc, 0x3f, 0xe7, 0x37, 0xff, 0x0d, 0x00,
0x00, 0xff, 0xff, 0x7d, 0xd4, 0x80, 0xa8, 0xff, 0x11, 0x00, 0x00,
} }
// Reference imports to suppress errors if they are not otherwise used. // Reference imports to suppress errors if they are not otherwise used.

@ -391,14 +391,31 @@ message PairHistory {
} }
message PairData { message PairData {
/// Time stamp of last result. /// Time of last failure.
int64 timestamp = 1 [json_name = "timestamp"]; int64 fail_time = 1 [json_name = "fail_time"];
/// Minimum penalization amount (only applies to failed attempts). /**
int64 min_penalize_amt_sat = 2 [json_name = "min_penalize_amt_sat"]; Lowest amount that failed to forward rounded to whole sats. This may be
set to zero if the failure is independent of amount.
*/
int64 fail_amt_sat = 2 [json_name = "fail_amt_sat"];
/// Whether the last payment attempt through this pair was successful. /**
bool last_attempt_successful = 3 [json_name = "last_attempt_successful"]; Lowest amount that failed to forward in millisats. This may be
set to zero if the failure is independent of amount.
*/
int64 fail_amt_msat = 4 [json_name = "fail_amt_msat"];
reserved 3;
/// Time of last success.
int64 success_time = 5 [json_name = "success_time"];
/// Highest amount that we could successfully forward rounded to whole sats.
int64 success_amt_sat = 6 [json_name = "success_amt_sat"];
/// Highest amount that we could successfully forward in millisats.
int64 success_amt_msat = 7 [json_name = "success_amt_msat"];
} }
message QueryProbabilityRequest{ message QueryProbabilityRequest{

@ -494,14 +494,18 @@ func (s *Server) QueryMissionControl(ctx context.Context,
// toRPCPairData marshalls mission control pair data to the rpc struct. // toRPCPairData marshalls mission control pair data to the rpc struct.
func toRPCPairData(data *routing.TimedPairResult) *PairData { func toRPCPairData(data *routing.TimedPairResult) *PairData {
rpcData := PairData{ rpcData := PairData{
MinPenalizeAmtSat: int64( FailAmtSat: int64(data.FailAmt.ToSatoshis()),
data.MinPenalizeAmt.ToSatoshis(), FailAmtMsat: int64(data.FailAmt),
), SuccessAmtSat: int64(data.SuccessAmt.ToSatoshis()),
LastAttemptSuccessful: data.Success, SuccessAmtMsat: int64(data.SuccessAmt),
} }
if !data.Timestamp.IsZero() { if !data.FailTime.IsZero() {
rpcData.Timestamp = data.Timestamp.Unix() rpcData.FailTime = data.FailTime.Unix()
}
if !data.SuccessTime.IsZero() {
rpcData.SuccessTime = data.SuccessTime.Unix()
} }
return &rpcData return &rpcData

@ -125,27 +125,22 @@ type MissionControlConfig struct {
// TimedPairResult describes a timestamped pair result. // TimedPairResult describes a timestamped pair result.
type TimedPairResult struct { type TimedPairResult struct {
// timestamp is the time when this result was obtained. // FailTime is the time of the last failure.
Timestamp time.Time FailTime time.Time
// minPenalizeAmt is the minimum amount for which a penalty should be // FailAmt is the amount of the last failure. This amount may be pushed
// applied based on this result. Only applies to fail results. // up if a later success is higher than the last failed amount.
MinPenalizeAmt lnwire.MilliSatoshi FailAmt lnwire.MilliSatoshi
// success indicates whether the payment attempt was successful through // SuccessTime is the time of the last success.
// this pair. SuccessTime time.Time
Success bool
}
// newTimedPairResult wraps a pair result with a timestamp. // SuccessAmt is the highest amount that successfully forwarded. This
func newTimedPairResult(timestamp time.Time, // isn't necessarily the last success amount. The value of this field
result pairResult) TimedPairResult { // may also be pushed down if a later failure is lower than the highest
// success amount. Because of this, SuccessAmt may not match
return TimedPairResult{ // SuccessTime.
Timestamp: timestamp, SuccessAmt lnwire.MilliSatoshi
MinPenalizeAmt: result.minPenalizeAmt,
Success: result.success,
}
} }
// MissionControlSnapshot contains a snapshot of the current state of mission // MissionControlSnapshot contains a snapshot of the current state of mission
@ -273,8 +268,8 @@ func (m *MissionControl) GetProbability(fromNode, toNode route.Vertex,
} }
// setLastPairResult stores a result for a node pair. // setLastPairResult stores a result for a node pair.
func (m *MissionControl) setLastPairResult(fromNode, func (m *MissionControl) setLastPairResult(fromNode, toNode route.Vertex,
toNode route.Vertex, result TimedPairResult) { timestamp time.Time, result *pairResult) {
nodePairs, ok := m.lastPairResult[fromNode] nodePairs, ok := m.lastPairResult[fromNode]
if !ok { if !ok {
@ -282,7 +277,60 @@ func (m *MissionControl) setLastPairResult(fromNode,
m.lastPairResult[fromNode] = nodePairs m.lastPairResult[fromNode] = nodePairs
} }
nodePairs[toNode] = result current := nodePairs[toNode]
// Apply the new result to the existing data for this pair. If there is
// no existing data, apply it to the default values for TimedPairResult.
if result.success {
successAmt := result.amt
current.SuccessTime = timestamp
// Only update the success amount if this amount is higher. This
// prevents the success range from shrinking when there is no
// reason to do so. For example: small amount probes shouldn't
// affect a previous success for a much larger amount.
if successAmt > current.SuccessAmt {
current.SuccessAmt = successAmt
}
// If the success amount goes into the failure range, move the
// failure range up. Future attempts up to the success amount
// are likely to succeed. We don't want to clear the failure
// completely, because we haven't learnt much for amounts above
// the current success amount.
if !current.FailTime.IsZero() && successAmt >= current.FailAmt {
current.FailAmt = successAmt + 1
}
} else {
// For failures we always want to update both the amount and the
// time. Those need to relate to the same result, because the
// time is used to gradually diminish the penality for that
// specific result. Updating the timestamp but not the amount
// could cause a failure for a lower amount (a more severe
// condition) to be revived as if it just happened.
failAmt := result.amt
current.FailTime = timestamp
current.FailAmt = failAmt
switch {
// The failure amount is set to zero when the failure is
// amount-independent, meaning that the attempt would have
// failed regardless of the amount. This should also reset the
// success amount to zero.
case failAmt == 0:
current.SuccessAmt = 0
// If the failure range goes into the success range, move the
// success range down.
case failAmt <= current.SuccessAmt:
current.SuccessAmt = failAmt - 1
}
}
log.Debugf("Setting %v->%v range to [%v-%v]",
fromNode, toNode, current.SuccessAmt, current.FailAmt)
nodePairs[toNode] = current
} }
// setAllFail stores a fail result for all known connection of the given node. // setAllFail stores a fail result for all known connection of the given node.
@ -295,9 +343,9 @@ func (m *MissionControl) setAllFail(fromNode route.Vertex,
} }
for connection := range nodePairs { for connection := range nodePairs {
nodePairs[connection] = newTimedPairResult( nodePairs[connection] = TimedPairResult{
timestamp, failPairResult(0), FailTime: timestamp,
) }
} }
} }
@ -492,21 +540,19 @@ func (m *MissionControl) applyPaymentResult(
} }
for pair, pairResult := range i.pairResults { for pair, pairResult := range i.pairResults {
pairResult := pairResult
if pairResult.success { if pairResult.success {
log.Debugf("Reporting pair success to Mission "+ log.Debugf("Reporting pair success to Mission "+
"Control: pair=%v", pair) "Control: pair=%v", pair)
} else { } else {
log.Debugf("Reporting pair failure to Mission "+ log.Debugf("Reporting pair failure to Mission "+
"Control: pair=%v, minPenalizeAmt=%v", "Control: pair=%v, amt=%v",
pair, pairResult.minPenalizeAmt) pair, pairResult.amt)
} }
m.setLastPairResult( m.setLastPairResult(
pair.From, pair.To, pair.From, pair.To, result.timeReply, &pairResult,
newTimedPairResult(
result.timeReply,
pairResult,
),
) )
} }

@ -204,12 +204,12 @@ func TestMissionControlChannelUpdate(t *testing.T) {
ctx.reportFailure( ctx.reportFailure(
0, lnwire.NewFeeInsufficient(0, lnwire.ChannelUpdate{}), 0, lnwire.NewFeeInsufficient(0, lnwire.ChannelUpdate{}),
) )
ctx.expectP(0, testAprioriHopProbability) ctx.expectP(100, testAprioriHopProbability)
// Report another failure for the same channel. We expect it to be // Report another failure for the same channel. We expect it to be
// pruned. // pruned.
ctx.reportFailure( ctx.reportFailure(
0, lnwire.NewFeeInsufficient(0, lnwire.ChannelUpdate{}), 0, lnwire.NewFeeInsufficient(0, lnwire.ChannelUpdate{}),
) )
ctx.expectP(0, 0) ctx.expectP(100, 0)
} }

@ -80,19 +80,20 @@ func (p *probabilityEstimator) getNodeProbability(now time.Time,
totalWeight := aprioriFactor totalWeight := aprioriFactor
for _, result := range results { for _, result := range results {
age := now.Sub(result.Timestamp)
switch { switch {
// Weigh success with a constant high weight of 1. There is no // Weigh success with a constant high weight of 1. There is no
// decay. // decay. Amt is never zero, so this clause is never executed
case result.Success: // when result.SuccessAmt is zero.
case amt <= result.SuccessAmt:
totalWeight++ totalWeight++
probabilitiesTotal += p.prevSuccessProbability probabilitiesTotal += p.prevSuccessProbability
// Weigh failures in accordance with their age. The base // Weigh failures in accordance with their age. The base
// probability of a failure is considered zero, so nothing needs // probability of a failure is considered zero, so nothing needs
// to be added to probabilitiesTotal. // to be added to probabilitiesTotal.
case amt >= result.MinPenalizeAmt: case !result.FailTime.IsZero() && amt >= result.FailAmt:
age := now.Sub(result.FailTime)
totalWeight += p.getWeight(age) totalWeight += p.getWeight(age)
} }
} }
@ -155,9 +156,10 @@ func (p *probabilityEstimator) calculateProbability(
return nodeProbability return nodeProbability
} }
// For successes, we have a fixed (high) probability. Those pairs // For successes, we have a fixed (high) probability. Those pairs will
// will be assumed good until proven otherwise. // be assumed good until proven otherwise. Amt is never zero, so this
if lastPairResult.Success { // clause is never executed when lastPairResult.SuccessAmt is zero.
if amt <= lastPairResult.SuccessAmt {
return p.prevSuccessProbability return p.prevSuccessProbability
} }
@ -166,11 +168,11 @@ func (p *probabilityEstimator) calculateProbability(
// penalization. If the current amount is smaller than the amount that // penalization. If the current amount is smaller than the amount that
// previously triggered a failure, we act as if this is an untried // previously triggered a failure, we act as if this is an untried
// channel. // channel.
if amt < lastPairResult.MinPenalizeAmt { if lastPairResult.FailTime.IsZero() || amt < lastPairResult.FailAmt {
return nodeProbability return nodeProbability
} }
timeSinceLastFailure := now.Sub(lastPairResult.Timestamp) timeSinceLastFailure := now.Sub(lastPairResult.FailTime)
// Calculate success probability based on the weight of the last // Calculate success probability based on the weight of the last
// failure. When the failure is fresh, its weight is 1 and we'll return // failure. When the failure is fresh, its weight is 1 and we'll return

@ -84,10 +84,9 @@ func TestProbabilityEstimatorOneSuccess(t *testing.T) {
ctx := newEstimatorTestContext(t) ctx := newEstimatorTestContext(t)
ctx.results = map[int]TimedPairResult{ ctx.results = map[int]TimedPairResult{
node1: newTimedPairResult( node1: {
testTime.Add(-time.Hour), SuccessAmt: lnwire.MilliSatoshi(1000),
successPairResult(), },
),
} }
// Because of the previous success, this channel keep reporting a high // Because of the previous success, this channel keep reporting a high
@ -108,10 +107,10 @@ func TestProbabilityEstimatorOneFailure(t *testing.T) {
ctx := newEstimatorTestContext(t) ctx := newEstimatorTestContext(t)
ctx.results = map[int]TimedPairResult{ ctx.results = map[int]TimedPairResult{
node1: newTimedPairResult( node1: {
testTime.Add(-time.Hour), FailTime: testTime.Add(-time.Hour),
failPairResult(0), FailAmt: lnwire.MilliSatoshi(50),
), },
} }
// For an untried node, we expected the node probability. The weight for // For an untried node, we expected the node probability. The weight for
@ -131,18 +130,17 @@ func TestProbabilityEstimatorMix(t *testing.T) {
ctx := newEstimatorTestContext(t) ctx := newEstimatorTestContext(t)
ctx.results = map[int]TimedPairResult{ ctx.results = map[int]TimedPairResult{
node1: newTimedPairResult( node1: {
testTime.Add(-time.Hour), SuccessAmt: lnwire.MilliSatoshi(1000),
successPairResult(), },
), node2: {
node2: newTimedPairResult( FailTime: testTime.Add(-2 * time.Hour),
testTime.Add(-2*time.Hour), FailAmt: lnwire.MilliSatoshi(50),
failPairResult(0), },
), node3: {
node3: newTimedPairResult( FailTime: testTime.Add(-3 * time.Hour),
testTime.Add(-3*time.Hour), FailAmt: lnwire.MilliSatoshi(50),
failPairResult(0), },
),
} }
// We expect the probability for a previously successful channel to // We expect the probability for a previously successful channel to

@ -17,9 +17,9 @@ var (
// pairResult contains the result of the interpretation of a payment attempt for // pairResult contains the result of the interpretation of a payment attempt for
// a specific node pair. // a specific node pair.
type pairResult struct { type pairResult struct {
// minPenalizeAmt is the minimum amount for which a penalty should be // amt is the amount that was forwarded for this pair. Can be set to
// applied based on this result. Only applies to fail results. // zero for failures that are amount independent.
minPenalizeAmt lnwire.MilliSatoshi amt lnwire.MilliSatoshi
// success indicates whether the payment attempt was successful through // success indicates whether the payment attempt was successful through
// this pair. // this pair.
@ -29,24 +29,28 @@ type pairResult struct {
// failPairResult creates a new result struct for a failure. // failPairResult creates a new result struct for a failure.
func failPairResult(minPenalizeAmt lnwire.MilliSatoshi) pairResult { func failPairResult(minPenalizeAmt lnwire.MilliSatoshi) pairResult {
return pairResult{ return pairResult{
minPenalizeAmt: minPenalizeAmt, amt: minPenalizeAmt,
} }
} }
// successPairResult creates a new result struct for a success. // newSuccessPairResult creates a new result struct for a success.
func successPairResult() pairResult { func successPairResult(successAmt lnwire.MilliSatoshi) pairResult {
return pairResult{ return pairResult{
success: true, success: true,
amt: successAmt,
} }
} }
// String returns the human-readable representation of a pair result. // String returns the human-readable representation of a pair result.
func (p pairResult) String() string { func (p pairResult) String() string {
var resultType string
if p.success { if p.success {
return "success" resultType = "success"
} else {
resultType = "failed"
} }
return fmt.Sprintf("failed (minPenalizeAmt=%v)", p.minPenalizeAmt) return fmt.Sprintf("%v (amt=%v)", resultType, p.amt)
} }
// interpretedResult contains the result of the interpretation of a payment // interpretedResult contains the result of the interpretation of a payment
@ -458,9 +462,9 @@ func (i *interpretedResult) successPairRange(
rt *route.Route, fromIdx, toIdx int) { rt *route.Route, fromIdx, toIdx int) {
for idx := fromIdx; idx <= toIdx; idx++ { for idx := fromIdx; idx <= toIdx; idx++ {
pair, _ := getPair(rt, idx) pair, amt := getPair(rt, idx)
i.pairResults[pair] = successPairResult() i.pairResults[pair] = successPairResult(amt)
} }
} }

@ -74,7 +74,7 @@ var resultTestCases = []resultTestCase{
expectedResult: &interpretedResult{ expectedResult: &interpretedResult{
pairResults: map[DirectedNodePair]pairResult{ pairResults: map[DirectedNodePair]pairResult{
getTestPair(0, 1): successPairResult(), getTestPair(0, 1): successPairResult(100),
getTestPair(1, 2): failPairResult(99), getTestPair(1, 2): failPairResult(99),
}, },
}, },
@ -109,8 +109,8 @@ var resultTestCases = []resultTestCase{
expectedResult: &interpretedResult{ expectedResult: &interpretedResult{
pairResults: map[DirectedNodePair]pairResult{ pairResults: map[DirectedNodePair]pairResult{
getTestPair(0, 1): successPairResult(), getTestPair(0, 1): successPairResult(100),
getTestPair(1, 2): successPairResult(), getTestPair(1, 2): successPairResult(99),
}, },
finalFailureReason: &reasonIncorrectDetails, finalFailureReason: &reasonIncorrectDetails,
}, },
@ -124,7 +124,7 @@ var resultTestCases = []resultTestCase{
expectedResult: &interpretedResult{ expectedResult: &interpretedResult{
pairResults: map[DirectedNodePair]pairResult{ pairResults: map[DirectedNodePair]pairResult{
getTestPair(0, 1): successPairResult(), getTestPair(0, 1): successPairResult(100),
}, },
}, },
}, },
@ -137,8 +137,8 @@ var resultTestCases = []resultTestCase{
expectedResult: &interpretedResult{ expectedResult: &interpretedResult{
pairResults: map[DirectedNodePair]pairResult{ pairResults: map[DirectedNodePair]pairResult{
getTestPair(0, 1): successPairResult(), getTestPair(0, 1): successPairResult(100),
getTestPair(1, 2): successPairResult(), getTestPair(1, 2): successPairResult(99),
}, },
}, },
}, },
@ -190,6 +190,7 @@ var resultTestCases = []resultTestCase{
pairResults: map[DirectedNodePair]pairResult{ pairResults: map[DirectedNodePair]pairResult{
getTestPair(0, 1): { getTestPair(0, 1): {
success: true, success: true,
amt: 100,
}, },
getTestPair(1, 2): {}, getTestPair(1, 2): {},
getTestPair(2, 1): {}, getTestPair(2, 1): {},
@ -211,12 +212,15 @@ var resultTestCases = []resultTestCase{
pairResults: map[DirectedNodePair]pairResult{ pairResults: map[DirectedNodePair]pairResult{
getTestPair(0, 1): { getTestPair(0, 1): {
success: true, success: true,
amt: 100,
}, },
getTestPair(1, 2): { getTestPair(1, 2): {
success: true, success: true,
amt: 99,
}, },
getTestPair(2, 3): { getTestPair(2, 3): {
success: true, success: true,
amt: 97,
}, },
getTestPair(4, 3): {}, getTestPair(4, 3): {},
}, },
@ -238,9 +242,11 @@ var resultTestCases = []resultTestCase{
pairResults: map[DirectedNodePair]pairResult{ pairResults: map[DirectedNodePair]pairResult{
getTestPair(0, 1): { getTestPair(0, 1): {
success: true, success: true,
amt: 100,
}, },
getTestPair(1, 2): { getTestPair(1, 2): {
success: true, success: true,
amt: 99,
}, },
getTestPair(3, 2): {}, getTestPair(3, 2): {},
getTestPair(3, 4): {}, getTestPair(3, 4): {},