From dd072304b0d35111205710dd075fdcfad8e893e2 Mon Sep 17 00:00:00 2001 From: "Johan T. Halseth" Date: Mon, 18 Mar 2019 13:28:07 +0100 Subject: [PATCH 1/4] autopilot: move queryHeuristic out of agent This commit moves the logic querying the available heuristics out of the autopilot agent and into the autopilot manager. This lets us query the heuristic without the autopilot agent being active. If called without the agent being active, the current set of channels will be considered by the heuristics. If the agent is active also the pending channels will be considered. --- autopilot/agent.go | 52 ------------------------------ autopilot/manager.go | 75 +++++++++++++++++++++++++++++++++++++++----- 2 files changed, 68 insertions(+), 59 deletions(-) diff --git a/autopilot/agent.go b/autopilot/agent.go index 2f257173..9610427c 100644 --- a/autopilot/agent.go +++ b/autopilot/agent.go @@ -819,55 +819,3 @@ func (a *Agent) executeDirective(directive AttachmentDirective) { // directive in goroutine? a.OnChannelPendingOpen() } - -// HeuristicScores is an alias for a map that maps heuristic names to a map of -// scores for pubkeys. -type HeuristicScores map[string]map[NodeID]float64 - -// queryHeuristics gets node scores from all available simple heuristics, and -// the agent's current active heuristic. -func (a *Agent) queryHeuristics(nodes map[NodeID]struct{}) ( - HeuristicScores, error) { - - // Get the agent's current channel state. - a.chanStateMtx.Lock() - a.pendingMtx.Lock() - totalChans := mergeChanState(a.pendingOpens, a.chanState) - a.pendingMtx.Unlock() - a.chanStateMtx.Unlock() - - // As channel size we'll use the maximum size. - chanSize := a.cfg.Constraints.MaxChanSize() - - // We'll start by getting the scores from each available sub-heuristic, - // in addition the active agent heuristic. - report := make(HeuristicScores) - for _, h := range append(availableHeuristics, a.cfg.Heuristic) { - name := h.Name() - - // If the active agent heuristic is among the simple heuristics - // it might get queried more than once. As an optimization - // we'll just skip it the second time. - if _, ok := report[name]; ok { - continue - } - - s, err := h.NodeScores( - a.cfg.Graph, totalChans, chanSize, nodes, - ) - if err != nil { - return nil, fmt.Errorf("unable to get sub score: %v", err) - } - - log.Debugf("Heuristic \"%v\" scored %d nodes", name, len(s)) - - scores := make(map[NodeID]float64) - for nID, score := range s { - scores[nID] = score.Score - } - - report[name] = scores - } - - return report, nil -} diff --git a/autopilot/manager.go b/autopilot/manager.go index 283aab02..17ce145c 100644 --- a/autopilot/manager.go +++ b/autopilot/manager.go @@ -269,23 +269,84 @@ func (m *Manager) StopAgent() error { return nil } -// QueryHeuristics queries the active autopilot agent for node scores. +// QueryHeuristics queries the available autopilot heuristics for node scores. func (m *Manager) QueryHeuristics(nodes []NodeID) (HeuristicScores, error) { m.Lock() defer m.Unlock() - // Not active, so we can return early. - if m.pilot == nil { - return nil, fmt.Errorf("autopilot not active") - } - n := make(map[NodeID]struct{}) for _, node := range nodes { n[node] = struct{}{} } log.Debugf("Querying heuristics for %d nodes", len(n)) - return m.pilot.queryHeuristics(n) + return m.queryHeuristics(n) +} + +// HeuristicScores is an alias for a map that maps heuristic names to a map of +// scores for pubkeys. +type HeuristicScores map[string]map[NodeID]float64 + +// queryHeuristics gets node scores from all available simple heuristics, and +// the agent's current active heuristic. +// +// NOTE: Must be called with the manager's lock. +func (m *Manager) queryHeuristics(nodes map[NodeID]struct{}) ( + HeuristicScores, error) { + + // Fetch the current set of channels. + totalChans, err := m.cfg.ChannelState() + if err != nil { + return nil, err + } + + // If the agent is active, we can merge the channel state with the + // channels pending open. + if m.pilot != nil { + m.pilot.chanStateMtx.Lock() + m.pilot.pendingMtx.Lock() + totalChans = mergeChanState( + m.pilot.pendingOpens, m.pilot.chanState, + ) + m.pilot.pendingMtx.Unlock() + m.pilot.chanStateMtx.Unlock() + } + + // As channel size we'll use the maximum size. + chanSize := m.cfg.PilotCfg.Constraints.MaxChanSize() + + // We'll start by getting the scores from each available sub-heuristic, + // in addition the current agent heuristic. + report := make(HeuristicScores) + for _, h := range append(availableHeuristics, m.cfg.PilotCfg.Heuristic) { + name := h.Name() + + // If the agent heuristic is among the simple heuristics it + // might get queried more than once. As an optimization we'll + // just skip it the second time. + if _, ok := report[name]; ok { + continue + } + + s, err := h.NodeScores( + m.cfg.PilotCfg.Graph, totalChans, chanSize, nodes, + ) + if err != nil { + return nil, fmt.Errorf("unable to get sub score: %v", + err) + } + + log.Debugf("Heuristic \"%v\" scored %d nodes", name, len(s)) + + scores := make(map[NodeID]float64) + for nID, score := range s { + scores[nID] = score.Score + } + + report[name] = scores + } + + return report, nil } // SetNodeScores is used to set the scores of the given heuristic, if it is From c7ab6f360323ee0222eb66382c5b2dcefb675a57 Mon Sep 17 00:00:00 2001 From: "Johan T. Halseth" Date: Mon, 18 Mar 2019 14:36:00 +0100 Subject: [PATCH 2/4] lnrpc/autopilotrpc: add ignore_local_state flag --- lnrpc/autopilotrpc/autopilot.pb.go | 92 +++++++++++++++++------------- lnrpc/autopilotrpc/autopilot.proto | 3 + 2 files changed, 54 insertions(+), 41 deletions(-) diff --git a/lnrpc/autopilotrpc/autopilot.pb.go b/lnrpc/autopilotrpc/autopilot.pb.go index c9e6da01..50afb82d 100644 --- a/lnrpc/autopilotrpc/autopilot.pb.go +++ b/lnrpc/autopilotrpc/autopilot.pb.go @@ -33,7 +33,7 @@ func (m *StatusRequest) Reset() { *m = StatusRequest{} } func (m *StatusRequest) String() string { return proto.CompactTextString(m) } func (*StatusRequest) ProtoMessage() {} func (*StatusRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_autopilot_569ccc5858bc499b, []int{0} + return fileDescriptor_autopilot_1f7ac28ef56bb20c, []int{0} } func (m *StatusRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_StatusRequest.Unmarshal(m, b) @@ -65,7 +65,7 @@ func (m *StatusResponse) Reset() { *m = StatusResponse{} } func (m *StatusResponse) String() string { return proto.CompactTextString(m) } func (*StatusResponse) ProtoMessage() {} func (*StatusResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_autopilot_569ccc5858bc499b, []int{1} + return fileDescriptor_autopilot_1f7ac28ef56bb20c, []int{1} } func (m *StatusResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_StatusResponse.Unmarshal(m, b) @@ -104,7 +104,7 @@ func (m *ModifyStatusRequest) Reset() { *m = ModifyStatusRequest{} } func (m *ModifyStatusRequest) String() string { return proto.CompactTextString(m) } func (*ModifyStatusRequest) ProtoMessage() {} func (*ModifyStatusRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_autopilot_569ccc5858bc499b, []int{2} + return fileDescriptor_autopilot_1f7ac28ef56bb20c, []int{2} } func (m *ModifyStatusRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ModifyStatusRequest.Unmarshal(m, b) @@ -141,7 +141,7 @@ func (m *ModifyStatusResponse) Reset() { *m = ModifyStatusResponse{} } func (m *ModifyStatusResponse) String() string { return proto.CompactTextString(m) } func (*ModifyStatusResponse) ProtoMessage() {} func (*ModifyStatusResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_autopilot_569ccc5858bc499b, []int{3} + return fileDescriptor_autopilot_1f7ac28ef56bb20c, []int{3} } func (m *ModifyStatusResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ModifyStatusResponse.Unmarshal(m, b) @@ -162,7 +162,9 @@ func (m *ModifyStatusResponse) XXX_DiscardUnknown() { var xxx_messageInfo_ModifyStatusResponse proto.InternalMessageInfo type QueryScoresRequest struct { - Pubkeys []string `protobuf:"bytes,1,rep,name=pubkeys,proto3" json:"pubkeys,omitempty"` + Pubkeys []string `protobuf:"bytes,1,rep,name=pubkeys,proto3" json:"pubkeys,omitempty"` + // / If set, we will ignore the local channel state when calculating scores. + IgnoreLocalState bool `protobuf:"varint,2,opt,name=ignore_local_state,json=no_state,proto3" json:"ignore_local_state,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -172,7 +174,7 @@ func (m *QueryScoresRequest) Reset() { *m = QueryScoresRequest{} } func (m *QueryScoresRequest) String() string { return proto.CompactTextString(m) } func (*QueryScoresRequest) ProtoMessage() {} func (*QueryScoresRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_autopilot_569ccc5858bc499b, []int{4} + return fileDescriptor_autopilot_1f7ac28ef56bb20c, []int{4} } func (m *QueryScoresRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_QueryScoresRequest.Unmarshal(m, b) @@ -199,6 +201,13 @@ func (m *QueryScoresRequest) GetPubkeys() []string { return nil } +func (m *QueryScoresRequest) GetIgnoreLocalState() bool { + if m != nil { + return m.IgnoreLocalState + } + return false +} + type QueryScoresResponse struct { Results []*QueryScoresResponse_HeuristicResult `protobuf:"bytes,1,rep,name=results,proto3" json:"results,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` @@ -210,7 +219,7 @@ func (m *QueryScoresResponse) Reset() { *m = QueryScoresResponse{} } func (m *QueryScoresResponse) String() string { return proto.CompactTextString(m) } func (*QueryScoresResponse) ProtoMessage() {} func (*QueryScoresResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_autopilot_569ccc5858bc499b, []int{5} + return fileDescriptor_autopilot_1f7ac28ef56bb20c, []int{5} } func (m *QueryScoresResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_QueryScoresResponse.Unmarshal(m, b) @@ -249,7 +258,7 @@ func (m *QueryScoresResponse_HeuristicResult) Reset() { *m = QueryScores func (m *QueryScoresResponse_HeuristicResult) String() string { return proto.CompactTextString(m) } func (*QueryScoresResponse_HeuristicResult) ProtoMessage() {} func (*QueryScoresResponse_HeuristicResult) Descriptor() ([]byte, []int) { - return fileDescriptor_autopilot_569ccc5858bc499b, []int{5, 0} + return fileDescriptor_autopilot_1f7ac28ef56bb20c, []int{5, 0} } func (m *QueryScoresResponse_HeuristicResult) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_QueryScoresResponse_HeuristicResult.Unmarshal(m, b) @@ -299,7 +308,7 @@ func (m *SetScoresRequest) Reset() { *m = SetScoresRequest{} } func (m *SetScoresRequest) String() string { return proto.CompactTextString(m) } func (*SetScoresRequest) ProtoMessage() {} func (*SetScoresRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_autopilot_569ccc5858bc499b, []int{6} + return fileDescriptor_autopilot_1f7ac28ef56bb20c, []int{6} } func (m *SetScoresRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SetScoresRequest.Unmarshal(m, b) @@ -343,7 +352,7 @@ func (m *SetScoresResponse) Reset() { *m = SetScoresResponse{} } func (m *SetScoresResponse) String() string { return proto.CompactTextString(m) } func (*SetScoresResponse) ProtoMessage() {} func (*SetScoresResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_autopilot_569ccc5858bc499b, []int{7} + return fileDescriptor_autopilot_1f7ac28ef56bb20c, []int{7} } func (m *SetScoresResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SetScoresResponse.Unmarshal(m, b) @@ -573,37 +582,38 @@ var _Autopilot_serviceDesc = grpc.ServiceDesc{ } func init() { - proto.RegisterFile("autopilotrpc/autopilot.proto", fileDescriptor_autopilot_569ccc5858bc499b) + proto.RegisterFile("autopilotrpc/autopilot.proto", fileDescriptor_autopilot_1f7ac28ef56bb20c) } -var fileDescriptor_autopilot_569ccc5858bc499b = []byte{ - // 439 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x94, 0x4d, 0x8b, 0xd3, 0x40, - 0x18, 0xc7, 0x99, 0x2c, 0x76, 0xcd, 0xd3, 0xd5, 0x5d, 0xa7, 0xcb, 0x12, 0x62, 0xd1, 0xee, 0x9c, - 0x8a, 0x60, 0x8a, 0xd5, 0x83, 0x0a, 0x1e, 0x5c, 0x11, 0x04, 0xf5, 0xe0, 0x94, 0xbd, 0x78, 0x4b, - 0xb2, 0x63, 0x3b, 0x34, 0xce, 0xc4, 0x79, 0x59, 0xc9, 0x17, 0xf2, 0xea, 0x67, 0xf0, 0xe8, 0xb7, - 0x92, 0x66, 0x92, 0x98, 0x84, 0x1a, 0x11, 0xbc, 0xe5, 0x79, 0xfb, 0x3d, 0x2f, 0xf9, 0x33, 0x30, - 0x8d, 0xad, 0x91, 0x39, 0xcf, 0xa4, 0x51, 0x79, 0xba, 0x68, 0x8c, 0x28, 0x57, 0xd2, 0x48, 0x7c, - 0xd4, 0x8e, 0x92, 0x63, 0xb8, 0xb5, 0x32, 0xb1, 0xb1, 0x9a, 0xb2, 0x2f, 0x96, 0x69, 0x43, 0xe6, - 0x70, 0xbb, 0x76, 0xe8, 0x5c, 0x0a, 0xcd, 0xf0, 0x19, 0x8c, 0xe2, 0xd4, 0xf0, 0x6b, 0x16, 0xa0, - 0x19, 0x9a, 0xdf, 0xa4, 0x95, 0x45, 0x1e, 0xc2, 0xe4, 0xbd, 0xbc, 0xe2, 0x9f, 0x8a, 0x0e, 0x60, - 0x97, 0xce, 0x44, 0x9c, 0x64, 0x4d, 0xba, 0xb3, 0xc8, 0x19, 0x9c, 0x76, 0xd3, 0x1d, 0x9e, 0x44, - 0x80, 0x3f, 0x58, 0xa6, 0x8a, 0x55, 0x2a, 0x15, 0x6b, 0x28, 0x01, 0x1c, 0xe6, 0x36, 0xd9, 0xb2, - 0x42, 0x07, 0x68, 0x76, 0x30, 0xf7, 0x69, 0x6d, 0x92, 0x6f, 0x1e, 0x4c, 0x3a, 0x05, 0xd5, 0x98, - 0x6f, 0xe1, 0x50, 0x31, 0x6d, 0x33, 0xe3, 0x2a, 0xc6, 0xcb, 0x47, 0x51, 0x7b, 0xd3, 0x68, 0x4f, - 0x4d, 0xf4, 0x86, 0x59, 0xc5, 0xb5, 0xe1, 0x29, 0x2d, 0x2b, 0x69, 0x4d, 0x08, 0x7f, 0x20, 0x38, - 0xee, 0x05, 0xf1, 0x14, 0xfc, 0x4d, 0xed, 0x2a, 0x77, 0xf3, 0xe9, 0x6f, 0x07, 0xbe, 0x84, 0x91, - 0x2e, 0xe1, 0x81, 0x57, 0x76, 0x7f, 0xf1, 0xcf, 0xdd, 0x23, 0x17, 0x7e, 0x2d, 0x8c, 0x2a, 0x68, - 0x05, 0x0b, 0x9f, 0xc1, 0xb8, 0xe5, 0xc6, 0x27, 0x70, 0xb0, 0x65, 0x45, 0xd5, 0x7d, 0xf7, 0x89, - 0x4f, 0xe1, 0xc6, 0x75, 0x9c, 0x59, 0x16, 0x78, 0x33, 0x34, 0x47, 0xd4, 0x19, 0xcf, 0xbd, 0xa7, - 0x88, 0x7c, 0x47, 0x70, 0xb2, 0x62, 0xa6, 0x7b, 0xd7, 0xe1, 0x25, 0x2e, 0x7a, 0x4b, 0x3c, 0xe8, - 0x2e, 0xd1, 0xa7, 0xfd, 0xef, 0x89, 0x27, 0x70, 0xa7, 0xd5, 0xc2, 0x5d, 0x69, 0xf9, 0xd3, 0x03, - 0xff, 0x65, 0x3d, 0x05, 0x7e, 0x05, 0x23, 0xa7, 0x1f, 0x7c, 0xb7, 0x37, 0x5b, 0x5b, 0x84, 0xe1, - 0x74, 0x7f, 0xb0, 0x92, 0xca, 0x25, 0x1c, 0xb5, 0xa5, 0x88, 0xcf, 0xbb, 0xd9, 0x7b, 0x54, 0x1d, - 0x92, 0xa1, 0x94, 0x0a, 0x4b, 0x61, 0xdc, 0xfa, 0xcd, 0x78, 0x36, 0xa0, 0x00, 0x07, 0x3d, 0xff, - 0xab, 0x46, 0xf0, 0x3b, 0xf0, 0x9b, 0x93, 0xe0, 0x7b, 0xc3, 0xbf, 0x23, 0xbc, 0xff, 0xc7, 0xb8, - 0xa3, 0x5d, 0x3c, 0xf9, 0xb8, 0x5c, 0x73, 0xb3, 0xb1, 0x49, 0x94, 0xca, 0xcf, 0x8b, 0x8c, 0xaf, - 0x37, 0x46, 0x70, 0xb1, 0x16, 0xcc, 0x7c, 0x95, 0x6a, 0xbb, 0xc8, 0xc4, 0xd5, 0x22, 0x13, 0x9d, - 0x47, 0x43, 0xe5, 0x69, 0x32, 0x2a, 0x1f, 0x8e, 0xc7, 0xbf, 0x02, 0x00, 0x00, 0xff, 0xff, 0xcf, - 0x06, 0x7e, 0xe7, 0x58, 0x04, 0x00, 0x00, +var fileDescriptor_autopilot_1f7ac28ef56bb20c = []byte{ + // 463 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x94, 0xcf, 0x6f, 0xd3, 0x30, + 0x14, 0xc7, 0x95, 0x4c, 0x74, 0xcb, 0xeb, 0x60, 0xc3, 0x9d, 0xa6, 0x28, 0x54, 0xd0, 0x45, 0x1c, + 0x2a, 0x24, 0x52, 0x51, 0x38, 0x00, 0x12, 0x07, 0x86, 0x90, 0x90, 0x80, 0x03, 0x2e, 0xbb, 0x70, + 0x99, 0xd2, 0xcc, 0xb4, 0x56, 0x8d, 0x1d, 0xec, 0xe7, 0xa1, 0xfc, 0x43, 0x5c, 0xf9, 0x1b, 0x38, + 0xf2, 0x5f, 0xa1, 0xc5, 0x49, 0x49, 0xaa, 0x12, 0x84, 0xb4, 0x5b, 0xde, 0x8f, 0x7c, 0x9e, 0xdf, + 0xd7, 0x5f, 0x19, 0x86, 0xa9, 0x45, 0x95, 0x73, 0xa1, 0x50, 0xe7, 0xd9, 0x64, 0x1d, 0x24, 0xb9, + 0x56, 0xa8, 0xc8, 0x7e, 0xb3, 0x1a, 0x1f, 0xc0, 0xcd, 0x19, 0xa6, 0x68, 0x0d, 0x65, 0x5f, 0x2d, + 0x33, 0x18, 0x8f, 0xe1, 0x56, 0x9d, 0x30, 0xb9, 0x92, 0x86, 0x91, 0x63, 0xe8, 0xa5, 0x19, 0xf2, + 0x4b, 0x16, 0x7a, 0x23, 0x6f, 0xbc, 0x47, 0xab, 0x28, 0x7e, 0x08, 0x83, 0xf7, 0xea, 0x82, 0x7f, + 0x2e, 0x5a, 0x80, 0xab, 0x76, 0x26, 0xd3, 0xb9, 0x58, 0xb7, 0xbb, 0x28, 0x3e, 0x86, 0xa3, 0x76, + 0xbb, 0xc3, 0xc7, 0x1f, 0x81, 0x7c, 0xb0, 0x4c, 0x17, 0xb3, 0x4c, 0x69, 0xb6, 0xa6, 0x84, 0xb0, + 0x9b, 0xdb, 0xf9, 0x8a, 0x15, 0x26, 0xf4, 0x46, 0x3b, 0xe3, 0x80, 0xd6, 0x21, 0xb9, 0x0f, 0x84, + 0x2f, 0xa4, 0xd2, 0xec, 0x5c, 0xa8, 0x2c, 0x15, 0xe7, 0x06, 0x53, 0x64, 0xa1, 0x5f, 0xce, 0xda, + 0x93, 0xca, 0xc5, 0xf1, 0x77, 0x1f, 0x06, 0x2d, 0x6c, 0xb5, 0xcc, 0x5b, 0xd8, 0xd5, 0xcc, 0x58, + 0x81, 0x8e, 0xdb, 0x9f, 0x3e, 0x4a, 0x9a, 0x7a, 0x24, 0x5b, 0xfe, 0x49, 0xde, 0x30, 0xab, 0xb9, + 0x41, 0x9e, 0xd1, 0xf2, 0x4f, 0x5a, 0x13, 0xa2, 0x9f, 0x1e, 0x1c, 0x6c, 0x14, 0xc9, 0x10, 0x82, + 0x65, 0x9d, 0x2a, 0x15, 0x08, 0xe8, 0x9f, 0x04, 0x39, 0x83, 0x9e, 0x29, 0xe1, 0xa1, 0x5f, 0x4e, + 0x7f, 0xf1, 0xdf, 0xd3, 0x13, 0x57, 0x7e, 0x2d, 0x51, 0x17, 0xb4, 0x82, 0x45, 0xcf, 0xa0, 0xdf, + 0x48, 0x93, 0x43, 0xd8, 0x59, 0xb1, 0xa2, 0x9a, 0x7e, 0xf5, 0x49, 0x8e, 0xe0, 0xc6, 0x65, 0x2a, + 0xac, 0xd3, 0xc9, 0xa3, 0x2e, 0x78, 0xee, 0x3f, 0xf5, 0xe2, 0x1f, 0x1e, 0x1c, 0xce, 0x18, 0xb6, + 0xd5, 0xef, 0x5e, 0xe2, 0x74, 0x63, 0x89, 0x07, 0xed, 0x25, 0x36, 0x69, 0xd7, 0x7d, 0xe2, 0x01, + 0xdc, 0x6e, 0x8c, 0x70, 0x2a, 0x4d, 0x7f, 0xf9, 0x10, 0xbc, 0xac, 0x4f, 0x41, 0x5e, 0x41, 0xcf, + 0xb9, 0x8c, 0xdc, 0xd9, 0x38, 0x5b, 0xd3, 0xaa, 0xd1, 0x70, 0x7b, 0xb1, 0xb2, 0xca, 0x19, 0xec, + 0x37, 0x0d, 0x4b, 0x4e, 0xda, 0xdd, 0x5b, 0xbc, 0x1f, 0xc5, 0x5d, 0x2d, 0x15, 0x96, 0x42, 0xbf, + 0x71, 0xcd, 0x64, 0xd4, 0xe1, 0x00, 0x07, 0x3d, 0xf9, 0xa7, 0x47, 0xc8, 0x3b, 0x08, 0xd6, 0x92, + 0x90, 0xbb, 0xdd, 0xd7, 0x11, 0xdd, 0xfb, 0x6b, 0xdd, 0xd1, 0x4e, 0x9f, 0x7c, 0x9a, 0x2e, 0x38, + 0x2e, 0xed, 0x3c, 0xc9, 0xd4, 0x97, 0x89, 0xe0, 0x8b, 0x25, 0x4a, 0x2e, 0x17, 0x92, 0xe1, 0x37, + 0xa5, 0x57, 0x13, 0x21, 0x2f, 0x26, 0x42, 0xb6, 0x9e, 0x16, 0x9d, 0x67, 0xf3, 0x5e, 0xf9, 0xbc, + 0x3c, 0xfe, 0x1d, 0x00, 0x00, 0xff, 0xff, 0xb1, 0x4e, 0x74, 0x27, 0x7e, 0x04, 0x00, 0x00, } diff --git a/lnrpc/autopilotrpc/autopilot.proto b/lnrpc/autopilotrpc/autopilot.proto index ad11c250..9570136c 100644 --- a/lnrpc/autopilotrpc/autopilot.proto +++ b/lnrpc/autopilotrpc/autopilot.proto @@ -50,6 +50,9 @@ message ModifyStatusResponse {} message QueryScoresRequest{ repeated string pubkeys = 1 [json_name = "pubkeys"]; + + /// If set, we will ignore the local channel state when calculating scores. + bool ignore_local_state = 2 [json_name = "no_state"]; } message QueryScoresResponse { From d4813422c951e2613ccc1ba7ba93ac397edca9db Mon Sep 17 00:00:00 2001 From: "Johan T. Halseth" Date: Mon, 18 Mar 2019 14:41:45 +0100 Subject: [PATCH 3/4] autopilot+autopilotrpc: ignore local channels if ignore_local_state set --- autopilot/manager.go | 45 +++++++++++++++----------- lnrpc/autopilotrpc/autopilot_server.go | 4 ++- 2 files changed, 30 insertions(+), 19 deletions(-) diff --git a/autopilot/manager.go b/autopilot/manager.go index 17ce145c..f078b2a6 100644 --- a/autopilot/manager.go +++ b/autopilot/manager.go @@ -270,7 +270,9 @@ func (m *Manager) StopAgent() error { } // QueryHeuristics queries the available autopilot heuristics for node scores. -func (m *Manager) QueryHeuristics(nodes []NodeID) (HeuristicScores, error) { +func (m *Manager) QueryHeuristics(nodes []NodeID, localState bool) ( + HeuristicScores, error) { + m.Lock() defer m.Unlock() @@ -280,7 +282,7 @@ func (m *Manager) QueryHeuristics(nodes []NodeID) (HeuristicScores, error) { } log.Debugf("Querying heuristics for %d nodes", len(n)) - return m.queryHeuristics(n) + return m.queryHeuristics(n, localState) } // HeuristicScores is an alias for a map that maps heuristic names to a map of @@ -291,25 +293,32 @@ type HeuristicScores map[string]map[NodeID]float64 // the agent's current active heuristic. // // NOTE: Must be called with the manager's lock. -func (m *Manager) queryHeuristics(nodes map[NodeID]struct{}) ( +func (m *Manager) queryHeuristics(nodes map[NodeID]struct{}, localState bool) ( HeuristicScores, error) { - // Fetch the current set of channels. - totalChans, err := m.cfg.ChannelState() - if err != nil { - return nil, err - } + // If we want to take the local state into action when querying the + // heuristics, we fetch it. If not we'll just pass an emply slice to + // the heuristic. + var totalChans []Channel + var err error + if localState { + // Fetch the current set of channels. + totalChans, err = m.cfg.ChannelState() + if err != nil { + return nil, err + } - // If the agent is active, we can merge the channel state with the - // channels pending open. - if m.pilot != nil { - m.pilot.chanStateMtx.Lock() - m.pilot.pendingMtx.Lock() - totalChans = mergeChanState( - m.pilot.pendingOpens, m.pilot.chanState, - ) - m.pilot.pendingMtx.Unlock() - m.pilot.chanStateMtx.Unlock() + // If the agent is active, we can merge the channel state with + // the channels pending open. + if m.pilot != nil { + m.pilot.chanStateMtx.Lock() + m.pilot.pendingMtx.Lock() + totalChans = mergeChanState( + m.pilot.pendingOpens, m.pilot.chanState, + ) + m.pilot.pendingMtx.Unlock() + m.pilot.chanStateMtx.Unlock() + } } // As channel size we'll use the maximum size. diff --git a/lnrpc/autopilotrpc/autopilot_server.go b/lnrpc/autopilotrpc/autopilot_server.go index 5f31384b..4a938072 100644 --- a/lnrpc/autopilotrpc/autopilot_server.go +++ b/lnrpc/autopilotrpc/autopilot_server.go @@ -180,7 +180,9 @@ func (s *Server) QueryScores(ctx context.Context, in *QueryScoresRequest) ( } // Query the heuristics. - heuristicScores, err := s.manager.QueryHeuristics(nodes) + heuristicScores, err := s.manager.QueryHeuristics( + nodes, !in.IgnoreLocalState, + ) if err != nil { return nil, err } From 6aae6fda93fe22915d258c88271378790815b175 Mon Sep 17 00:00:00 2001 From: "Johan T. Halseth" Date: Mon, 18 Mar 2019 14:58:19 +0100 Subject: [PATCH 4/4] lncli/autopilot: add -ignorelocal state flag to query --- cmd/lncli/autopilotrpc_active.go | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/cmd/lncli/autopilotrpc_active.go b/cmd/lncli/autopilotrpc_active.go index c770e69a..16bd517c 100644 --- a/cmd/lncli/autopilotrpc_active.go +++ b/cmd/lncli/autopilotrpc_active.go @@ -97,9 +97,16 @@ func disable(ctx *cli.Context) error { var queryScoresCommand = cli.Command{ Name: "query", Usage: "Query the autopilot heuristcs for nodes' scores.", - ArgsUsage: " ...", + ArgsUsage: "[flags] ...", Description: "", Action: actionDecorator(queryScores), + Flags: []cli.Flag{ + cli.BoolFlag{ + Name: "ignorelocalstate, i", + Usage: "Ignore local channel state when calculating " + + "scores.", + }, + }, } func queryScores(ctx *cli.Context) error { @@ -123,7 +130,8 @@ loop: } req := &autopilotrpc.QueryScoresRequest{ - Pubkeys: pubs, + Pubkeys: pubs, + IgnoreLocalState: ctx.Bool("ignorelocalstate"), } resp, err := client.QueryScores(ctxb, req)