mirror of
https://github.com/lightninglabs/faraday.git
synced 2026-08-13 12:33:35 +02:00
Merge pull request #9 from lightninglabs/recs-revenuebased
trmrpc: Add revenue and volume based close recommendations
This commit is contained in:
commit
f9d7d86315
9 changed files with 1224 additions and 424 deletions
|
|
@ -15,6 +15,17 @@ var channelInsightsCommand = cli.Command{
|
|||
Action: queryChannelInsights,
|
||||
}
|
||||
|
||||
// insightsResp is used to display additional information that is calculated
|
||||
// from the channel insight in the cli response.
|
||||
type insightsResp struct {
|
||||
*trmrpc.ChannelInsight
|
||||
UptimeRatio float64 `json:"uptime_ratio"`
|
||||
RevenuePerConfirmation float64 `json:"revenue_per_conf_msat"`
|
||||
VolumePerConfirmation float64 `json:"volume_per_conf_msat"`
|
||||
IncomingVolumePerConfirmation float64 `json:"incoming_vol_per_conf_msat"`
|
||||
OutgoingVolumePerConfirmation float64 `json:"outgoing_vol_per_conf_msat"`
|
||||
}
|
||||
|
||||
func queryChannelInsights(ctx *cli.Context) error {
|
||||
client, cleanup := getClient(ctx)
|
||||
defer cleanup()
|
||||
|
|
@ -27,17 +38,14 @@ func queryChannelInsights(ctx *cli.Context) error {
|
|||
return err
|
||||
}
|
||||
|
||||
type insightsResp struct {
|
||||
*trmrpc.ChannelInsight
|
||||
UptimeRatio float64 `json:"uptime_ratio"`
|
||||
RevenuePerConfirmation float64 `json:"revenue_per_confirmation_msat"`
|
||||
}
|
||||
insights := make([]insightsResp, len(resp.ChannelInsights))
|
||||
for i, channel := range resp.ChannelInsights {
|
||||
confirmations := float64(channel.Confirmations)
|
||||
|
||||
insight := insightsResp{
|
||||
ChannelInsight: channel,
|
||||
RevenuePerConfirmation: float64(channel.FeesEarnedMsat) /
|
||||
float64(channel.Confirmations),
|
||||
confirmations,
|
||||
}
|
||||
|
||||
if channel.MonitoredSeconds != 0 {
|
||||
|
|
@ -45,6 +53,20 @@ func queryChannelInsights(ctx *cli.Context) error {
|
|||
float64(channel.MonitoredSeconds)
|
||||
}
|
||||
|
||||
// Calculate incoming, outgoing and total volume per
|
||||
// confirmation.
|
||||
insight.IncomingVolumePerConfirmation =
|
||||
float64(channel.VolumeIncomingMsat) /
|
||||
confirmations
|
||||
|
||||
insight.OutgoingVolumePerConfirmation =
|
||||
float64(channel.VolumeOutgoingMsat) /
|
||||
confirmations
|
||||
|
||||
insight.VolumePerConfirmation =
|
||||
insight.IncomingVolumePerConfirmation +
|
||||
confirmations
|
||||
|
||||
insights[i] = insight
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package main
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/lightninglabs/terminator/trmrpc"
|
||||
|
|
@ -11,19 +12,51 @@ import (
|
|||
var (
|
||||
defaultMinMonitored = time.Hour * 24 * 7 * 4 // four weeks in hours
|
||||
defaultOutlierMultiplier = 3
|
||||
)
|
||||
|
||||
var closeRecommendationCommand = cli.Command{
|
||||
Name: "closerecs",
|
||||
Category: "channel",
|
||||
Usage: "Get close recommendations for currently open channels.",
|
||||
Flags: []cli.Flag{
|
||||
cli.Int64Flag{
|
||||
Name: "min_monitored",
|
||||
Usage: "amount of time in seconds a channel should " +
|
||||
"be monitored for to be eligible for close",
|
||||
Value: int64(defaultMinMonitored.Seconds()),
|
||||
// monitoredFlag is common to recommendation requests.
|
||||
monitoredFlag = cli.Int64Flag{
|
||||
Name: "min_monitored",
|
||||
Usage: "amount of time in seconds a channel should be monitored " +
|
||||
"for to be eligible for close",
|
||||
Value: int64(defaultMinMonitored.Seconds()),
|
||||
}
|
||||
|
||||
// Flags required for threshold close recommendations.
|
||||
thresholdFlags = []cli.Flag{
|
||||
cli.Float64Flag{
|
||||
Name: "uptime",
|
||||
Usage: "Ratio of uptime to time monitored, expressed" +
|
||||
"in [0;1].",
|
||||
},
|
||||
cli.Float64Flag{
|
||||
Name: "revenue",
|
||||
Usage: "threshold revenue (in msat) per confirmation " +
|
||||
"beneath which channels will be identified " +
|
||||
"for close.",
|
||||
},
|
||||
cli.Float64Flag{
|
||||
Name: "incoming",
|
||||
Usage: "threshold incoming volume (in msat) per " +
|
||||
"confirmation beneath which channels will be " +
|
||||
"identified for close",
|
||||
},
|
||||
cli.Float64Flag{
|
||||
Name: "outgoing",
|
||||
Usage: "threshold outgoing volume (in msat) per " +
|
||||
"confirmation beneath which channels will be " +
|
||||
"identified for close",
|
||||
},
|
||||
cli.Float64Flag{
|
||||
Name: "volume",
|
||||
Usage: "threshold total volume (in msat) per " +
|
||||
"confirmation beneath which channels will be " +
|
||||
"identified for close",
|
||||
},
|
||||
monitoredFlag,
|
||||
}
|
||||
|
||||
// Flags required for outlier close recommendations.
|
||||
outlierFlags = []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "outlier_mult",
|
||||
Usage: "(optional with outlier strategy) Number of " +
|
||||
|
|
@ -32,43 +65,147 @@ var closeRecommendationCommand = cli.Command{
|
|||
"Recommended values are 1.5 for aggressive " +
|
||||
"recommendations and 3 for conservative ones.",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "uptime_threshold",
|
||||
Usage: "(optional) Uptime percentage threshold " +
|
||||
"underneath which a channel will be recommended " +
|
||||
"for close.",
|
||||
cli.BoolFlag{
|
||||
Name: "uptime",
|
||||
Usage: "set to get recommendations based on the " +
|
||||
"channel's peer's ratio of uptime to time " +
|
||||
"monitored",
|
||||
},
|
||||
},
|
||||
Action: queryCloseRecommendations,
|
||||
cli.BoolFlag{
|
||||
Name: "revenue",
|
||||
Usage: "get recommendations based on the " +
|
||||
"channel's revenue per confirmation",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "incoming_volume",
|
||||
Usage: "get recommendations based on the " +
|
||||
"channel's incoming volume per confirmation",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "outgoing_volume",
|
||||
Usage: "get recommendations based on the " +
|
||||
"channel's outgoing volume per confirmation",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "volume",
|
||||
Usage: "get recommendations based on the " +
|
||||
"channel's total volume per confirmation",
|
||||
},
|
||||
monitoredFlag,
|
||||
}
|
||||
)
|
||||
|
||||
var thresholdRecommendationCommand = cli.Command{
|
||||
Name: "threshold",
|
||||
Category: "recommendations",
|
||||
Usage: "Get close recommendations for currently open channels " +
|
||||
"based whether they are below a set threshold.",
|
||||
Flags: thresholdFlags,
|
||||
Action: queryThresholdRecommendations,
|
||||
}
|
||||
|
||||
func queryCloseRecommendations(ctx *cli.Context) error {
|
||||
func queryThresholdRecommendations(ctx *cli.Context) error {
|
||||
client, cleanup := getClient(ctx)
|
||||
defer cleanup()
|
||||
|
||||
// Set monitored value from cli and default outlier multiplier. The
|
||||
// outlier multiplier will be overwritten if the user provided it.
|
||||
req := &trmrpc.CloseRecommendationsRequest{
|
||||
MinimumMonitored: ctx.Int64("min_monitored"),
|
||||
OutlierMultiplier: float32(defaultOutlierMultiplier),
|
||||
// Set monitored value from cli values, this value will always be
|
||||
// non-zero because the flag has a default.
|
||||
req := &trmrpc.ThresholdRecommendationsRequest{
|
||||
RecRequest: &trmrpc.CloseRecommendationRequest{
|
||||
MinimumMonitored: ctx.Int64("min_monitored"),
|
||||
},
|
||||
}
|
||||
|
||||
// If an a custom outlier multiple was set, use it.
|
||||
if ctx.IsSet("outlier_mult") {
|
||||
req.OutlierMultiplier = float32(ctx.Float64("outlier_mult"))
|
||||
}
|
||||
// Set threshold and metric based on uptime/revenue flags.
|
||||
switch {
|
||||
case ctx.IsSet("uptime"):
|
||||
req.ThresholdValue = float32(ctx.Float64("uptime"))
|
||||
req.RecRequest.Metric = trmrpc.CloseRecommendationRequest_UPTIME
|
||||
|
||||
// If an uptime threshold was set, use it.
|
||||
if ctx.IsSet("uptime_threshold") {
|
||||
uptimeThreshold := float32(ctx.Float64("uptime_threshold"))
|
||||
req.Threshold =
|
||||
&trmrpc.CloseRecommendationsRequest_UptimeThreshold{
|
||||
UptimeThreshold: uptimeThreshold,
|
||||
}
|
||||
case ctx.IsSet("revenue"):
|
||||
req.ThresholdValue = float32(ctx.Float64("revenue"))
|
||||
req.RecRequest.Metric = trmrpc.CloseRecommendationRequest_REVENUE
|
||||
|
||||
case ctx.IsSet("incoming"):
|
||||
req.ThresholdValue = float32(ctx.Float64("incoming"))
|
||||
req.RecRequest.Metric = trmrpc.CloseRecommendationRequest_INCOMING_VOLUME
|
||||
|
||||
case ctx.IsSet("outgoing"):
|
||||
req.ThresholdValue = float32(ctx.Float64("outgoing"))
|
||||
req.RecRequest.Metric = trmrpc.CloseRecommendationRequest_OUTGOING_VOLUME
|
||||
|
||||
case ctx.IsSet("volume"):
|
||||
req.ThresholdValue = float32(ctx.Float64("volume"))
|
||||
req.RecRequest.Metric = trmrpc.CloseRecommendationRequest_TOTAL_VOLUME
|
||||
|
||||
default:
|
||||
return fmt.Errorf("threshold required")
|
||||
}
|
||||
|
||||
rpcCtx := context.Background()
|
||||
recs, err := client.CloseRecommendations(rpcCtx, req)
|
||||
recs, err := client.ThresholdRecommendations(rpcCtx, req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
printRespJSON(recs)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var outlierRecommendationCommand = cli.Command{
|
||||
Name: "outliers",
|
||||
Category: "recommendations",
|
||||
Usage: "Get close recommendations for currently open channels " +
|
||||
"based on whether it is an outlier.",
|
||||
Flags: outlierFlags,
|
||||
Action: queryOutlierRecommendations,
|
||||
}
|
||||
|
||||
func queryOutlierRecommendations(ctx *cli.Context) error {
|
||||
client, cleanup := getClient(ctx)
|
||||
defer cleanup()
|
||||
|
||||
// Set monitored value from cli and default outlier multiplier. The
|
||||
// outlier multiplier will be overwritten if the user provided it, and
|
||||
// the monitored value will always be non-zero because the flag has a
|
||||
// default value.
|
||||
req := &trmrpc.OutlierRecommendationsRequest{
|
||||
RecRequest: &trmrpc.CloseRecommendationRequest{
|
||||
MinimumMonitored: ctx.Int64("min_monitored"),
|
||||
},
|
||||
OutlierMultiplier: float32(defaultOutlierMultiplier),
|
||||
}
|
||||
|
||||
// If an a custom outlier multiple was set, use it.
|
||||
if ctx.IsSet("outlier_mult") {
|
||||
req.OutlierMultiplier = float32(ctx.Float64("outlier_mult"))
|
||||
}
|
||||
|
||||
// Set metric based on uptime or revenue flags.
|
||||
switch {
|
||||
case ctx.IsSet("uptime"):
|
||||
req.RecRequest.Metric = trmrpc.CloseRecommendationRequest_UPTIME
|
||||
|
||||
case ctx.IsSet("revenue"):
|
||||
req.RecRequest.Metric = trmrpc.CloseRecommendationRequest_REVENUE
|
||||
|
||||
case ctx.IsSet("incoming_volume"):
|
||||
req.RecRequest.Metric = trmrpc.CloseRecommendationRequest_INCOMING_VOLUME
|
||||
|
||||
case ctx.IsSet("outgoing_volume"):
|
||||
req.RecRequest.Metric = trmrpc.CloseRecommendationRequest_OUTGOING_VOLUME
|
||||
|
||||
case ctx.IsSet("volume"):
|
||||
req.RecRequest.Metric = trmrpc.CloseRecommendationRequest_TOTAL_VOLUME
|
||||
|
||||
default:
|
||||
return fmt.Errorf("uptime, revenue or volume realted flag " +
|
||||
"required")
|
||||
}
|
||||
|
||||
rpcCtx := context.Background()
|
||||
recs, err := client.OutlierRecommendations(rpcCtx, req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,8 @@ func main() {
|
|||
},
|
||||
}
|
||||
app.Commands = []cli.Command{
|
||||
closeRecommendationCommand,
|
||||
thresholdRecommendationCommand,
|
||||
outlierRecommendationCommand,
|
||||
revenueReportCommand,
|
||||
channelInsightsCommand,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,11 @@
|
|||
// time will be considered for closing.
|
||||
//
|
||||
// Channels will be assessed based on the following data points:
|
||||
// - Uptime percentage
|
||||
// - Uptime ratio
|
||||
// - Fee revenue per block capital has been committed for
|
||||
// - Incoming volume per block capital has been committed for
|
||||
// - Outgoing volume per block capital has been committed for
|
||||
// - Total volume per block capital has been committed for
|
||||
//
|
||||
// Channels that are outliers within the set of channels that are eligible for
|
||||
// close recommendation will be recommended for closure.
|
||||
|
|
@ -15,7 +19,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/lightninglabs/terminator/dataset"
|
||||
"github.com/lightningnetwork/lnd/lnrpc"
|
||||
"github.com/lightninglabs/terminator/insights"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
@ -24,30 +28,56 @@ var (
|
|||
errZeroMinMonitored = errors.New("must provide a non-zero minimum " +
|
||||
"monitor time for channel exclusion")
|
||||
|
||||
// ErrNoMetric is returned when a close recommendations with no chosen
|
||||
// metric is provided.
|
||||
ErrNoMetric = errors.New("metric required for close " +
|
||||
"recommendations")
|
||||
|
||||
// DefaultOutlierMultiplier is the default value used in close
|
||||
// recommendations based on outliers when there is no user provided
|
||||
// value.
|
||||
DefaultOutlierMultiplier float64 = 3
|
||||
)
|
||||
|
||||
// Metric is an enum which indicate what data point our recommendations should
|
||||
// be based on.
|
||||
type Metric int
|
||||
|
||||
const (
|
||||
invalidMetric Metric = iota
|
||||
|
||||
// UptimeMetric bases recommendations on the uptime of the channel's
|
||||
// remote peer.
|
||||
UptimeMetric
|
||||
|
||||
// RevenueMetric bases recommendations on the revenue that the channel
|
||||
// has generated per block that our capital has been committed for.
|
||||
RevenueMetric
|
||||
|
||||
// IncomingVolume bases recommendations on the incoming volume that the
|
||||
// channel has processed, scaled by funding transaction confirmations.
|
||||
IncomingVolume
|
||||
|
||||
// IncomingVolume bases recommendations on the incoming volume that the
|
||||
// channel has processed, scaled by funding transaction confirmations.
|
||||
OutgoingVolume
|
||||
|
||||
// Volume bases recommendations on the total volume that the
|
||||
// channel has processed, scaled by funding transaction confirmations.
|
||||
Volume
|
||||
)
|
||||
|
||||
// CloseRecommendationConfig provides the functions and parameters required to
|
||||
// provide close recommendations.
|
||||
// provide close recommendations. This struct holds fields which are common to
|
||||
// all recommendation calculation strategies.
|
||||
type CloseRecommendationConfig struct {
|
||||
// OpenChannels is a function which returns all of our currently open,
|
||||
// public channels.
|
||||
OpenChannels func() ([]*lnrpc.Channel, error)
|
||||
// ChannelInsights is a function which returns a set of channel insights
|
||||
// for our current set of channels.
|
||||
ChannelInsights func() ([]*insights.ChannelInfo, error)
|
||||
|
||||
// OutlierMultiplier is the number of inter quartile ranges a value
|
||||
// should be away from the lower/upper quartile to be considered an
|
||||
// outlier. Recommended values are 1.5 for more aggressive
|
||||
// recommendations and 3 for more cautious recommendations.
|
||||
OutlierMultiplier float64
|
||||
|
||||
// UptimeThreshold is the uptime percentage over the channel's observed
|
||||
// lifetime beneath which channels will be recommended for close. This
|
||||
// value is expressed as a percentage in [0,1], and will default to 0 if
|
||||
// it is not set.
|
||||
UptimeThreshold float64
|
||||
// Metric defines the metric that we will use to provide close
|
||||
// recommendations. Calls will fail if no value is provided.
|
||||
Metric Metric
|
||||
|
||||
// MinimumMonitored is the minimum amount of time that a channel must
|
||||
// have been monitored for before it is considered for closing.
|
||||
|
|
@ -72,29 +102,53 @@ type Report struct {
|
|||
// for long enough to be considered for close.
|
||||
ConsideredChannels int
|
||||
|
||||
// OutlierRecommendations is a map of chanel outpoints to a bool which
|
||||
// indicates whether we should close the channel based on whether it is
|
||||
// an outlier.
|
||||
OutlierRecommendations map[string]Recommendation
|
||||
|
||||
// ThresholdRecommendations is a map of chanel outpoints to a bool which
|
||||
// indicates whether we should close the channel based on whether it is
|
||||
// below a user provided threshold.
|
||||
ThresholdRecommendations map[string]Recommendation
|
||||
// Recommendations is a map of chanel outpoints to a bool which
|
||||
// indicates whether we should close the channel.
|
||||
Recommendations map[string]Recommendation
|
||||
}
|
||||
|
||||
// CloseRecommendations returns a report which contains information about the
|
||||
// channels that were considered and a list of close recommendations. Channels
|
||||
// are considered for close if their uptime percentage is a lower outlier in
|
||||
// uptime percentage dataset.
|
||||
func CloseRecommendations(cfg *CloseRecommendationConfig) (*Report, error) {
|
||||
// OutlierRecommendations returns recommendations based on whether a value is a
|
||||
// lower outlier within its current dataset. It takes an outlier multiplier value
|
||||
// which is the number of inter quartile ranges a value should be away from the
|
||||
// lower/upper quartile to be considered an outlier. Recommended values are 1.5
|
||||
// for more aggressive recommendations and 3 for more cautious recommendations.
|
||||
func OutlierRecommendations(cfg *CloseRecommendationConfig,
|
||||
outlierMultiplier float64) (*Report, error) {
|
||||
|
||||
getRecs := func(dataset dataset.Dataset) (map[string]Recommendation, error) {
|
||||
return getOutlierRecs(dataset, outlierMultiplier, false)
|
||||
}
|
||||
|
||||
return closeRecommendations(cfg, getRecs)
|
||||
}
|
||||
|
||||
// ThresholdRecommendations returns a recommendations based on whether a value is
|
||||
// below a given threshold.
|
||||
func ThresholdRecommendations(cfg *CloseRecommendationConfig,
|
||||
threshold float64) (*Report, error) {
|
||||
|
||||
getRecs := func(dataset dataset.Dataset) (map[string]Recommendation, error) {
|
||||
return getThresholdRecs(dataset, threshold, true), nil
|
||||
}
|
||||
|
||||
return closeRecommendations(cfg, getRecs)
|
||||
}
|
||||
|
||||
// closeRecommendations returns a report which contains information about the
|
||||
// channels that were considered and a list of close recommendations. It takes
|
||||
// a function which can produce the relevant dataset from a set of channel
|
||||
// insights and a function which can produces recommendations as parameters.
|
||||
func closeRecommendations(cfg *CloseRecommendationConfig,
|
||||
getRecommendations func(data dataset.Dataset) (
|
||||
map[string]Recommendation, error)) (*Report, error) {
|
||||
|
||||
// Check that the minimum wait time is non-zero.
|
||||
if cfg.MinimumMonitored == 0 {
|
||||
return nil, errZeroMinMonitored
|
||||
}
|
||||
|
||||
// Get the set of currently open channels.
|
||||
channels, err := cfg.OpenChannels()
|
||||
// Get the set of insights for our currently open channels.
|
||||
channels, err := cfg.ChannelInsights()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -102,48 +156,62 @@ func CloseRecommendations(cfg *CloseRecommendationConfig) (*Report, error) {
|
|||
// Filter out channels that are below the minimum required age.
|
||||
filtered := filterChannels(channels, cfg.MinimumMonitored)
|
||||
|
||||
// Produce a dataset containing uptime percentage for channels that have
|
||||
// been monitored for longer than the minimum time.
|
||||
uptime := getUptimeDataset(filtered)
|
||||
|
||||
report := &Report{
|
||||
TotalChannels: len(channels),
|
||||
ConsideredChannels: len(uptime),
|
||||
ConsideredChannels: len(filtered),
|
||||
}
|
||||
|
||||
var data dataset.Dataset
|
||||
switch cfg.Metric {
|
||||
case UptimeMetric:
|
||||
data = getUptimeDataset(filtered)
|
||||
|
||||
case RevenueMetric:
|
||||
data = getConfirmationScaledDataset(revenueValue, filtered)
|
||||
|
||||
case IncomingVolume:
|
||||
data = getConfirmationScaledDataset(
|
||||
incomingVolumeValue, filtered,
|
||||
)
|
||||
|
||||
case OutgoingVolume:
|
||||
data = getConfirmationScaledDataset(
|
||||
outgoingVolumeValue, filtered,
|
||||
)
|
||||
|
||||
case Volume:
|
||||
data = getConfirmationScaledDataset(totalVolumeValue, filtered)
|
||||
|
||||
default:
|
||||
return nil, ErrNoMetric
|
||||
}
|
||||
|
||||
// Get close recommendations based on outliers.
|
||||
report.OutlierRecommendations, err = getOutlierRecs(
|
||||
uptime, cfg.OutlierMultiplier,
|
||||
)
|
||||
report.Recommendations, err = getRecommendations(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Get close recommendations based on threshold.
|
||||
report.ThresholdRecommendations = getThresholdRecs(
|
||||
uptime, cfg.UptimeThreshold,
|
||||
)
|
||||
|
||||
return report, nil
|
||||
}
|
||||
|
||||
// getThresholdRecs returns a map of channel points to values that are below a
|
||||
// given threshold.
|
||||
func getThresholdRecs(uptime dataset.Dataset,
|
||||
threshold float64) map[string]Recommendation {
|
||||
// getThresholdRecs returns a map of channel points to values that are above
|
||||
// or below a given threshold.
|
||||
func getThresholdRecs(values dataset.Dataset,
|
||||
threshold float64, belowThreshold bool) map[string]Recommendation {
|
||||
|
||||
// Get a map of channel labels to a boolean indicating whether
|
||||
// they are beneath the threshold.
|
||||
thresholdValues := uptime.GetThreshold(threshold, true)
|
||||
thresholdValues := values.GetThreshold(threshold, belowThreshold)
|
||||
|
||||
recommendations := make(
|
||||
map[string]Recommendation, len(thresholdValues),
|
||||
)
|
||||
|
||||
for chanPoint, belowThrehsold := range thresholdValues {
|
||||
for chanPoint, crossesThreshold := range thresholdValues {
|
||||
recommendations[chanPoint] = Recommendation{
|
||||
Value: uptime.Value(chanPoint),
|
||||
RecommendClose: belowThrehsold,
|
||||
Value: values.Value(chanPoint),
|
||||
RecommendClose: crossesThreshold,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -151,75 +219,150 @@ func getThresholdRecs(uptime dataset.Dataset,
|
|||
}
|
||||
|
||||
// getOutlierRecs generates map of channel outpoint strings to booleans
|
||||
// indicating whether we recommend closing a channel.
|
||||
func getOutlierRecs(uptime dataset.Dataset,
|
||||
outlierMultiplier float64) (map[string]Recommendation, error) {
|
||||
// indicating whether we recommend closing a channel. It takes a outlier
|
||||
// multiplier which scales the degree to which we want to calculate outliers,
|
||||
// and an upper outlier boolean which determines whether we want to identify
|
||||
// upper or lower outliers.
|
||||
func getOutlierRecs(values dataset.Dataset,
|
||||
outlierMultiplier float64,
|
||||
upperOutlier bool) (map[string]Recommendation, error) {
|
||||
|
||||
recommendations := make(map[string]Recommendation)
|
||||
|
||||
outliers, err := uptime.GetOutliers(outlierMultiplier)
|
||||
outliers, err := values.GetOutliers(outlierMultiplier)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Add a recommendation for each channel to our set of recommendations.
|
||||
// If the channel is a lower outlier, we recommend it for close.
|
||||
// RecommendClose in the recommendation will be set to true if the
|
||||
// channel matches the outlier type we are looking for (upper or
|
||||
// lower).
|
||||
for chanPoint, outlier := range outliers {
|
||||
var recommendClose bool
|
||||
|
||||
// If we want to detect upper outliers, and the channel is a
|
||||
// upper outlier, set recommend close to true.
|
||||
if upperOutlier && outlier.UpperOutlier {
|
||||
recommendClose = true
|
||||
}
|
||||
|
||||
// If we want to detect lower outliers, and the channel is a
|
||||
// lower outlier, set recommend close to true.
|
||||
if !upperOutlier && outlier.LowerOutlier {
|
||||
recommendClose = true
|
||||
}
|
||||
|
||||
recommendations[chanPoint] = Recommendation{
|
||||
Value: uptime.Value(chanPoint),
|
||||
RecommendClose: outlier.LowerOutlier,
|
||||
Value: values.Value(chanPoint),
|
||||
RecommendClose: recommendClose,
|
||||
}
|
||||
}
|
||||
|
||||
return recommendations, nil
|
||||
}
|
||||
|
||||
// filterChannels filters out channels that are beneath the minimum age and
|
||||
// produces a map of channel outpoint strings to rpc channels which contains
|
||||
// the channels that are eligible for close recommendation.
|
||||
func filterChannels(openChannels []*lnrpc.Channel,
|
||||
minimumAge time.Duration) map[string]*lnrpc.Channel {
|
||||
// filterChannels filters out channels that are beneath the minimum age, or
|
||||
// are private and returns a set of channels that are eligible for close
|
||||
// recommendations.
|
||||
func filterChannels(channelInsights []*insights.ChannelInfo,
|
||||
minimumAge time.Duration) []*insights.ChannelInfo {
|
||||
|
||||
// Create a map which will hold channel point labels to uptime
|
||||
// percentage.
|
||||
channels := make(map[string]*lnrpc.Channel)
|
||||
filteredChannels := make(
|
||||
[]*insights.ChannelInfo, 0, len(channelInsights),
|
||||
)
|
||||
|
||||
for _, channel := range channelInsights {
|
||||
if channel.MonitoredFor < minimumAge {
|
||||
log.Tracef("Channel: %v has not been "+
|
||||
"monitored for long enough, excluding it "+
|
||||
"from consideration", channel.ChannelPoint)
|
||||
|
||||
for _, channel := range openChannels {
|
||||
if channel.Lifetime < int64(minimumAge.Seconds()) {
|
||||
log.Tracef("Channel: %v has not been monitored for "+
|
||||
"long enough, excluding it from consideration",
|
||||
channel.ChannelPoint)
|
||||
continue
|
||||
}
|
||||
|
||||
channels[channel.ChannelPoint] = channel
|
||||
if channel.Private {
|
||||
log.Tracef("Channel: %v is private, excluding "+
|
||||
"it from consideration", channel.ChannelPoint)
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
filteredChannels = append(filteredChannels, channel)
|
||||
}
|
||||
|
||||
log.Debugf("considering: %v channels for close out of %v",
|
||||
len(channels), len(openChannels))
|
||||
len(filteredChannels), len(channelInsights))
|
||||
|
||||
return channels
|
||||
return filteredChannels
|
||||
}
|
||||
|
||||
// getUptimeDataset takes a set of channels that are eligible for close and
|
||||
// produces an uptime dataset.
|
||||
func getUptimeDataset(
|
||||
eligibleChannels map[string]*lnrpc.Channel) dataset.Dataset {
|
||||
eligibleChannels []*insights.ChannelInfo) dataset.Dataset {
|
||||
|
||||
// Create a map which will hold channel point string label to uptime
|
||||
// percentage.
|
||||
var channels = make(map[string]float64)
|
||||
// ratio.
|
||||
var channels = make(map[string]float64, len(eligibleChannels))
|
||||
|
||||
for outpoint, channel := range eligibleChannels {
|
||||
// Calculate the uptime percentage for the channel and add it
|
||||
for _, channel := range eligibleChannels {
|
||||
// Calculate the uptime ratio for the channel and add it
|
||||
// to the channel -> uptime map.
|
||||
uptimePercentage := float64(channel.Uptime) / float64(channel.Lifetime)
|
||||
channels[outpoint] = uptimePercentage
|
||||
uptimeRatio := float64(channel.Uptime) /
|
||||
float64(channel.MonitoredFor)
|
||||
|
||||
log.Tracef("channel: %v has uptime percentage: %v",
|
||||
outpoint, uptimePercentage)
|
||||
channels[channel.ChannelPoint] = uptimeRatio
|
||||
}
|
||||
|
||||
// Create a dataset for the uptime values we have collected.
|
||||
return dataset.New(channels)
|
||||
}
|
||||
|
||||
// getConfirmationScaledDataset returns a dataset that scales a value by the
|
||||
// number of confirmations its funding transaction has. It takes a function
|
||||
// which gets the relevant value from the channel insight as input.
|
||||
func getConfirmationScaledDataset(getValue perConfirmationValue,
|
||||
eligibleChannels []*insights.ChannelInfo) dataset.Dataset {
|
||||
|
||||
// Create a map which will hold channel point string label to revenue
|
||||
// per block that we have had revenue committed for.
|
||||
var channels = make(map[string]float64, len(eligibleChannels))
|
||||
|
||||
for _, channel := range eligibleChannels {
|
||||
// Channels cannot have zero confirmations because we are
|
||||
// dealing with open (ie confirmed) channels, so we can
|
||||
// get the value and scale it by our confirmation total.
|
||||
valuePerConfirmation :=
|
||||
getValue(channel) /
|
||||
float64(channel.Confirmations)
|
||||
|
||||
channels[channel.ChannelPoint] = valuePerConfirmation
|
||||
}
|
||||
|
||||
return channels
|
||||
}
|
||||
|
||||
// perConfirmationValue is a function which gets a value from a channel insight
|
||||
// that needs to be scaled by its number of confirmations.
|
||||
type perConfirmationValue func(channel *insights.ChannelInfo) float64
|
||||
|
||||
// revenueValue gets total revenue for a channel.
|
||||
func revenueValue(channel *insights.ChannelInfo) float64 {
|
||||
return float64(channel.FeesEarned)
|
||||
}
|
||||
|
||||
// incomingVolumeValue gets total incoming volume for a channel.
|
||||
func incomingVolumeValue(channel *insights.ChannelInfo) float64 {
|
||||
return float64(channel.VolumeIncoming)
|
||||
}
|
||||
|
||||
// outgoingVolumeValue gets total outgoing volume for a channel.
|
||||
func outgoingVolumeValue(channel *insights.ChannelInfo) float64 {
|
||||
return float64(channel.VolumeOutgoing)
|
||||
}
|
||||
|
||||
// totalVolumeValue gets total volume for a channel.
|
||||
func totalVolumeValue(channel *insights.ChannelInfo) float64 {
|
||||
return float64(channel.VolumeIncoming + channel.VolumeOutgoing)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/lightninglabs/terminator/dataset"
|
||||
"github.com/lightningnetwork/lnd/lnrpc"
|
||||
"github.com/lightninglabs/terminator/insights"
|
||||
)
|
||||
|
||||
// TestCloseRecommendations tests CloseRecommendations for error cases where
|
||||
|
|
@ -15,56 +15,72 @@ import (
|
|||
// the minimum acceptable number of channels. It does not test the report
|
||||
// provided, because that will be covered by further tests.
|
||||
func TestCloseRecommendations(t *testing.T) {
|
||||
var (
|
||||
openChanErr = errors.New("intentional test err")
|
||||
hourSeconds = int64(time.Hour.Seconds())
|
||||
)
|
||||
var openChanErr = errors.New("intentional test err")
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
OpenChannels func() ([]*lnrpc.Channel, error)
|
||||
upperOutlier bool
|
||||
metric Metric
|
||||
ChanInsights func() ([]*insights.ChannelInfo, error)
|
||||
MinMonitored time.Duration
|
||||
expectedErr error
|
||||
}{
|
||||
{
|
||||
name: "no channels",
|
||||
OpenChannels: func() ([]*lnrpc.Channel, error) {
|
||||
name: "no channels",
|
||||
upperOutlier: false,
|
||||
metric: UptimeMetric,
|
||||
ChanInsights: func() ([]*insights.ChannelInfo, error) {
|
||||
return nil, nil
|
||||
},
|
||||
MinMonitored: time.Hour,
|
||||
expectedErr: nil,
|
||||
},
|
||||
{
|
||||
name: "open channels fails",
|
||||
OpenChannels: func() ([]*lnrpc.Channel, error) {
|
||||
name: "channel insights fails",
|
||||
upperOutlier: false,
|
||||
metric: invalidMetric,
|
||||
ChanInsights: func() ([]*insights.ChannelInfo, error) {
|
||||
return nil, nil
|
||||
},
|
||||
MinMonitored: time.Hour,
|
||||
expectedErr: ErrNoMetric,
|
||||
},
|
||||
{
|
||||
name: "channel insights fails",
|
||||
metric: UptimeMetric,
|
||||
ChanInsights: func() ([]*insights.ChannelInfo, error) {
|
||||
return nil, openChanErr
|
||||
},
|
||||
MinMonitored: time.Hour,
|
||||
expectedErr: openChanErr,
|
||||
},
|
||||
{
|
||||
name: "zero min monitored",
|
||||
OpenChannels: func() ([]*lnrpc.Channel, error) {
|
||||
name: "zero min monitored",
|
||||
upperOutlier: false,
|
||||
metric: UptimeMetric,
|
||||
ChanInsights: func() ([]*insights.ChannelInfo, error) {
|
||||
return nil, nil
|
||||
},
|
||||
MinMonitored: 0,
|
||||
expectedErr: errZeroMinMonitored,
|
||||
},
|
||||
{
|
||||
name: "enough channels",
|
||||
OpenChannels: func() ([]*lnrpc.Channel, error) {
|
||||
return []*lnrpc.Channel{
|
||||
name: "enough channels",
|
||||
upperOutlier: false,
|
||||
metric: UptimeMetric,
|
||||
ChanInsights: func() ([]*insights.ChannelInfo, error) {
|
||||
return []*insights.ChannelInfo{
|
||||
{
|
||||
ChannelPoint: "a:1",
|
||||
Lifetime: hourSeconds,
|
||||
MonitoredFor: time.Hour,
|
||||
},
|
||||
{
|
||||
ChannelPoint: "b:2",
|
||||
Lifetime: hourSeconds,
|
||||
MonitoredFor: time.Hour,
|
||||
},
|
||||
{
|
||||
ChannelPoint: "c:3",
|
||||
Lifetime: hourSeconds,
|
||||
MonitoredFor: time.Hour,
|
||||
},
|
||||
}, nil
|
||||
},
|
||||
|
|
@ -79,13 +95,24 @@ func TestCloseRecommendations(t *testing.T) {
|
|||
t.Run(test.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
_, err := CloseRecommendations(
|
||||
recFunc := func(data dataset.Dataset) (
|
||||
m map[string]Recommendation, err error) {
|
||||
|
||||
return getOutlierRecs(
|
||||
data, DefaultOutlierMultiplier,
|
||||
test.upperOutlier,
|
||||
)
|
||||
}
|
||||
|
||||
_, err := closeRecommendations(
|
||||
&CloseRecommendationConfig{
|
||||
OpenChannels: test.OpenChannels,
|
||||
OutlierMultiplier: 3,
|
||||
MinimumMonitored: test.MinMonitored,
|
||||
ChannelInsights: test.ChanInsights,
|
||||
MinimumMonitored: test.MinMonitored,
|
||||
Metric: test.metric,
|
||||
},
|
||||
recFunc,
|
||||
)
|
||||
|
||||
if err != test.expectedErr {
|
||||
t.Fatalf("expected: %v, got: %v",
|
||||
test.expectedErr, err)
|
||||
|
|
@ -94,19 +121,21 @@ func TestCloseRecommendations(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// TestGetCloseRecs tests the generating of close recommendations for a set of
|
||||
// channels. It also contains a test case for when there are too few channels
|
||||
// to calculate outliers, to test that the error is silenced and no
|
||||
// recommendations are provided.
|
||||
func TestGetCloseRecs(t *testing.T) {
|
||||
// TestOutlierRecommendations tests the generating of close recommendations
|
||||
// for a set of channels based on whether they are outliers. It also contains
|
||||
// a test case for when there are too few channels to calculate outliers, to
|
||||
// test that the error is silenced and no recommendations are provided.
|
||||
func TestOutlierRecommendations(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
upperOutlier bool
|
||||
channelUptimes map[string]float64
|
||||
expectedRecs map[string]Recommendation
|
||||
outlierMultiplier float64
|
||||
}{
|
||||
{
|
||||
name: "not enough values, all false",
|
||||
name: "not enough values, all false",
|
||||
upperOutlier: false,
|
||||
channelUptimes: map[string]float64{
|
||||
"a:0": 0.7,
|
||||
},
|
||||
|
|
@ -119,7 +148,9 @@ func TestGetCloseRecs(t *testing.T) {
|
|||
outlierMultiplier: 2,
|
||||
},
|
||||
{
|
||||
name: "similar values, weak outlier no recommendations",
|
||||
name: "similar values, weak outlier no " +
|
||||
"recommendations",
|
||||
upperOutlier: false,
|
||||
channelUptimes: map[string]float64{
|
||||
"a:0": 0.7,
|
||||
"a:1": 0.6,
|
||||
|
|
@ -133,7 +164,9 @@ func TestGetCloseRecs(t *testing.T) {
|
|||
},
|
||||
},
|
||||
{
|
||||
name: "similar values, strong outlier no recommendations",
|
||||
name: "similar values, strong outlier no " +
|
||||
"make linrecommendations",
|
||||
upperOutlier: false,
|
||||
channelUptimes: map[string]float64{
|
||||
"a:0": 0.7,
|
||||
"a:1": 0.6,
|
||||
|
|
@ -147,7 +180,8 @@ func TestGetCloseRecs(t *testing.T) {
|
|||
},
|
||||
},
|
||||
{
|
||||
name: "lower outlier recommended for close",
|
||||
name: "lower outlier recommended for close",
|
||||
upperOutlier: false,
|
||||
channelUptimes: map[string]float64{
|
||||
"a:0": 0.6,
|
||||
"a:1": 0.6,
|
||||
|
|
@ -166,7 +200,27 @@ func TestGetCloseRecs(t *testing.T) {
|
|||
"a:5": {Value: 0.1, RecommendClose: true},
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
name: "upper outlier recommended for close",
|
||||
upperOutlier: true,
|
||||
channelUptimes: map[string]float64{
|
||||
"a:0": 0.9,
|
||||
"a:1": 0.2,
|
||||
"a:2": 0.2,
|
||||
"a:3": 0.2,
|
||||
"a:4": 0.1,
|
||||
"a:5": 0.1,
|
||||
},
|
||||
outlierMultiplier: 3,
|
||||
expectedRecs: map[string]Recommendation{
|
||||
"a:0": {Value: 0.9, RecommendClose: true},
|
||||
"a:1": {Value: 0.2, RecommendClose: false},
|
||||
"a:2": {Value: 0.2, RecommendClose: false},
|
||||
"a:3": {Value: 0.2, RecommendClose: false},
|
||||
"a:4": {Value: 0.1, RecommendClose: false},
|
||||
"a:5": {Value: 0.1, RecommendClose: false},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "zero multiplier replaced with default",
|
||||
channelUptimes: map[string]float64{
|
||||
|
|
@ -199,6 +253,7 @@ func TestGetCloseRecs(t *testing.T) {
|
|||
|
||||
recs, err := getOutlierRecs(
|
||||
uptimeData, test.outlierMultiplier,
|
||||
test.upperOutlier,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
|
|
@ -225,48 +280,54 @@ func TestGetCloseRecs(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// TestFilterChannels tests filtering of channels based on their lifetime.
|
||||
func TestFilterChannels(t *testing.T) {
|
||||
openChannels := []*lnrpc.Channel{
|
||||
{
|
||||
ChannelPoint: "a:0",
|
||||
Lifetime: 10,
|
||||
Uptime: 1,
|
||||
},
|
||||
{
|
||||
ChannelPoint: "a:1",
|
||||
Lifetime: 100,
|
||||
Uptime: 1,
|
||||
},
|
||||
{
|
||||
ChannelPoint: "a:2",
|
||||
Lifetime: 100,
|
||||
Uptime: 1,
|
||||
},
|
||||
{
|
||||
ChannelPoint: "a:3",
|
||||
Lifetime: 100,
|
||||
Uptime: 1,
|
||||
},
|
||||
}
|
||||
|
||||
// TestThresholdRecommendations tests getting of recommendations above and
|
||||
// below a threshold.
|
||||
func TestThresholdRecommendations(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
openChannels []*lnrpc.Channel
|
||||
minAge time.Duration
|
||||
expectedChanPoints []string
|
||||
name string
|
||||
belowThreshold bool
|
||||
threshold float64
|
||||
values map[string]float64
|
||||
expectedRecs map[string]Recommendation
|
||||
}{
|
||||
{
|
||||
name: "one filtered - monitored time",
|
||||
openChannels: openChannels,
|
||||
minAge: time.Second * 15,
|
||||
expectedChanPoints: []string{"a:1", "a:2", "a:3"},
|
||||
name: "nothing below threshold",
|
||||
belowThreshold: true,
|
||||
threshold: 0.4,
|
||||
values: map[string]float64{
|
||||
"a:0": 0.8,
|
||||
"a:1": 0.6,
|
||||
},
|
||||
expectedRecs: map[string]Recommendation{
|
||||
"a:0": {Value: 0.8, RecommendClose: false},
|
||||
"a:1": {Value: 0.6, RecommendClose: false},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "all channels included",
|
||||
openChannels: openChannels,
|
||||
minAge: time.Second * 5,
|
||||
expectedChanPoints: []string{"a:0", "a:1", "a:2", "a:3"},
|
||||
name: "one below threshold",
|
||||
belowThreshold: true,
|
||||
threshold: 0.7,
|
||||
values: map[string]float64{
|
||||
"a:0": 0.8,
|
||||
"a:1": 0.6,
|
||||
},
|
||||
expectedRecs: map[string]Recommendation{
|
||||
"a:0": {Value: 0.8, RecommendClose: false},
|
||||
"a:1": {Value: 0.6, RecommendClose: true},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "one above threshold",
|
||||
belowThreshold: false,
|
||||
threshold: 0.7,
|
||||
values: map[string]float64{
|
||||
"a:0": 0.8,
|
||||
"a:1": 0.6,
|
||||
},
|
||||
expectedRecs: map[string]Recommendation{
|
||||
"a:0": {Value: 0.8, RecommendClose: true},
|
||||
"a:1": {Value: 0.6, RecommendClose: false},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -276,18 +337,209 @@ func TestFilterChannels(t *testing.T) {
|
|||
t.Run(test.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
filtered := filterChannels(test.openChannels, test.minAge)
|
||||
recs := getThresholdRecs(
|
||||
dataset.New(test.values), test.threshold,
|
||||
test.belowThreshold,
|
||||
)
|
||||
|
||||
if len(test.expectedChanPoints) != len(filtered) {
|
||||
t.Fatalf("expected: %v channels, got: %v",
|
||||
len(test.expectedChanPoints),
|
||||
len(filtered))
|
||||
if len(test.expectedRecs) != len(recs) {
|
||||
t.Fatalf("expected: %v recommendations, "+
|
||||
"got: %v", len(test.expectedRecs),
|
||||
len(recs))
|
||||
}
|
||||
|
||||
for _, expected := range test.expectedChanPoints {
|
||||
if _, ok := filtered[expected]; !ok {
|
||||
t.Fatalf("expected channel: %v to "+
|
||||
"be present", expected)
|
||||
// Run through our expected set of true recommendations
|
||||
// and check that they match the set returned in the
|
||||
// report.
|
||||
for channel, expectClose := range test.expectedRecs {
|
||||
recClose := recs[channel]
|
||||
if recClose != expectClose {
|
||||
t.Fatalf("expected close rec: %v"+
|
||||
" for channel: %v, got: %v",
|
||||
expectClose, channel, recClose)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestFilterChannels tests filtering of channels based on their lifetime.
|
||||
func TestFilterChannels(t *testing.T) {
|
||||
chanInsights := []*insights.ChannelInfo{
|
||||
{
|
||||
ChannelPoint: "a:0",
|
||||
MonitoredFor: 10,
|
||||
Uptime: 1,
|
||||
},
|
||||
{
|
||||
ChannelPoint: "a:1",
|
||||
MonitoredFor: 100,
|
||||
Uptime: 1,
|
||||
},
|
||||
{
|
||||
ChannelPoint: "a:2",
|
||||
MonitoredFor: 100,
|
||||
Uptime: 1,
|
||||
},
|
||||
{
|
||||
ChannelPoint: "a:3",
|
||||
MonitoredFor: 100,
|
||||
Uptime: 1,
|
||||
},
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
chanInsights []*insights.ChannelInfo
|
||||
minAge time.Duration
|
||||
expectedChannels map[string]bool
|
||||
}{
|
||||
{
|
||||
name: "one filtered - monitored time",
|
||||
chanInsights: chanInsights,
|
||||
minAge: 15,
|
||||
expectedChannels: map[string]bool{
|
||||
"a:1": true,
|
||||
"a:2": true,
|
||||
"a:3": true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "all channels included",
|
||||
chanInsights: chanInsights,
|
||||
minAge: 5,
|
||||
expectedChannels: map[string]bool{
|
||||
"a:0": true,
|
||||
"a:1": true,
|
||||
"a:2": true,
|
||||
"a:3": true,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
test := test
|
||||
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
filtered := filterChannels(test.chanInsights, test.minAge)
|
||||
|
||||
if len(test.expectedChannels) != len(filtered) {
|
||||
t.Fatalf("expected: %v channels, got: %v",
|
||||
len(test.expectedChannels),
|
||||
len(filtered))
|
||||
}
|
||||
|
||||
for _, filteredChan := range filtered {
|
||||
_, ok := test.expectedChannels[filteredChan.ChannelPoint]
|
||||
if !ok {
|
||||
t.Fatalf("unexpected channel: %v",
|
||||
filteredChan)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestGetConfirmationScaledDataset tests scaling of data by the number of
|
||||
// confirmations that a channel has.
|
||||
func TestGetConfirmationScaledDataset(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
insights []*insights.ChannelInfo
|
||||
getValue perConfirmationValue
|
||||
expectedValues map[string]float64
|
||||
}{
|
||||
{
|
||||
name: "no channels",
|
||||
getValue: revenueValue,
|
||||
insights: []*insights.ChannelInfo{},
|
||||
},
|
||||
{
|
||||
name: "revenue scaled",
|
||||
getValue: revenueValue,
|
||||
insights: []*insights.ChannelInfo{
|
||||
{
|
||||
ChannelPoint: "a:0",
|
||||
FeesEarned: 7,
|
||||
Confirmations: 2,
|
||||
},
|
||||
{
|
||||
ChannelPoint: "a:1",
|
||||
FeesEarned: 10,
|
||||
Confirmations: 1,
|
||||
},
|
||||
},
|
||||
expectedValues: map[string]float64{
|
||||
"a:0": 3.5,
|
||||
"a:1": 10,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "total volume",
|
||||
getValue: totalVolumeValue,
|
||||
insights: []*insights.ChannelInfo{
|
||||
{
|
||||
ChannelPoint: "a:0",
|
||||
VolumeIncoming: 10,
|
||||
VolumeOutgoing: 2,
|
||||
Confirmations: 2,
|
||||
},
|
||||
},
|
||||
expectedValues: map[string]float64{
|
||||
"a:0": 6,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "incoming volume",
|
||||
getValue: incomingVolumeValue,
|
||||
insights: []*insights.ChannelInfo{
|
||||
{
|
||||
ChannelPoint: "a:0",
|
||||
VolumeIncoming: 10,
|
||||
VolumeOutgoing: 2,
|
||||
Confirmations: 2,
|
||||
},
|
||||
},
|
||||
expectedValues: map[string]float64{
|
||||
"a:0": 5,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "outgoing volume",
|
||||
getValue: outgoingVolumeValue,
|
||||
insights: []*insights.ChannelInfo{
|
||||
{
|
||||
ChannelPoint: "a:0",
|
||||
VolumeIncoming: 10,
|
||||
VolumeOutgoing: 2,
|
||||
Confirmations: 2,
|
||||
},
|
||||
},
|
||||
expectedValues: map[string]float64{
|
||||
"a:0": 1,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
test := test
|
||||
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
data := getConfirmationScaledDataset(
|
||||
test.getValue, test.insights,
|
||||
)
|
||||
if len(data) != len(test.expectedValues) {
|
||||
t.Fatalf("expected: %v, got: %v",
|
||||
len(test.expectedValues), len(data))
|
||||
}
|
||||
|
||||
for chanPoint, value := range test.expectedValues {
|
||||
if data.Value(chanPoint) != value {
|
||||
t.Fatalf("expected: %v to "+
|
||||
"have value %v, got %v", chanPoint,
|
||||
value, data.Value(chanPoint))
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -2,49 +2,87 @@ package trmrpc
|
|||
|
||||
import (
|
||||
"context"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"github.com/lightninglabs/terminator/insights"
|
||||
"github.com/lightninglabs/terminator/recommend"
|
||||
)
|
||||
|
||||
// parseRequest parses a rpc close recommendation request and returns the
|
||||
// close recommendation config that the request requires.
|
||||
func parseRequest(ctx context.Context, cfg *Config,
|
||||
req *CloseRecommendationsRequest) *recommend.CloseRecommendationConfig {
|
||||
// parseRecommendationRequest parses a close recommendation request and
|
||||
// returns the config required to get recommendations.
|
||||
func parseRecommendationRequest(ctx context.Context, cfg *Config,
|
||||
req *CloseRecommendationRequest) *recommend.CloseRecommendationConfig {
|
||||
|
||||
// Create a close recommendations config with the minimum monitored
|
||||
// value provided in the request and the default outlier multiplier.
|
||||
recConfig := &recommend.CloseRecommendationConfig{
|
||||
OpenChannels: cfg.wrapListChannels(ctx, true),
|
||||
recCfg := &recommend.CloseRecommendationConfig{
|
||||
ChannelInsights: func() ([]*insights.ChannelInfo, error) {
|
||||
return channelInsights(ctx, cfg)
|
||||
},
|
||||
MinimumMonitored: time.Second *
|
||||
time.Duration(req.MinimumMonitored),
|
||||
OutlierMultiplier: recommend.DefaultOutlierMultiplier,
|
||||
}
|
||||
|
||||
// If a non-zero outlier multiple was provided, set it on the config.
|
||||
if req.OutlierMultiplier != 0 {
|
||||
recConfig.OutlierMultiplier = float64(req.OutlierMultiplier)
|
||||
// Get the metric that the recommendations are being calculated based
|
||||
// on.
|
||||
switch req.Metric {
|
||||
case CloseRecommendationRequest_UPTIME:
|
||||
recCfg.Metric = recommend.UptimeMetric
|
||||
|
||||
case CloseRecommendationRequest_REVENUE:
|
||||
recCfg.Metric = recommend.RevenueMetric
|
||||
|
||||
case CloseRecommendationRequest_INCOMING_VOLUME:
|
||||
recCfg.Metric = recommend.IncomingVolume
|
||||
|
||||
case CloseRecommendationRequest_OUTGOING_VOLUME:
|
||||
recCfg.Metric = recommend.OutgoingVolume
|
||||
|
||||
case CloseRecommendationRequest_TOTAL_VOLUME:
|
||||
recCfg.Metric = recommend.Volume
|
||||
}
|
||||
|
||||
threshold, ok := req.Threshold.(*CloseRecommendationsRequest_UptimeThreshold)
|
||||
if ok {
|
||||
recConfig.UptimeThreshold = float64(threshold.UptimeThreshold)
|
||||
}
|
||||
|
||||
return recConfig
|
||||
return recCfg
|
||||
}
|
||||
|
||||
// parseResponse parses the response obtained getting a close recommendation
|
||||
// parseOutlierRequest parses a rpc outlier recommendation request and returns
|
||||
// the close recommendation config and multiplier required.
|
||||
func parseOutlierRequest(ctx context.Context, cfg *Config,
|
||||
req *OutlierRecommendationsRequest) (
|
||||
*recommend.CloseRecommendationConfig, float64) {
|
||||
|
||||
multiplier := recommend.DefaultOutlierMultiplier
|
||||
if req.OutlierMultiplier != 0 {
|
||||
multiplier = float64(req.OutlierMultiplier)
|
||||
}
|
||||
|
||||
return parseRecommendationRequest(ctx, cfg, req.RecRequest), multiplier
|
||||
}
|
||||
|
||||
// parseThresholdRequest parses a rpc threshold recommendation request and
|
||||
// returns the close recommendation config and threshold required. The above
|
||||
// threshold boolean is inverted to allow for
|
||||
// a default that returns values below a threshold.
|
||||
func parseThresholdRequest(ctx context.Context, cfg *Config,
|
||||
req *ThresholdRecommendationsRequest) (
|
||||
*recommend.CloseRecommendationConfig, float64) {
|
||||
|
||||
return parseRecommendationRequest(ctx, cfg, req.RecRequest),
|
||||
float64(req.ThresholdValue)
|
||||
}
|
||||
|
||||
// rpcResponse parses the response obtained getting a close recommendation
|
||||
// and converts it to a close recommendation response.
|
||||
func parseResponse(report *recommend.Report) *CloseRecommendationsResponse {
|
||||
func rpcResponse(report *recommend.Report) *CloseRecommendationsResponse {
|
||||
resp := &CloseRecommendationsResponse{
|
||||
TotalChannels: int32(report.TotalChannels),
|
||||
ConsideredChannels: int32(report.ConsideredChannels),
|
||||
}
|
||||
|
||||
for chanPoint, rec := range report.OutlierRecommendations {
|
||||
resp.OutlierRecommendations = append(
|
||||
resp.OutlierRecommendations, &Recommendation{
|
||||
for chanPoint, rec := range report.Recommendations {
|
||||
resp.Recommendations = append(
|
||||
resp.Recommendations, &Recommendation{
|
||||
ChanPoint: chanPoint,
|
||||
Value: float32(rec.Value),
|
||||
RecommendClose: rec.RecommendClose,
|
||||
|
|
@ -52,15 +90,11 @@ func parseResponse(report *recommend.Report) *CloseRecommendationsResponse {
|
|||
)
|
||||
}
|
||||
|
||||
for chanPoint, rec := range report.ThresholdRecommendations {
|
||||
resp.ThresholdRecommendations = append(
|
||||
resp.ThresholdRecommendations, &Recommendation{
|
||||
ChanPoint: chanPoint,
|
||||
Value: float32(rec.Value),
|
||||
RecommendClose: rec.RecommendClose,
|
||||
},
|
||||
)
|
||||
}
|
||||
// Sort the recommendations returned by value.
|
||||
sort.SliceStable(resp.Recommendations, func(i, j int) bool {
|
||||
return resp.Recommendations[i].Value <
|
||||
resp.Recommendations[j].Value
|
||||
})
|
||||
|
||||
return resp
|
||||
}
|
||||
|
|
|
|||
454
trmrpc/rpc.pb.go
454
trmrpc/rpc.pb.go
|
|
@ -23,101 +23,228 @@ var _ = math.Inf
|
|||
// proto package needs to be updated.
|
||||
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
|
||||
|
||||
type CloseRecommendationsRequest struct {
|
||||
type CloseRecommendationRequest_Metric int32
|
||||
|
||||
const (
|
||||
CloseRecommendationRequest_UNKNOWN CloseRecommendationRequest_Metric = 0
|
||||
CloseRecommendationRequest_UPTIME CloseRecommendationRequest_Metric = 1
|
||||
CloseRecommendationRequest_REVENUE CloseRecommendationRequest_Metric = 2
|
||||
CloseRecommendationRequest_INCOMING_VOLUME CloseRecommendationRequest_Metric = 3
|
||||
CloseRecommendationRequest_OUTGOING_VOLUME CloseRecommendationRequest_Metric = 4
|
||||
CloseRecommendationRequest_TOTAL_VOLUME CloseRecommendationRequest_Metric = 5
|
||||
)
|
||||
|
||||
var CloseRecommendationRequest_Metric_name = map[int32]string{
|
||||
0: "UNKNOWN",
|
||||
1: "UPTIME",
|
||||
2: "REVENUE",
|
||||
3: "INCOMING_VOLUME",
|
||||
4: "OUTGOING_VOLUME",
|
||||
5: "TOTAL_VOLUME",
|
||||
}
|
||||
|
||||
var CloseRecommendationRequest_Metric_value = map[string]int32{
|
||||
"UNKNOWN": 0,
|
||||
"UPTIME": 1,
|
||||
"REVENUE": 2,
|
||||
"INCOMING_VOLUME": 3,
|
||||
"OUTGOING_VOLUME": 4,
|
||||
"TOTAL_VOLUME": 5,
|
||||
}
|
||||
|
||||
func (x CloseRecommendationRequest_Metric) String() string {
|
||||
return proto.EnumName(CloseRecommendationRequest_Metric_name, int32(x))
|
||||
}
|
||||
|
||||
func (CloseRecommendationRequest_Metric) EnumDescriptor() ([]byte, []int) {
|
||||
return fileDescriptor_77a6da22d6a3feb1, []int{0, 0}
|
||||
}
|
||||
|
||||
type CloseRecommendationRequest struct {
|
||||
//
|
||||
//The minimum amount of time in seconds that a channel should have been
|
||||
//monitored by lnd to be eligible for close. This value is in place to
|
||||
//protect against closing of newer channels.
|
||||
MinimumMonitored int64 `protobuf:"varint,1,opt,name=minimum_monitored,json=minimumMonitored,proto3" json:"minimum_monitored,omitempty"`
|
||||
//
|
||||
//The number of inter-quartile ranges a value needs to be beneath the lower
|
||||
//quartile/ above the upper quartile to be considered a lower/upper outlier.
|
||||
//Lower values will be more aggressive in recommending channel closes, and
|
||||
//upper values will be more conservative. Recommended values are 1.5 for
|
||||
//aggressive recommendations and 3 for conservative recommendations.
|
||||
OutlierMultiplier float32 `protobuf:"fixed32,2,opt,name=outlier_multiplier,json=outlierMultiplier,proto3" json:"outlier_multiplier,omitempty"`
|
||||
//
|
||||
//Threshold contains the threshold value that is used to recommend channels
|
||||
//for closure.
|
||||
//
|
||||
// Types that are valid to be assigned to Threshold:
|
||||
// *CloseRecommendationsRequest_UptimeThreshold
|
||||
Threshold isCloseRecommendationsRequest_Threshold `protobuf_oneof:"threshold"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
//The data point base close recommendations on. Available options are:
|
||||
//Uptime: ratio of channel peer's uptime to the period they have been
|
||||
//monitored to.
|
||||
//Revenue: the revenue that the channel has produced per block that its
|
||||
//funding transaction has been confirmed for.
|
||||
Metric CloseRecommendationRequest_Metric `protobuf:"varint,2,opt,name=metric,proto3,enum=trmrpc.CloseRecommendationRequest_Metric" json:"metric,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *CloseRecommendationsRequest) Reset() { *m = CloseRecommendationsRequest{} }
|
||||
func (m *CloseRecommendationsRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*CloseRecommendationsRequest) ProtoMessage() {}
|
||||
func (*CloseRecommendationsRequest) Descriptor() ([]byte, []int) {
|
||||
func (m *CloseRecommendationRequest) Reset() { *m = CloseRecommendationRequest{} }
|
||||
func (m *CloseRecommendationRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*CloseRecommendationRequest) ProtoMessage() {}
|
||||
func (*CloseRecommendationRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_77a6da22d6a3feb1, []int{0}
|
||||
}
|
||||
|
||||
func (m *CloseRecommendationsRequest) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_CloseRecommendationsRequest.Unmarshal(m, b)
|
||||
func (m *CloseRecommendationRequest) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_CloseRecommendationRequest.Unmarshal(m, b)
|
||||
}
|
||||
func (m *CloseRecommendationsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_CloseRecommendationsRequest.Marshal(b, m, deterministic)
|
||||
func (m *CloseRecommendationRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_CloseRecommendationRequest.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *CloseRecommendationsRequest) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_CloseRecommendationsRequest.Merge(m, src)
|
||||
func (m *CloseRecommendationRequest) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_CloseRecommendationRequest.Merge(m, src)
|
||||
}
|
||||
func (m *CloseRecommendationsRequest) XXX_Size() int {
|
||||
return xxx_messageInfo_CloseRecommendationsRequest.Size(m)
|
||||
func (m *CloseRecommendationRequest) XXX_Size() int {
|
||||
return xxx_messageInfo_CloseRecommendationRequest.Size(m)
|
||||
}
|
||||
func (m *CloseRecommendationsRequest) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_CloseRecommendationsRequest.DiscardUnknown(m)
|
||||
func (m *CloseRecommendationRequest) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_CloseRecommendationRequest.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_CloseRecommendationsRequest proto.InternalMessageInfo
|
||||
var xxx_messageInfo_CloseRecommendationRequest proto.InternalMessageInfo
|
||||
|
||||
func (m *CloseRecommendationsRequest) GetMinimumMonitored() int64 {
|
||||
func (m *CloseRecommendationRequest) GetMinimumMonitored() int64 {
|
||||
if m != nil {
|
||||
return m.MinimumMonitored
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *CloseRecommendationsRequest) GetOutlierMultiplier() float32 {
|
||||
func (m *CloseRecommendationRequest) GetMetric() CloseRecommendationRequest_Metric {
|
||||
if m != nil {
|
||||
return m.Metric
|
||||
}
|
||||
return CloseRecommendationRequest_UNKNOWN
|
||||
}
|
||||
|
||||
type OutlierRecommendationsRequest struct {
|
||||
//
|
||||
//The parameters that are common to all close recommendations.
|
||||
RecRequest *CloseRecommendationRequest `protobuf:"bytes,1,opt,name=rec_request,json=recRequest,proto3" json:"rec_request,omitempty"`
|
||||
//
|
||||
//The number of inter-quartile ranges a value needs to be beneath the lower
|
||||
//quartile/ above the upper quartile to be considered a lower/upper outlier.
|
||||
//Lower values will be more aggressive in recommending channel closes, and
|
||||
//upper values will be more conservative. Recommended values are 1.5 for
|
||||
//aggressive recommendations and 3 for conservative recommendations.
|
||||
OutlierMultiplier float32 `protobuf:"fixed32,2,opt,name=outlier_multiplier,json=outlierMultiplier,proto3" json:"outlier_multiplier,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *OutlierRecommendationsRequest) Reset() { *m = OutlierRecommendationsRequest{} }
|
||||
func (m *OutlierRecommendationsRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*OutlierRecommendationsRequest) ProtoMessage() {}
|
||||
func (*OutlierRecommendationsRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_77a6da22d6a3feb1, []int{1}
|
||||
}
|
||||
|
||||
func (m *OutlierRecommendationsRequest) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_OutlierRecommendationsRequest.Unmarshal(m, b)
|
||||
}
|
||||
func (m *OutlierRecommendationsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_OutlierRecommendationsRequest.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *OutlierRecommendationsRequest) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_OutlierRecommendationsRequest.Merge(m, src)
|
||||
}
|
||||
func (m *OutlierRecommendationsRequest) XXX_Size() int {
|
||||
return xxx_messageInfo_OutlierRecommendationsRequest.Size(m)
|
||||
}
|
||||
func (m *OutlierRecommendationsRequest) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_OutlierRecommendationsRequest.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_OutlierRecommendationsRequest proto.InternalMessageInfo
|
||||
|
||||
func (m *OutlierRecommendationsRequest) GetRecRequest() *CloseRecommendationRequest {
|
||||
if m != nil {
|
||||
return m.RecRequest
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *OutlierRecommendationsRequest) GetOutlierMultiplier() float32 {
|
||||
if m != nil {
|
||||
return m.OutlierMultiplier
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type isCloseRecommendationsRequest_Threshold interface {
|
||||
isCloseRecommendationsRequest_Threshold()
|
||||
type ThresholdRecommendationsRequest struct {
|
||||
//
|
||||
//The parameters that are common to all close recommendations.
|
||||
RecRequest *CloseRecommendationRequest `protobuf:"bytes,1,opt,name=rec_request,json=recRequest,proto3" json:"rec_request,omitempty"`
|
||||
//
|
||||
//The threshold that recommendations will be calculated based on.
|
||||
//For uptime: ratio of uptime to observed lifetime beneath which channels
|
||||
//will be recommended for closure.
|
||||
//
|
||||
//For revenue: revenue per block that capital has been committed to the
|
||||
//channel beneath which channels will be recommended for closure. This
|
||||
//value is provided per block so that channels that have been open for
|
||||
//different periods of time can be compared.
|
||||
//
|
||||
//For incoming volume: The incoming volume per block that capital has
|
||||
//been committed to the channel beneath which channels will be recommended
|
||||
//for closure. This value is provided per block so that channels that have
|
||||
//been open for different periods of time can be compared.
|
||||
//
|
||||
//For outgoing volume: The outgoing volume per block that capital has been
|
||||
//committed to the channel beneath which channels will be recommended for
|
||||
//closure. This value is provided per block so that channels that have been
|
||||
//open for different periods of time can be compared.
|
||||
//
|
||||
//For total volume: The total volume per block that capital has been
|
||||
//committed to the channel beneath which channels will be recommended for
|
||||
//closure. This value is provided per block so that channels that have been
|
||||
//open for different periods of time can be compared.
|
||||
ThresholdValue float32 `protobuf:"fixed32,2,opt,name=threshold_value,json=thresholdValue,proto3" json:"threshold_value,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
type CloseRecommendationsRequest_UptimeThreshold struct {
|
||||
UptimeThreshold float32 `protobuf:"fixed32,3,opt,name=uptime_threshold,json=uptimeThreshold,proto3,oneof"`
|
||||
func (m *ThresholdRecommendationsRequest) Reset() { *m = ThresholdRecommendationsRequest{} }
|
||||
func (m *ThresholdRecommendationsRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*ThresholdRecommendationsRequest) ProtoMessage() {}
|
||||
func (*ThresholdRecommendationsRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_77a6da22d6a3feb1, []int{2}
|
||||
}
|
||||
|
||||
func (*CloseRecommendationsRequest_UptimeThreshold) isCloseRecommendationsRequest_Threshold() {}
|
||||
func (m *ThresholdRecommendationsRequest) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_ThresholdRecommendationsRequest.Unmarshal(m, b)
|
||||
}
|
||||
func (m *ThresholdRecommendationsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_ThresholdRecommendationsRequest.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *ThresholdRecommendationsRequest) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_ThresholdRecommendationsRequest.Merge(m, src)
|
||||
}
|
||||
func (m *ThresholdRecommendationsRequest) XXX_Size() int {
|
||||
return xxx_messageInfo_ThresholdRecommendationsRequest.Size(m)
|
||||
}
|
||||
func (m *ThresholdRecommendationsRequest) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_ThresholdRecommendationsRequest.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
func (m *CloseRecommendationsRequest) GetThreshold() isCloseRecommendationsRequest_Threshold {
|
||||
var xxx_messageInfo_ThresholdRecommendationsRequest proto.InternalMessageInfo
|
||||
|
||||
func (m *ThresholdRecommendationsRequest) GetRecRequest() *CloseRecommendationRequest {
|
||||
if m != nil {
|
||||
return m.Threshold
|
||||
return m.RecRequest
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *CloseRecommendationsRequest) GetUptimeThreshold() float32 {
|
||||
if x, ok := m.GetThreshold().(*CloseRecommendationsRequest_UptimeThreshold); ok {
|
||||
return x.UptimeThreshold
|
||||
func (m *ThresholdRecommendationsRequest) GetThresholdValue() float32 {
|
||||
if m != nil {
|
||||
return m.ThresholdValue
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// XXX_OneofWrappers is for the internal use of the proto package.
|
||||
func (*CloseRecommendationsRequest) XXX_OneofWrappers() []interface{} {
|
||||
return []interface{}{
|
||||
(*CloseRecommendationsRequest_UptimeThreshold)(nil),
|
||||
}
|
||||
}
|
||||
|
||||
type CloseRecommendationsResponse struct {
|
||||
//
|
||||
//The total number of channels, before filtering out channels that are
|
||||
|
|
@ -127,29 +254,21 @@ type CloseRecommendationsResponse struct {
|
|||
//The number of channels that were considered for close recommendations.
|
||||
ConsideredChannels int32 `protobuf:"varint,2,opt,name=considered_channels,json=consideredChannels,proto3" json:"considered_channels,omitempty"`
|
||||
//
|
||||
//A map of channels to close recommendations, based out whether they are
|
||||
//outliers in the uptime dataset. The absence of a channel in this set
|
||||
//implies that it was not considered for close because it did not meet
|
||||
//the criteria for close (it is private, or has not been monitored for
|
||||
//long enough to make a decision).
|
||||
OutlierRecommendations []*Recommendation `protobuf:"bytes,3,rep,name=outlier_recommendations,json=outlierRecommendations,proto3" json:"outlier_recommendations,omitempty"`
|
||||
//
|
||||
//A set of channel close recommendations, based out whether they are
|
||||
//beneath the threshold provided in the request. The absence of a channel
|
||||
//in this set implies that it was not considered for close because it
|
||||
//did not meet the criteria for close (it is private, or has not been
|
||||
//monitored for long enough to make a decision).
|
||||
ThresholdRecommendations []*Recommendation `protobuf:"bytes,4,rep,name=threshold_recommendations,json=thresholdRecommendations,proto3" json:"threshold_recommendations,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
//A set of channel close recommendations. The absence of a channel in this
|
||||
//set implies that it was not considered for close because it did not meet
|
||||
//the criteria for close recommendations (it is private, or has not been
|
||||
//monitored for long enough).
|
||||
Recommendations []*Recommendation `protobuf:"bytes,3,rep,name=recommendations,proto3" json:"recommendations,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *CloseRecommendationsResponse) Reset() { *m = CloseRecommendationsResponse{} }
|
||||
func (m *CloseRecommendationsResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*CloseRecommendationsResponse) ProtoMessage() {}
|
||||
func (*CloseRecommendationsResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_77a6da22d6a3feb1, []int{1}
|
||||
return fileDescriptor_77a6da22d6a3feb1, []int{3}
|
||||
}
|
||||
|
||||
func (m *CloseRecommendationsResponse) XXX_Unmarshal(b []byte) error {
|
||||
|
|
@ -184,16 +303,9 @@ func (m *CloseRecommendationsResponse) GetConsideredChannels() int32 {
|
|||
return 0
|
||||
}
|
||||
|
||||
func (m *CloseRecommendationsResponse) GetOutlierRecommendations() []*Recommendation {
|
||||
func (m *CloseRecommendationsResponse) GetRecommendations() []*Recommendation {
|
||||
if m != nil {
|
||||
return m.OutlierRecommendations
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *CloseRecommendationsResponse) GetThresholdRecommendations() []*Recommendation {
|
||||
if m != nil {
|
||||
return m.ThresholdRecommendations
|
||||
return m.Recommendations
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
@ -216,7 +328,7 @@ func (m *Recommendation) Reset() { *m = Recommendation{} }
|
|||
func (m *Recommendation) String() string { return proto.CompactTextString(m) }
|
||||
func (*Recommendation) ProtoMessage() {}
|
||||
func (*Recommendation) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_77a6da22d6a3feb1, []int{2}
|
||||
return fileDescriptor_77a6da22d6a3feb1, []int{4}
|
||||
}
|
||||
|
||||
func (m *Recommendation) XXX_Unmarshal(b []byte) error {
|
||||
|
|
@ -282,7 +394,7 @@ func (m *RevenueReportRequest) Reset() { *m = RevenueReportRequest{} }
|
|||
func (m *RevenueReportRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*RevenueReportRequest) ProtoMessage() {}
|
||||
func (*RevenueReportRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_77a6da22d6a3feb1, []int{3}
|
||||
return fileDescriptor_77a6da22d6a3feb1, []int{5}
|
||||
}
|
||||
|
||||
func (m *RevenueReportRequest) XXX_Unmarshal(b []byte) error {
|
||||
|
|
@ -338,7 +450,7 @@ func (m *RevenueReportResponse) Reset() { *m = RevenueReportResponse{} }
|
|||
func (m *RevenueReportResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*RevenueReportResponse) ProtoMessage() {}
|
||||
func (*RevenueReportResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_77a6da22d6a3feb1, []int{4}
|
||||
return fileDescriptor_77a6da22d6a3feb1, []int{6}
|
||||
}
|
||||
|
||||
func (m *RevenueReportResponse) XXX_Unmarshal(b []byte) error {
|
||||
|
|
@ -386,7 +498,7 @@ func (m *RevenueReport) Reset() { *m = RevenueReport{} }
|
|||
func (m *RevenueReport) String() string { return proto.CompactTextString(m) }
|
||||
func (*RevenueReport) ProtoMessage() {}
|
||||
func (*RevenueReport) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_77a6da22d6a3feb1, []int{5}
|
||||
return fileDescriptor_77a6da22d6a3feb1, []int{7}
|
||||
}
|
||||
|
||||
func (m *RevenueReport) XXX_Unmarshal(b []byte) error {
|
||||
|
|
@ -449,7 +561,7 @@ func (m *PairReport) Reset() { *m = PairReport{} }
|
|||
func (m *PairReport) String() string { return proto.CompactTextString(m) }
|
||||
func (*PairReport) ProtoMessage() {}
|
||||
func (*PairReport) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_77a6da22d6a3feb1, []int{6}
|
||||
return fileDescriptor_77a6da22d6a3feb1, []int{8}
|
||||
}
|
||||
|
||||
func (m *PairReport) XXX_Unmarshal(b []byte) error {
|
||||
|
|
@ -508,7 +620,7 @@ func (m *ChannelInsightsRequest) Reset() { *m = ChannelInsightsRequest{}
|
|||
func (m *ChannelInsightsRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*ChannelInsightsRequest) ProtoMessage() {}
|
||||
func (*ChannelInsightsRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_77a6da22d6a3feb1, []int{7}
|
||||
return fileDescriptor_77a6da22d6a3feb1, []int{9}
|
||||
}
|
||||
|
||||
func (m *ChannelInsightsRequest) XXX_Unmarshal(b []byte) error {
|
||||
|
|
@ -541,7 +653,7 @@ func (m *ChannelInsightsResponse) Reset() { *m = ChannelInsightsResponse
|
|||
func (m *ChannelInsightsResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*ChannelInsightsResponse) ProtoMessage() {}
|
||||
func (*ChannelInsightsResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_77a6da22d6a3feb1, []int{8}
|
||||
return fileDescriptor_77a6da22d6a3feb1, []int{10}
|
||||
}
|
||||
|
||||
func (m *ChannelInsightsResponse) XXX_Unmarshal(b []byte) error {
|
||||
|
|
@ -606,7 +718,7 @@ func (m *ChannelInsight) Reset() { *m = ChannelInsight{} }
|
|||
func (m *ChannelInsight) String() string { return proto.CompactTextString(m) }
|
||||
func (*ChannelInsight) ProtoMessage() {}
|
||||
func (*ChannelInsight) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_77a6da22d6a3feb1, []int{9}
|
||||
return fileDescriptor_77a6da22d6a3feb1, []int{11}
|
||||
}
|
||||
|
||||
func (m *ChannelInsight) XXX_Unmarshal(b []byte) error {
|
||||
|
|
@ -684,7 +796,10 @@ func (m *ChannelInsight) GetPrivate() bool {
|
|||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterType((*CloseRecommendationsRequest)(nil), "trmrpc.CloseRecommendationsRequest")
|
||||
proto.RegisterEnum("trmrpc.CloseRecommendationRequest_Metric", CloseRecommendationRequest_Metric_name, CloseRecommendationRequest_Metric_value)
|
||||
proto.RegisterType((*CloseRecommendationRequest)(nil), "trmrpc.CloseRecommendationRequest")
|
||||
proto.RegisterType((*OutlierRecommendationsRequest)(nil), "trmrpc.OutlierRecommendationsRequest")
|
||||
proto.RegisterType((*ThresholdRecommendationsRequest)(nil), "trmrpc.ThresholdRecommendationsRequest")
|
||||
proto.RegisterType((*CloseRecommendationsResponse)(nil), "trmrpc.CloseRecommendationsResponse")
|
||||
proto.RegisterType((*Recommendation)(nil), "trmrpc.Recommendation")
|
||||
proto.RegisterType((*RevenueReportRequest)(nil), "trmrpc.RevenueReportRequest")
|
||||
|
|
@ -700,58 +815,66 @@ func init() {
|
|||
func init() { proto.RegisterFile("rpc.proto", fileDescriptor_77a6da22d6a3feb1) }
|
||||
|
||||
var fileDescriptor_77a6da22d6a3feb1 = []byte{
|
||||
// 814 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x55, 0xcd, 0x6e, 0xdb, 0x46,
|
||||
0x10, 0xae, 0x28, 0xff, 0x69, 0x54, 0xc9, 0xca, 0x56, 0x71, 0x14, 0xd7, 0x69, 0x0c, 0x36, 0x6d,
|
||||
0x05, 0xa4, 0xb5, 0x03, 0xf7, 0x52, 0xf4, 0xd6, 0x06, 0x01, 0x62, 0xa0, 0x46, 0x82, 0xb5, 0x8f,
|
||||
0x05, 0x88, 0x2d, 0x35, 0x91, 0x17, 0xe5, 0xee, 0x32, 0xbb, 0x4b, 0x01, 0x79, 0x92, 0x5e, 0xfa,
|
||||
0x16, 0x7d, 0x8d, 0x5e, 0x7a, 0xe8, 0xfb, 0x14, 0xfb, 0x43, 0x52, 0x54, 0x64, 0xf7, 0x46, 0x7e,
|
||||
0xdf, 0xb7, 0x33, 0xc3, 0x99, 0x6f, 0x87, 0x30, 0xd0, 0x65, 0x7e, 0x56, 0x6a, 0x65, 0x15, 0xd9,
|
||||
0xb3, 0x5a, 0xe8, 0x32, 0x3f, 0x3e, 0x59, 0x2a, 0xb5, 0x2c, 0xf0, 0x9c, 0x95, 0xfc, 0x9c, 0x49,
|
||||
0xa9, 0x2c, 0xb3, 0x5c, 0x49, 0x13, 0x54, 0xe9, 0x5f, 0x3d, 0xf8, 0xfc, 0x65, 0xa1, 0x0c, 0x52,
|
||||
0xcc, 0x95, 0x10, 0x28, 0x17, 0x81, 0xa6, 0xf8, 0xbe, 0x42, 0x63, 0xc9, 0x73, 0x78, 0x20, 0xb8,
|
||||
0xe4, 0xa2, 0x12, 0x99, 0x50, 0x92, 0x5b, 0xa5, 0x71, 0x31, 0xeb, 0x9d, 0xf6, 0xe6, 0x7d, 0x3a,
|
||||
0x89, 0xc4, 0x55, 0x8d, 0x93, 0xef, 0x80, 0xa8, 0xca, 0x16, 0x1c, 0x75, 0x26, 0xaa, 0xc2, 0xf2,
|
||||
0xd2, 0x3d, 0xce, 0x92, 0xd3, 0xde, 0x3c, 0xa1, 0x0f, 0x22, 0x73, 0xd5, 0x10, 0xe4, 0x39, 0x4c,
|
||||
0xaa, 0xd2, 0x72, 0x81, 0x99, 0xbd, 0xd5, 0x68, 0x6e, 0x55, 0xb1, 0x98, 0xf5, 0x9d, 0xf8, 0xf5,
|
||||
0x27, 0xf4, 0x30, 0x30, 0x37, 0x35, 0xf1, 0xf3, 0x10, 0x06, 0x8d, 0x2a, 0xfd, 0x33, 0x81, 0x93,
|
||||
0xed, 0x55, 0x9b, 0x52, 0x49, 0x83, 0xe4, 0x2b, 0x18, 0x5b, 0x65, 0x59, 0x91, 0xe5, 0xb7, 0x4c,
|
||||
0x4a, 0x2c, 0x8c, 0xaf, 0x79, 0x97, 0x8e, 0x3c, 0xfa, 0x32, 0x82, 0xe4, 0x1c, 0x3e, 0xcb, 0x95,
|
||||
0x34, 0x7c, 0x81, 0x1a, 0x17, 0xad, 0x36, 0xf1, 0x5a, 0xd2, 0x52, 0xcd, 0x81, 0x37, 0xf0, 0xa8,
|
||||
0xfe, 0x42, 0xdd, 0x4d, 0x3d, 0xeb, 0x9f, 0xf6, 0xe7, 0xc3, 0x8b, 0xa3, 0xb3, 0xd0, 0xf6, 0xb3,
|
||||
0x6e, 0x65, 0xf4, 0x28, 0x1e, 0xdb, 0x28, 0x98, 0x5c, 0xc3, 0xe3, 0xe6, 0xb3, 0x3e, 0x0a, 0xb9,
|
||||
0x73, 0x6f, 0xc8, 0x59, 0x73, 0x70, 0x23, 0x68, 0x2a, 0x61, 0xdc, 0x85, 0xc8, 0x13, 0x00, 0xf7,
|
||||
0x75, 0x59, 0xa9, 0xb8, 0xb4, 0xbe, 0x17, 0x03, 0x3a, 0x70, 0xc8, 0x5b, 0x07, 0x90, 0x29, 0xec,
|
||||
0xae, 0x58, 0x51, 0x61, 0x9c, 0x55, 0x78, 0x21, 0xdf, 0xc0, 0x61, 0x53, 0x51, 0x96, 0xbb, 0x76,
|
||||
0xfb, 0xf1, 0x1c, 0xd0, 0x71, 0x03, 0xfb, 0x21, 0xa4, 0xef, 0x61, 0x4a, 0x71, 0x85, 0xb2, 0x42,
|
||||
0x8a, 0xa5, 0xd2, 0xb6, 0x36, 0xcf, 0x53, 0x18, 0xb6, 0x59, 0xdd, 0x08, 0xfa, 0xf3, 0x01, 0x85,
|
||||
0x26, 0xad, 0x71, 0x65, 0x19, 0xcb, 0xb4, 0xcd, 0xdc, 0xac, 0x7d, 0xf2, 0x1d, 0x3a, 0xf0, 0xc8,
|
||||
0x0d, 0x17, 0x48, 0x1e, 0xc3, 0x81, 0x4b, 0xed, 0xc9, 0xbe, 0x27, 0xf7, 0x51, 0x2e, 0x1c, 0x95,
|
||||
0xbe, 0x86, 0x87, 0x1b, 0x29, 0xe3, 0xe4, 0xcf, 0x61, 0x5f, 0x7b, 0x24, 0xe4, 0x1b, 0x5e, 0x3c,
|
||||
0x6c, 0xdb, 0xb7, 0xae, 0xaf, 0x55, 0xe9, 0xbf, 0x3d, 0x18, 0x75, 0x28, 0x6f, 0x1e, 0xa6, 0x97,
|
||||
0x68, 0x6b, 0x47, 0xc4, 0x86, 0x8d, 0x02, 0x1a, 0xcd, 0x40, 0x2e, 0xe1, 0xd3, 0x92, 0x71, 0x67,
|
||||
0x84, 0x90, 0x2e, 0xf1, 0xe9, 0xbe, 0xde, 0x9a, 0xee, 0xec, 0x2d, 0xe3, 0x3a, 0x3c, 0x9a, 0x57,
|
||||
0xd2, 0xea, 0x0f, 0x74, 0x58, 0xb6, 0xc8, 0x31, 0x85, 0xc9, 0xa6, 0x80, 0x4c, 0xa0, 0xff, 0x3b,
|
||||
0x7e, 0x88, 0xa9, 0xdd, 0x23, 0x99, 0xaf, 0x4f, 0x69, 0x78, 0x41, 0xea, 0x4c, 0xed, 0xd1, 0x38,
|
||||
0xb9, 0x1f, 0x93, 0x1f, 0x7a, 0xe9, 0xdf, 0x3d, 0x80, 0x96, 0x21, 0x2f, 0x60, 0xca, 0x84, 0xaa,
|
||||
0xa4, 0xcd, 0x54, 0x65, 0x97, 0x8a, 0xcb, 0x65, 0x26, 0x0c, 0xb3, 0xf1, 0x2e, 0x93, 0xc0, 0xbd,
|
||||
0x89, 0xd4, 0x95, 0x61, 0x96, 0x7c, 0x0b, 0xe4, 0x1d, 0xa2, 0xd9, 0xd0, 0x27, 0xe1, 0xee, 0x3b,
|
||||
0xa6, 0xa3, 0x6e, 0xe3, 0x73, 0x99, 0x2b, 0xd1, 0xe8, 0xfb, 0xeb, 0xf1, 0x2f, 0x23, 0xd5, 0x89,
|
||||
0xdf, 0xd5, 0xef, 0xb4, 0xf1, 0xd7, 0xd5, 0xe9, 0x0c, 0x8e, 0x62, 0xe3, 0x2f, 0xa5, 0xe1, 0xcb,
|
||||
0x5b, 0x5b, 0xaf, 0xa8, 0xf4, 0x57, 0x78, 0xf4, 0x11, 0x13, 0xcd, 0xf0, 0x13, 0x4c, 0xe2, 0x08,
|
||||
0x33, 0x1e, 0xb9, 0xe8, 0x8a, 0xe6, 0x52, 0x75, 0x8f, 0xd2, 0xc3, 0xbc, 0x1b, 0x2a, 0xfd, 0x27,
|
||||
0x81, 0x71, 0x57, 0xf3, 0x7f, 0x97, 0xc9, 0xad, 0xcc, 0x7a, 0x25, 0x66, 0x06, 0x73, 0x25, 0x17,
|
||||
0x26, 0x7a, 0x7b, 0xd2, 0x10, 0xd7, 0x01, 0x77, 0x5e, 0x8b, 0x3b, 0xb0, 0x56, 0x06, 0xa3, 0x8f,
|
||||
0x02, 0x5a, 0xcb, 0x5e, 0xc0, 0x74, 0xa5, 0x8a, 0x4a, 0xe0, 0xd6, 0x6e, 0x91, 0xc0, 0x75, 0xba,
|
||||
0xdb, 0x9e, 0xe8, 0xce, 0x6f, 0x77, 0xfd, 0x44, 0x67, 0x82, 0x73, 0xf0, 0x5d, 0xcf, 0x90, 0x69,
|
||||
0x89, 0x8b, 0xa0, 0xde, 0xf3, 0xea, 0xb1, 0xc3, 0x5f, 0x79, 0xd8, 0x2b, 0x9f, 0xc1, 0x28, 0x57,
|
||||
0xf2, 0x1d, 0xd7, 0x22, 0x2e, 0xaa, 0xfd, 0xd3, 0xde, 0x7c, 0x44, 0xbb, 0x20, 0x99, 0xc1, 0x7e,
|
||||
0xa9, 0xf9, 0x8a, 0x59, 0x9c, 0x1d, 0xf8, 0xb5, 0x51, 0xbf, 0x5e, 0xfc, 0x91, 0xc0, 0xe4, 0x06,
|
||||
0xb5, 0xe0, 0x92, 0x59, 0xa5, 0xaf, 0x51, 0xaf, 0x50, 0x13, 0x06, 0xd3, 0x6d, 0x2b, 0x9d, 0x7c,
|
||||
0xd9, 0x4c, 0xea, 0xee, 0xdf, 0xd4, 0xf1, 0xb3, 0xfb, 0x45, 0xd1, 0x0e, 0xbf, 0x6c, 0xde, 0xf4,
|
||||
0x93, 0xed, 0xbb, 0x21, 0x06, 0x7d, 0x72, 0x07, 0x1b, 0xa3, 0x51, 0x38, 0xdc, 0xf0, 0x1d, 0xf9,
|
||||
0x62, 0xbb, 0xab, 0x9a, 0x32, 0x9f, 0xde, 0xc9, 0x87, 0x98, 0xbf, 0xed, 0xf9, 0xbf, 0xf2, 0xf7,
|
||||
0xff, 0x05, 0x00, 0x00, 0xff, 0xff, 0x9d, 0x67, 0xb7, 0xb2, 0xc8, 0x07, 0x00, 0x00,
|
||||
// 944 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x56, 0x4f, 0x6f, 0xe3, 0x44,
|
||||
0x14, 0xc7, 0x71, 0x9b, 0xb6, 0x2f, 0x9b, 0xd4, 0x3b, 0xdb, 0x2d, 0xa1, 0x6a, 0x69, 0x64, 0xed,
|
||||
0xb2, 0x41, 0x40, 0xba, 0x0a, 0x17, 0xc4, 0x89, 0xaa, 0x8a, 0x96, 0x88, 0x26, 0xa9, 0x66, 0x93,
|
||||
0x72, 0x41, 0xb2, 0x8c, 0x33, 0x9b, 0x0e, 0xc4, 0x33, 0xde, 0xf1, 0x38, 0xd2, 0x7e, 0x01, 0xae,
|
||||
0x1c, 0xf8, 0x32, 0x7c, 0x08, 0x2e, 0x1c, 0xf8, 0x2e, 0x1c, 0xd1, 0xfc, 0xb1, 0x1d, 0x87, 0x74,
|
||||
0xcb, 0x85, 0x9b, 0xe7, 0xf7, 0xfb, 0xcd, 0xfb, 0xcd, 0xbc, 0xf7, 0x32, 0x2f, 0x70, 0x20, 0x92,
|
||||
0xa8, 0x97, 0x08, 0x2e, 0x39, 0xaa, 0x4b, 0x11, 0x8b, 0x24, 0x3a, 0x39, 0x5d, 0x70, 0xbe, 0x58,
|
||||
0x92, 0x8b, 0x30, 0xa1, 0x17, 0x21, 0x63, 0x5c, 0x86, 0x92, 0x72, 0x96, 0x1a, 0x95, 0xff, 0xb7,
|
||||
0x03, 0x27, 0x57, 0x4b, 0x9e, 0x12, 0x4c, 0x22, 0x1e, 0xc7, 0x84, 0xcd, 0x35, 0x8d, 0xc9, 0xdb,
|
||||
0x8c, 0xa4, 0x12, 0x7d, 0x06, 0x8f, 0x63, 0xca, 0x68, 0x9c, 0xc5, 0x41, 0xcc, 0x19, 0x95, 0x5c,
|
||||
0x90, 0x79, 0xdb, 0xe9, 0x38, 0x5d, 0x17, 0x7b, 0x96, 0x18, 0xe5, 0x38, 0xba, 0x84, 0x7a, 0x4c,
|
||||
0xa4, 0xa0, 0x51, 0xbb, 0xd6, 0x71, 0xba, 0xad, 0xfe, 0xa7, 0x3d, 0x73, 0x84, 0xde, 0xfd, 0x06,
|
||||
0xbd, 0x91, 0xde, 0x80, 0xed, 0x46, 0xff, 0x27, 0xa8, 0x1b, 0x04, 0x35, 0x60, 0x6f, 0x36, 0xfe,
|
||||
0x6e, 0x3c, 0xf9, 0x7e, 0xec, 0x7d, 0x80, 0x00, 0xea, 0xb3, 0x9b, 0xe9, 0x70, 0x34, 0xf0, 0x1c,
|
||||
0x45, 0xe0, 0xc1, 0xed, 0x60, 0x3c, 0x1b, 0x78, 0x35, 0xf4, 0x04, 0x0e, 0x87, 0xe3, 0xab, 0xc9,
|
||||
0x68, 0x38, 0x7e, 0x15, 0xdc, 0x4e, 0xae, 0x67, 0xa3, 0x81, 0xe7, 0x2a, 0x70, 0x32, 0x9b, 0xbe,
|
||||
0x9a, 0xac, 0x81, 0x3b, 0xc8, 0x83, 0x47, 0xd3, 0xc9, 0xf4, 0xf2, 0x3a, 0x47, 0x76, 0xfd, 0xdf,
|
||||
0x1c, 0x38, 0x9b, 0x64, 0x72, 0x49, 0x89, 0xa8, 0x9e, 0x2d, 0xcd, 0x6f, 0x7f, 0x05, 0x0d, 0x41,
|
||||
0xa2, 0x40, 0x98, 0xa5, 0xbe, 0x77, 0xa3, 0xef, 0x3f, 0x7c, 0x2b, 0x0c, 0x82, 0x44, 0x79, 0x90,
|
||||
0x2f, 0x00, 0x71, 0xe3, 0x12, 0xc4, 0xd9, 0x52, 0xd2, 0x44, 0x7d, 0xea, 0x0c, 0xd5, 0xf0, 0x63,
|
||||
0xcb, 0x8c, 0x0a, 0xc2, 0xff, 0xd5, 0x81, 0xf3, 0xe9, 0x9d, 0x20, 0xe9, 0x1d, 0x5f, 0xce, 0xff,
|
||||
0xcf, 0x73, 0xbd, 0x80, 0x43, 0x99, 0xfb, 0x04, 0xab, 0x70, 0x99, 0x11, 0x7b, 0xa8, 0x56, 0x01,
|
||||
0xdf, 0x2a, 0xd4, 0xff, 0xdd, 0x81, 0xd3, 0x2d, 0x31, 0x53, 0x4c, 0xd2, 0x84, 0xb3, 0x94, 0xa0,
|
||||
0xe7, 0xd0, 0x92, 0x5c, 0x86, 0xcb, 0x20, 0xba, 0x0b, 0x19, 0x23, 0xcb, 0x54, 0x9f, 0x68, 0x17,
|
||||
0x37, 0x35, 0x7a, 0x65, 0x41, 0x74, 0x01, 0x4f, 0x22, 0xce, 0x52, 0x3a, 0x27, 0x82, 0xcc, 0x4b,
|
||||
0x6d, 0x4d, 0x6b, 0x51, 0x49, 0x15, 0x1b, 0xbe, 0x81, 0x43, 0x51, 0xb5, 0x6c, 0xbb, 0x1d, 0xb7,
|
||||
0xdb, 0xe8, 0x1f, 0xe7, 0x57, 0xdd, 0xb8, 0xe5, 0xa6, 0xdc, 0x67, 0xd0, 0xaa, 0x4a, 0xd0, 0x19,
|
||||
0x80, 0x72, 0x0e, 0x12, 0x4e, 0x99, 0xc9, 0xdc, 0x01, 0x3e, 0x50, 0xc8, 0x8d, 0x02, 0xd0, 0x11,
|
||||
0xec, 0xae, 0xa7, 0xc2, 0x2c, 0x54, 0xaa, 0x8a, 0xc8, 0x41, 0xa4, 0x52, 0xd1, 0x76, 0x3b, 0x4e,
|
||||
0x77, 0x1f, 0xb7, 0x0a, 0x58, 0x27, 0xc8, 0x7f, 0x0b, 0x47, 0x98, 0xac, 0x08, 0xcb, 0x08, 0x26,
|
||||
0x09, 0x17, 0x32, 0xcf, 0xf5, 0x39, 0x34, 0x4a, 0x57, 0x95, 0x1e, 0xb7, 0x7b, 0x80, 0xa1, 0xb0,
|
||||
0x4d, 0xd5, 0xb1, 0x52, 0x19, 0x0a, 0x19, 0x48, 0x1a, 0x1b, 0xf3, 0x1d, 0x7c, 0xa0, 0x91, 0x29,
|
||||
0x8d, 0x09, 0xfa, 0x08, 0xf6, 0x95, 0xb5, 0x26, 0x5d, 0x4d, 0xee, 0x11, 0x36, 0x57, 0x94, 0xff,
|
||||
0x2d, 0x3c, 0xdd, 0xb0, 0xb4, 0x55, 0xb9, 0x80, 0x3d, 0xa1, 0x11, 0xe3, 0xd7, 0xe8, 0x3f, 0x2d,
|
||||
0xb3, 0xb6, 0xae, 0xcf, 0x55, 0xfe, 0x5f, 0x0e, 0x34, 0x2b, 0x94, 0x2e, 0x6c, 0x28, 0x16, 0x44,
|
||||
0xe6, 0xd5, 0xb2, 0x09, 0x6b, 0x1a, 0xd4, 0x16, 0x0a, 0x0d, 0xe1, 0x51, 0x12, 0x52, 0x11, 0xe4,
|
||||
0x76, 0x35, 0x6d, 0xf7, 0xc9, 0x56, 0xbb, 0xde, 0x4d, 0x48, 0x85, 0xf9, 0x4c, 0x07, 0x4c, 0x8a,
|
||||
0x77, 0xb8, 0x91, 0x94, 0xc8, 0x09, 0x06, 0x6f, 0x53, 0x80, 0x3c, 0x70, 0x7f, 0x26, 0xef, 0xac,
|
||||
0xb5, 0xfa, 0x44, 0xdd, 0xf5, 0x2a, 0x35, 0xfa, 0x28, 0x77, 0x2a, 0xb7, 0xda, 0xca, 0x7d, 0x5d,
|
||||
0xfb, 0xca, 0xf1, 0xff, 0x70, 0x00, 0x4a, 0x06, 0xbd, 0x84, 0xa3, 0x30, 0xe6, 0x19, 0x93, 0x01,
|
||||
0xcf, 0xe4, 0x82, 0x53, 0xb6, 0x08, 0xe2, 0x34, 0x94, 0xf6, 0x55, 0x43, 0x86, 0x9b, 0x58, 0x6a,
|
||||
0x94, 0x86, 0x12, 0x7d, 0x0e, 0xe8, 0x0d, 0x21, 0xe9, 0x86, 0xbe, 0x66, 0x5e, 0x41, 0xc5, 0x54,
|
||||
0xd4, 0x65, 0x7c, 0xca, 0x22, 0x1e, 0x17, 0x7a, 0x77, 0x3d, 0xfe, 0xd0, 0x52, 0x95, 0xf8, 0x55,
|
||||
0xfd, 0x4e, 0x19, 0x7f, 0x5d, 0xed, 0xb7, 0xe1, 0xd8, 0x26, 0x7e, 0xc8, 0x52, 0xba, 0xb8, 0x93,
|
||||
0xf9, 0xb3, 0xe0, 0xff, 0x00, 0x1f, 0xfe, 0x8b, 0xb1, 0xcd, 0x70, 0x09, 0x9e, 0x2d, 0x61, 0x40,
|
||||
0x2d, 0x67, 0xbb, 0xa2, 0xf8, 0x2d, 0x55, 0xb7, 0xe2, 0xc3, 0xa8, 0x1a, 0xca, 0xff, 0xb3, 0x06,
|
||||
0xad, 0xaa, 0xe6, 0xa1, 0x1f, 0x93, 0x1a, 0x1e, 0xf9, 0x70, 0x08, 0x52, 0x12, 0x71, 0x36, 0x4f,
|
||||
0x6d, 0x6f, 0x7b, 0x05, 0xf1, 0xda, 0xe0, 0xaa, 0xd7, 0xb2, 0x44, 0x35, 0x78, 0xa1, 0x34, 0x8d,
|
||||
0xde, 0x34, 0x68, 0x2e, 0x7b, 0x09, 0x47, 0x2b, 0xbe, 0xcc, 0x62, 0xb2, 0x35, 0x5b, 0xc8, 0x70,
|
||||
0x95, 0xec, 0x96, 0x3b, 0xaa, 0xf5, 0xdb, 0x5d, 0xdf, 0x51, 0xa9, 0x60, 0x17, 0x74, 0xd6, 0x03,
|
||||
0x12, 0x0a, 0x46, 0xe6, 0x46, 0x5d, 0xd7, 0xea, 0x96, 0xc2, 0x07, 0x1a, 0xd6, 0xca, 0x67, 0xd0,
|
||||
0x8c, 0x38, 0x7b, 0x43, 0x45, 0x6c, 0xdf, 0xa7, 0xbd, 0x8e, 0xd3, 0x6d, 0xe2, 0x2a, 0x88, 0xda,
|
||||
0xb0, 0x97, 0x08, 0xba, 0x0a, 0x25, 0x69, 0xef, 0xeb, 0x67, 0x23, 0x5f, 0xf6, 0x7f, 0x71, 0xc1,
|
||||
0x9b, 0x12, 0x11, 0x53, 0x16, 0x4a, 0x2e, 0x5e, 0x13, 0xb1, 0x22, 0x02, 0x11, 0x38, 0xde, 0x3e,
|
||||
0x96, 0xd0, 0xf3, 0xbc, 0x56, 0xef, 0x1d, 0x5b, 0x27, 0xcf, 0xde, 0x33, 0x09, 0xca, 0x96, 0xa0,
|
||||
0xd0, 0xbe, 0x6f, 0xce, 0xa0, 0x17, 0x79, 0x84, 0x07, 0x26, 0xd1, 0x7f, 0xb4, 0xba, 0xde, 0x7c,
|
||||
0x58, 0x4e, 0xb7, 0x3f, 0x45, 0x36, 0xe8, 0xd9, 0x3d, 0xac, 0x8d, 0x86, 0xe1, 0x70, 0xa3, 0xcd,
|
||||
0xd1, 0xc7, 0xdb, 0x9b, 0xb8, 0x38, 0xe6, 0xf9, 0xbd, 0xbc, 0x89, 0xf9, 0x63, 0x5d, 0xff, 0x1b,
|
||||
0xfa, 0xf2, 0x9f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x0b, 0xdf, 0x60, 0xc4, 0x40, 0x09, 0x00, 0x00,
|
||||
}
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
|
|
@ -766,7 +889,8 @@ const _ = grpc.SupportPackageIsVersion4
|
|||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
|
||||
type TerminatorServerClient interface {
|
||||
CloseRecommendations(ctx context.Context, in *CloseRecommendationsRequest, opts ...grpc.CallOption) (*CloseRecommendationsResponse, error)
|
||||
OutlierRecommendations(ctx context.Context, in *OutlierRecommendationsRequest, opts ...grpc.CallOption) (*CloseRecommendationsResponse, error)
|
||||
ThresholdRecommendations(ctx context.Context, in *ThresholdRecommendationsRequest, opts ...grpc.CallOption) (*CloseRecommendationsResponse, error)
|
||||
RevenueReport(ctx context.Context, in *RevenueReportRequest, opts ...grpc.CallOption) (*RevenueReportResponse, error)
|
||||
ChannelInsights(ctx context.Context, in *ChannelInsightsRequest, opts ...grpc.CallOption) (*ChannelInsightsResponse, error)
|
||||
}
|
||||
|
|
@ -779,9 +903,18 @@ func NewTerminatorServerClient(cc *grpc.ClientConn) TerminatorServerClient {
|
|||
return &terminatorServerClient{cc}
|
||||
}
|
||||
|
||||
func (c *terminatorServerClient) CloseRecommendations(ctx context.Context, in *CloseRecommendationsRequest, opts ...grpc.CallOption) (*CloseRecommendationsResponse, error) {
|
||||
func (c *terminatorServerClient) OutlierRecommendations(ctx context.Context, in *OutlierRecommendationsRequest, opts ...grpc.CallOption) (*CloseRecommendationsResponse, error) {
|
||||
out := new(CloseRecommendationsResponse)
|
||||
err := c.cc.Invoke(ctx, "/trmrpc.TerminatorServer/CloseRecommendations", in, out, opts...)
|
||||
err := c.cc.Invoke(ctx, "/trmrpc.TerminatorServer/OutlierRecommendations", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *terminatorServerClient) ThresholdRecommendations(ctx context.Context, in *ThresholdRecommendationsRequest, opts ...grpc.CallOption) (*CloseRecommendationsResponse, error) {
|
||||
out := new(CloseRecommendationsResponse)
|
||||
err := c.cc.Invoke(ctx, "/trmrpc.TerminatorServer/ThresholdRecommendations", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -808,7 +941,8 @@ func (c *terminatorServerClient) ChannelInsights(ctx context.Context, in *Channe
|
|||
|
||||
// TerminatorServerServer is the server API for TerminatorServer service.
|
||||
type TerminatorServerServer interface {
|
||||
CloseRecommendations(context.Context, *CloseRecommendationsRequest) (*CloseRecommendationsResponse, error)
|
||||
OutlierRecommendations(context.Context, *OutlierRecommendationsRequest) (*CloseRecommendationsResponse, error)
|
||||
ThresholdRecommendations(context.Context, *ThresholdRecommendationsRequest) (*CloseRecommendationsResponse, error)
|
||||
RevenueReport(context.Context, *RevenueReportRequest) (*RevenueReportResponse, error)
|
||||
ChannelInsights(context.Context, *ChannelInsightsRequest) (*ChannelInsightsResponse, error)
|
||||
}
|
||||
|
|
@ -817,20 +951,38 @@ func RegisterTerminatorServerServer(s *grpc.Server, srv TerminatorServerServer)
|
|||
s.RegisterService(&_TerminatorServer_serviceDesc, srv)
|
||||
}
|
||||
|
||||
func _TerminatorServer_CloseRecommendations_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(CloseRecommendationsRequest)
|
||||
func _TerminatorServer_OutlierRecommendations_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(OutlierRecommendationsRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(TerminatorServerServer).CloseRecommendations(ctx, in)
|
||||
return srv.(TerminatorServerServer).OutlierRecommendations(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/trmrpc.TerminatorServer/CloseRecommendations",
|
||||
FullMethod: "/trmrpc.TerminatorServer/OutlierRecommendations",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(TerminatorServerServer).CloseRecommendations(ctx, req.(*CloseRecommendationsRequest))
|
||||
return srv.(TerminatorServerServer).OutlierRecommendations(ctx, req.(*OutlierRecommendationsRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _TerminatorServer_ThresholdRecommendations_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(ThresholdRecommendationsRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(TerminatorServerServer).ThresholdRecommendations(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/trmrpc.TerminatorServer/ThresholdRecommendations",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(TerminatorServerServer).ThresholdRecommendations(ctx, req.(*ThresholdRecommendationsRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
|
@ -876,8 +1028,12 @@ var _TerminatorServer_serviceDesc = grpc.ServiceDesc{
|
|||
HandlerType: (*TerminatorServerServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "CloseRecommendations",
|
||||
Handler: _TerminatorServer_CloseRecommendations_Handler,
|
||||
MethodName: "OutlierRecommendations",
|
||||
Handler: _TerminatorServer_OutlierRecommendations_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "ThresholdRecommendations",
|
||||
Handler: _TerminatorServer_ThresholdRecommendations_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "RevenueReport",
|
||||
|
|
|
|||
100
trmrpc/rpc.proto
100
trmrpc/rpc.proto
|
|
@ -5,12 +5,13 @@ import "google/api/annotations.proto";
|
|||
package trmrpc;
|
||||
|
||||
service TerminatorServer {
|
||||
rpc CloseRecommendations (CloseRecommendationsRequest) returns (CloseRecommendationsResponse);
|
||||
rpc OutlierRecommendations (OutlierRecommendationsRequest) returns (CloseRecommendationsResponse);
|
||||
rpc ThresholdRecommendations (ThresholdRecommendationsRequest) returns (CloseRecommendationsResponse);
|
||||
rpc RevenueReport (RevenueReportRequest) returns (RevenueReportResponse);
|
||||
rpc ChannelInsights (ChannelInsightsRequest) returns (ChannelInsightsResponse);
|
||||
}
|
||||
|
||||
message CloseRecommendationsRequest {
|
||||
message CloseRecommendationRequest {
|
||||
/*
|
||||
The minimum amount of time in seconds that a channel should have been
|
||||
monitored by lnd to be eligible for close. This value is in place to
|
||||
|
|
@ -18,6 +19,31 @@ message CloseRecommendationsRequest {
|
|||
*/
|
||||
int64 minimum_monitored = 1;
|
||||
|
||||
enum Metric{
|
||||
UNKNOWN = 0;
|
||||
UPTIME = 1;
|
||||
REVENUE = 2;
|
||||
INCOMING_VOLUME = 3;
|
||||
OUTGOING_VOLUME = 4;
|
||||
TOTAL_VOLUME = 5;
|
||||
}
|
||||
|
||||
/*
|
||||
The data point base close recommendations on. Available options are:
|
||||
Uptime: ratio of channel peer's uptime to the period they have been
|
||||
monitored to.
|
||||
Revenue: the revenue that the channel has produced per block that its
|
||||
funding transaction has been confirmed for.
|
||||
*/
|
||||
Metric metric = 2;
|
||||
}
|
||||
|
||||
message OutlierRecommendationsRequest {
|
||||
/*
|
||||
The parameters that are common to all close recommendations.
|
||||
*/
|
||||
CloseRecommendationRequest rec_request = 1;
|
||||
|
||||
/*
|
||||
The number of inter-quartile ranges a value needs to be beneath the lower
|
||||
quartile/ above the upper quartile to be considered a lower/upper outlier.
|
||||
|
|
@ -26,21 +52,43 @@ message CloseRecommendationsRequest {
|
|||
aggressive recommendations and 3 for conservative recommendations.
|
||||
*/
|
||||
float outlier_multiplier = 2;
|
||||
}
|
||||
|
||||
message ThresholdRecommendationsRequest {
|
||||
/*
|
||||
The parameters that are common to all close recommendations.
|
||||
*/
|
||||
CloseRecommendationRequest rec_request = 1;
|
||||
|
||||
/*
|
||||
Threshold contains the threshold value that is used to recommend channels
|
||||
for closure.
|
||||
*/
|
||||
oneof threshold{
|
||||
/*
|
||||
The threshold percentage uptime over observed lifetime beneath which
|
||||
channels will be recommended for closure.
|
||||
*/
|
||||
float uptime_threshold = 3;
|
||||
}
|
||||
}
|
||||
The threshold that recommendations will be calculated based on.
|
||||
For uptime: ratio of uptime to observed lifetime beneath which channels
|
||||
will be recommended for closure.
|
||||
|
||||
message CloseRecommendationsResponse{
|
||||
For revenue: revenue per block that capital has been committed to the
|
||||
channel beneath which channels will be recommended for closure. This
|
||||
value is provided per block so that channels that have been open for
|
||||
different periods of time can be compared.
|
||||
|
||||
For incoming volume: The incoming volume per block that capital has
|
||||
been committed to the channel beneath which channels will be recommended
|
||||
for closure. This value is provided per block so that channels that have
|
||||
been open for different periods of time can be compared.
|
||||
|
||||
For outgoing volume: The outgoing volume per block that capital has been
|
||||
committed to the channel beneath which channels will be recommended for
|
||||
closure. This value is provided per block so that channels that have been
|
||||
open for different periods of time can be compared.
|
||||
|
||||
For total volume: The total volume per block that capital has been
|
||||
committed to the channel beneath which channels will be recommended for
|
||||
closure. This value is provided per block so that channels that have been
|
||||
open for different periods of time can be compared.
|
||||
*/
|
||||
float threshold_value = 2;
|
||||
}
|
||||
|
||||
message CloseRecommendationsResponse {
|
||||
/*
|
||||
The total number of channels, before filtering out channels that are
|
||||
not eligible for close recommendations.
|
||||
|
|
@ -53,25 +101,15 @@ message CloseRecommendationsResponse{
|
|||
int32 considered_channels = 2;
|
||||
|
||||
/*
|
||||
A map of channels to close recommendations, based out whether they are
|
||||
outliers in the uptime dataset. The absence of a channel in this set
|
||||
implies that it was not considered for close because it did not meet
|
||||
the criteria for close (it is private, or has not been monitored for
|
||||
long enough to make a decision).
|
||||
A set of channel close recommendations. The absence of a channel in this
|
||||
set implies that it was not considered for close because it did not meet
|
||||
the criteria for close recommendations (it is private, or has not been
|
||||
monitored for long enough).
|
||||
*/
|
||||
repeated Recommendation outlier_recommendations = 3;
|
||||
|
||||
/*
|
||||
A set of channel close recommendations, based out whether they are
|
||||
beneath the threshold provided in the request. The absence of a channel
|
||||
in this set implies that it was not considered for close because it
|
||||
did not meet the criteria for close (it is private, or has not been
|
||||
monitored for long enough to make a decision).
|
||||
*/
|
||||
repeated Recommendation threshold_recommendations = 4;
|
||||
repeated Recommendation recommendations = 3;
|
||||
}
|
||||
|
||||
message Recommendation{
|
||||
message Recommendation {
|
||||
/*
|
||||
The channel point [funding txid: outpoint] of the channel being considered
|
||||
for close.
|
||||
|
|
@ -115,7 +153,7 @@ message RevenueReportResponse {
|
|||
repeated RevenueReport reports = 1;
|
||||
}
|
||||
|
||||
message RevenueReport{
|
||||
message RevenueReport {
|
||||
/*
|
||||
Target channel is the channel that the report is generated for; incoming
|
||||
fields in the report mean that this channel was the incoming channel,
|
||||
|
|
|
|||
|
|
@ -129,20 +129,37 @@ func (s *RPCServer) Stop() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// CloseRecommendations provides a set of close recommendations for the
|
||||
// current set of open channels.
|
||||
func (s *RPCServer) CloseRecommendations(ctx context.Context,
|
||||
req *CloseRecommendationsRequest) (*CloseRecommendationsResponse,
|
||||
// OutlierRecommendations provides a set of close recommendations for the
|
||||
// current set of open channels based on whether they are outliers.
|
||||
func (s *RPCServer) OutlierRecommendations(ctx context.Context,
|
||||
req *OutlierRecommendationsRequest) (*CloseRecommendationsResponse,
|
||||
error) {
|
||||
|
||||
cfg := parseRequest(ctx, s.cfg, req)
|
||||
cfg, multiplier := parseOutlierRequest(ctx, s.cfg, req)
|
||||
|
||||
report, err := recommend.CloseRecommendations(cfg)
|
||||
report, err := recommend.OutlierRecommendations(cfg, multiplier)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return parseResponse(report), nil
|
||||
return rpcResponse(report), nil
|
||||
}
|
||||
|
||||
// ThresholdRecommendations provides a set of close recommendations for the
|
||||
// current set of open channels based on whether they are above or below a
|
||||
// given threshold.
|
||||
func (s *RPCServer) ThresholdRecommendations(ctx context.Context,
|
||||
req *ThresholdRecommendationsRequest) (*CloseRecommendationsResponse,
|
||||
error) {
|
||||
|
||||
cfg, threshold := parseThresholdRequest(ctx, s.cfg, req)
|
||||
|
||||
report, err := recommend.ThresholdRecommendations(cfg, threshold)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return rpcResponse(report), nil
|
||||
}
|
||||
|
||||
// RevenueReport returns a pairwise revenue report for a channel
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue