Skip to content

Commit 98a89e9

Browse files
authored
Merge pull request #113 from bitromortac/2410-inbound-fees
inbound fees: collect and display stats
2 parents b901c20 + f7938f7 commit 98a89e9

File tree

4 files changed

+981
-220
lines changed

4 files changed

+981
-220
lines changed

collectors/graph_collector.go

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,32 @@ package collectors
33
import (
44
"context"
55
"fmt"
6+
"math"
67

78
"github.com/lightninglabs/lndclient"
89
"github.com/prometheus/client_golang/prometheus"
910
)
1011

12+
const (
13+
// inboundFeeFeatureBits is the feature id used to advertise inbound
14+
// fees in gossip TLV extensions.
15+
inboundFeeFeatureBits = 55555
16+
17+
// Define some collector names and help texts for inbound fees.
18+
inboundFeeRateName = "lnd_graph_inbound_fee_rate_msat_histogram"
19+
inboundFeeBaseName = "lnd_graph_inbound_fee_base_msat_histogram"
20+
inboundFeeRateHelp = "histogram of inbound fee rates for channel " +
21+
"routing policies in msat"
22+
inboundFeeBaseHelp = "histogram of inbound base fees for channel " +
23+
"routing policies in msat"
24+
25+
// Define labels to categorize inbound fees into negative and positive
26+
// buckets.
27+
inboundFeeSignLabel = "sign"
28+
inboundFeeSignLabelPositive = "positive"
29+
inboundFeeSignLabelNegative = "negative"
30+
)
31+
1132
// GraphCollector is a collector that keeps track of graph information.
1233
type GraphCollector struct {
1334
numEdgesDesc *prometheus.Desc
@@ -46,6 +67,9 @@ type GraphCollector struct {
4667
minFeeRateMsatDesc *prometheus.Desc
4768
avgFeeRateMsatDesc *prometheus.Desc
4869

70+
inboundFeeBaseMsatDesc *prometheus.Desc
71+
inboundFeeRateMsatDesc *prometheus.Desc
72+
4973
medianMaxHtlcMsatDesc *prometheus.Desc
5074
maxMaxHtlcMsatDesc *prometheus.Desc
5175
minMaxHtlcMsatDesc *prometheus.Desc
@@ -207,6 +231,15 @@ func NewGraphCollector(lnd lndclient.LightningClient,
207231
nil, nil,
208232
),
209233

234+
inboundFeeBaseMsatDesc: prometheus.NewDesc(
235+
inboundFeeBaseName, inboundFeeBaseHelp,
236+
[]string{inboundFeeSignLabel}, nil,
237+
),
238+
inboundFeeRateMsatDesc: prometheus.NewDesc(
239+
inboundFeeRateName, inboundFeeRateHelp,
240+
[]string{inboundFeeSignLabel}, nil,
241+
),
242+
210243
medianMaxHtlcMsatDesc: prometheus.NewDesc(
211244
"lnd_graph_max_htlc_msat_median",
212245
"median max htlc for a channel routing policy in msat",
@@ -274,6 +307,9 @@ func (g *GraphCollector) Describe(ch chan<- *prometheus.Desc) {
274307
ch <- g.avgFeeRateMsatDesc
275308
ch <- g.medianFeeRateMsatDesc
276309

310+
ch <- g.inboundFeeBaseMsatDesc
311+
ch <- g.inboundFeeRateMsatDesc
312+
277313
ch <- g.minMaxHtlcMsatDesc
278314
ch <- g.maxMaxHtlcMsatDesc
279315
ch <- g.avgMaxHtlcMsatDesc
@@ -366,6 +402,27 @@ func (g *GraphCollector) collectRoutingPolicyMetrics(
366402

367403
feeBaseStats = newStatsCompiler(numEdges)
368404
feeRateStats = newStatsCompiler(numEdges)
405+
406+
inboundFeeBaseStats = prometheus.NewHistogramVec(
407+
prometheus.HistogramOpts{
408+
Name: inboundFeeBaseName,
409+
Help: inboundFeeBaseHelp,
410+
Buckets: prometheus.ExponentialBuckets(
411+
1, 2, 20, // 1 to 1_048_576 msat
412+
),
413+
},
414+
[]string{inboundFeeSignLabel},
415+
)
416+
inboundFeeRateStats = prometheus.NewHistogramVec(
417+
prometheus.HistogramOpts{
418+
Name: inboundFeeRateName,
419+
Help: inboundFeeRateHelp,
420+
Buckets: prometheus.ExponentialBuckets(
421+
1, 2, 15, // 1 to 32768 PPM ~ 3 %
422+
),
423+
},
424+
[]string{inboundFeeSignLabel},
425+
)
369426
)
370427

371428
for _, edge := range edges {
@@ -385,6 +442,36 @@ func (g *GraphCollector) collectRoutingPolicyMetrics(
385442

386443
feeBaseStats.Observe(float64(policy.FeeBaseMsat))
387444
feeRateStats.Observe(float64(policy.FeeRateMilliMsat))
445+
446+
// Collect optional non-zero inbound fee statistics.
447+
_, ok := policy.CustomRecords[inboundFeeFeatureBits]
448+
if ok {
449+
absBase := math.Abs(float64(
450+
policy.InboundBaseFeeMsat,
451+
))
452+
if policy.InboundBaseFeeMsat < 0 {
453+
inboundFeeBaseStats.WithLabelValues(
454+
inboundFeeSignLabelNegative,
455+
).Observe(absBase)
456+
} else if policy.InboundBaseFeeMsat > 0 {
457+
inboundFeeBaseStats.WithLabelValues(
458+
inboundFeeSignLabelPositive,
459+
).Observe(absBase)
460+
}
461+
462+
absRate := math.Abs(
463+
float64(policy.InboundFeeRatePPM),
464+
)
465+
if policy.InboundFeeRatePPM < 0 {
466+
inboundFeeRateStats.WithLabelValues(
467+
inboundFeeSignLabelNegative,
468+
).Observe(absRate)
469+
} else if policy.InboundFeeRatePPM > 0 {
470+
inboundFeeRateStats.WithLabelValues(
471+
inboundFeeSignLabelPositive,
472+
).Observe(absRate)
473+
}
474+
}
388475
}
389476
}
390477

@@ -478,4 +565,7 @@ func (g *GraphCollector) collectRoutingPolicyMetrics(
478565
g.medianFeeRateMsatDesc, prometheus.GaugeValue,
479566
feeRateReport.median,
480567
)
568+
569+
inboundFeeBaseStats.Collect(ch)
570+
inboundFeeRateStats.Collect(ch)
481571
}

go.mod

Lines changed: 77 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -5,107 +5,127 @@ require (
55
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f
66
github.com/jessevdk/go-flags v1.5.0
77
github.com/jrick/logrotate v1.0.0
8-
github.com/lightninglabs/lndclient v0.17.4-4
9-
github.com/lightningnetwork/lnd v0.17.4-beta
8+
github.com/lightninglabs/lndclient v0.18.0-6
9+
github.com/lightningnetwork/lnd v0.18.3-beta
1010
github.com/prometheus/client_golang v1.18.0
11-
github.com/stretchr/testify v1.8.4
11+
github.com/stretchr/testify v1.9.0
12+
google.golang.org/grpc v1.59.0
1213
)
1314

1415
require (
16+
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect
17+
github.com/Microsoft/go-winio v0.6.1 // indirect
18+
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect
1519
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da // indirect
1620
github.com/aead/siphash v1.0.1 // indirect
17-
github.com/andybalholm/brotli v1.0.3 // indirect
1821
github.com/beorn7/perks v1.0.1 // indirect
19-
github.com/btcsuite/btcd v0.24.1-0.20240123000108-62e6af035ec5 // indirect
20-
github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect
22+
github.com/btcsuite/btcd v0.24.2-beta.rc1.0.20240625142744-cc26860b4026 // indirect
23+
github.com/btcsuite/btcd/btcec/v2 v2.3.3 // indirect
2124
github.com/btcsuite/btcd/btcutil/psbt v1.1.8 // indirect
2225
github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 // indirect
23-
github.com/btcsuite/btcwallet v0.16.10-0.20240127010340-16b422a2e8bf // indirect
24-
github.com/btcsuite/btcwallet/wallet/txauthor v1.3.2 // indirect
25-
github.com/btcsuite/btcwallet/wallet/txrules v1.2.0 // indirect
26-
github.com/btcsuite/btcwallet/wallet/txsizes v1.2.3 // indirect
27-
github.com/btcsuite/btcwallet/walletdb v1.4.0 // indirect
28-
github.com/btcsuite/btcwallet/wtxmgr v1.5.0 // indirect
26+
github.com/btcsuite/btcwallet v0.16.10-0.20240718224643-db3a4a2543bd // indirect
27+
github.com/btcsuite/btcwallet/wallet/txauthor v1.3.4 // indirect
28+
github.com/btcsuite/btcwallet/wallet/txrules v1.2.1 // indirect
29+
github.com/btcsuite/btcwallet/wallet/txsizes v1.2.4 // indirect
30+
github.com/btcsuite/btcwallet/walletdb v1.4.2 // indirect
31+
github.com/btcsuite/btcwallet/wtxmgr v1.5.3 // indirect
2932
github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd // indirect
3033
github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792 // indirect
3134
github.com/btcsuite/winsvc v1.0.0 // indirect
3235
github.com/cenkalti/backoff/v4 v4.1.3 // indirect
3336
github.com/cespare/xxhash/v2 v2.2.0 // indirect
37+
github.com/containerd/continuity v0.3.0 // indirect
3438
github.com/coreos/go-semver v0.3.0 // indirect
3539
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f // indirect
3640
github.com/coreos/go-systemd/v22 v22.3.2 // indirect
3741
github.com/davecgh/go-spew v1.1.1 // indirect
38-
github.com/decred/dcrd/crypto/blake256 v1.0.0 // indirect
39-
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect
40-
github.com/decred/dcrd/lru v1.0.0 // indirect
41-
github.com/dsnet/compress v0.0.1 // indirect
42-
github.com/dustin/go-humanize v1.0.0 // indirect
43-
github.com/fergusstrange/embedded-postgres v1.10.0 // indirect
42+
github.com/decred/dcrd/crypto/blake256 v1.0.1 // indirect
43+
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect
44+
github.com/decred/dcrd/lru v1.1.2 // indirect
45+
github.com/docker/cli v20.10.17+incompatible // indirect
46+
github.com/docker/docker v24.0.7+incompatible // indirect
47+
github.com/docker/go-connections v0.4.0 // indirect
48+
github.com/docker/go-units v0.5.0 // indirect
49+
github.com/dustin/go-humanize v1.0.1 // indirect
50+
github.com/fergusstrange/embedded-postgres v1.25.0 // indirect
4451
github.com/go-errors/errors v1.0.1 // indirect
4552
github.com/go-logr/logr v1.3.0 // indirect
4653
github.com/go-logr/stdr v1.2.2 // indirect
4754
github.com/gogo/protobuf v1.3.2 // indirect
4855
github.com/golang-jwt/jwt/v4 v4.4.2 // indirect
56+
github.com/golang-migrate/migrate/v4 v4.17.0 // indirect
4957
github.com/golang/protobuf v1.5.3 // indirect
5058
github.com/golang/snappy v0.0.4 // indirect
5159
github.com/google/btree v1.0.1 // indirect
52-
github.com/google/uuid v1.3.1 // indirect
60+
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
61+
github.com/google/uuid v1.6.0 // indirect
5362
github.com/gorilla/websocket v1.5.0 // indirect
5463
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect
5564
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect
5665
github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect
5766
github.com/grpc-ecosystem/grpc-gateway/v2 v2.5.0 // indirect
67+
github.com/hashicorp/errwrap v1.1.0 // indirect
68+
github.com/hashicorp/go-multierror v1.1.1 // indirect
69+
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
70+
github.com/imdario/mergo v0.3.12 // indirect
5871
github.com/jackc/chunkreader/v2 v2.0.1 // indirect
5972
github.com/jackc/pgconn v1.14.3 // indirect
60-
github.com/jackc/pgerrcode v0.0.0-20220416144525-469b46aa5efa // indirect
73+
github.com/jackc/pgerrcode v0.0.0-20240316143900-6e2875d9b438 // indirect
6174
github.com/jackc/pgio v1.0.0 // indirect
6275
github.com/jackc/pgpassfile v1.0.0 // indirect
6376
github.com/jackc/pgproto3/v2 v2.3.3 // indirect
6477
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
6578
github.com/jackc/pgtype v1.14.0 // indirect
6679
github.com/jackc/pgx/v4 v4.18.2 // indirect
80+
github.com/jackc/pgx/v5 v5.3.1 // indirect
6781
github.com/jonboulle/clockwork v0.2.2 // indirect
6882
github.com/json-iterator/go v1.1.12 // indirect
6983
github.com/juju/loggo v0.0.0-20210728185423-eebad3a902c4 // indirect
70-
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
7184
github.com/kkdai/bstream v1.0.0 // indirect
72-
github.com/klauspost/compress v1.13.6 // indirect
73-
github.com/klauspost/pgzip v1.2.5 // indirect
74-
github.com/lib/pq v1.10.3 // indirect
85+
github.com/lib/pq v1.10.9 // indirect
7586
github.com/lightninglabs/gozmq v0.0.0-20191113021534-d20a764486bf // indirect
76-
github.com/lightninglabs/neutrino v0.16.0 // indirect
77-
github.com/lightninglabs/neutrino/cache v1.1.1 // indirect
78-
github.com/lightningnetwork/lightning-onion v1.2.1-0.20230823005744-06182b1d7d2f // indirect
87+
github.com/lightninglabs/neutrino v0.16.1-0.20240425105051-602843d34ffd // indirect
88+
github.com/lightninglabs/neutrino/cache v1.1.2 // indirect
89+
github.com/lightningnetwork/lightning-onion v1.2.1-0.20240712235311-98bd56499dfb // indirect
7990
github.com/lightningnetwork/lnd/clock v1.1.1 // indirect
80-
github.com/lightningnetwork/lnd/healthcheck v1.2.3 // indirect
81-
github.com/lightningnetwork/lnd/kvdb v1.4.4 // indirect
91+
github.com/lightningnetwork/lnd/fn v1.2.0 // indirect
92+
github.com/lightningnetwork/lnd/healthcheck v1.2.5 // indirect
93+
github.com/lightningnetwork/lnd/kvdb v1.4.10 // indirect
8294
github.com/lightningnetwork/lnd/queue v1.1.1 // indirect
95+
github.com/lightningnetwork/lnd/sqldb v1.0.4 // indirect
8396
github.com/lightningnetwork/lnd/ticker v1.1.1 // indirect
84-
github.com/lightningnetwork/lnd/tlv v1.1.1 // indirect
97+
github.com/lightningnetwork/lnd/tlv v1.2.3 // indirect
8598
github.com/lightningnetwork/lnd/tor v1.1.2 // indirect
8699
github.com/ltcsuite/ltcd v0.0.0-20190101042124-f37f8bf35796 // indirect
87-
github.com/mattn/go-isatty v0.0.16 // indirect
100+
github.com/mattn/go-isatty v0.0.20 // indirect
88101
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect
89-
github.com/mholt/archiver/v3 v3.5.0 // indirect
90102
github.com/miekg/dns v1.1.43 // indirect
103+
github.com/mitchellh/mapstructure v1.4.1 // indirect
104+
github.com/moby/term v0.5.0 // indirect
91105
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
92106
github.com/modern-go/reflect2 v1.0.2 // indirect
93-
github.com/nwaples/rardecode v1.1.2 // indirect
94-
github.com/pierrec/lz4/v4 v4.1.8 // indirect
107+
github.com/ncruces/go-strftime v0.1.9 // indirect
108+
github.com/opencontainers/go-digest v1.0.0 // indirect
109+
github.com/opencontainers/image-spec v1.0.2 // indirect
110+
github.com/opencontainers/runc v1.1.12 // indirect
111+
github.com/ory/dockertest/v3 v3.10.0 // indirect
112+
github.com/pkg/errors v0.9.1 // indirect
95113
github.com/pmezard/go-difflib v1.0.0 // indirect
96114
github.com/prometheus/client_model v0.5.0 // indirect
97115
github.com/prometheus/common v0.45.0 // indirect
98116
github.com/prometheus/procfs v0.12.0 // indirect
99-
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect
117+
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
100118
github.com/rogpeppe/fastuuid v1.2.0 // indirect
101119
github.com/sirupsen/logrus v1.9.2 // indirect
102120
github.com/soheilhy/cmux v0.1.5 // indirect
103121
github.com/spf13/pflag v1.0.5 // indirect
104-
github.com/stretchr/objx v0.5.0 // indirect
122+
github.com/stretchr/objx v0.5.2 // indirect
105123
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // indirect
106124
github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802 // indirect
107-
github.com/ulikunitz/xz v0.5.11 // indirect
108125
github.com/xdg-go/stringprep v1.0.4 // indirect
126+
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect
127+
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
128+
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
109129
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect
110130
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 // indirect
111131
go.etcd.io/bbolt v1.3.7 // indirect
@@ -127,41 +147,38 @@ require (
127147
go.uber.org/atomic v1.7.0 // indirect
128148
go.uber.org/multierr v1.6.0 // indirect
129149
go.uber.org/zap v1.17.0 // indirect
130-
golang.org/x/crypto v0.21.0 // indirect
131-
golang.org/x/exp v0.0.0-20230315142452-642cacee5cc0 // indirect
132-
golang.org/x/mod v0.10.0 // indirect
133-
golang.org/x/net v0.23.0 // indirect
134-
golang.org/x/sys v0.18.0 // indirect
135-
golang.org/x/term v0.18.0 // indirect
150+
golang.org/x/crypto v0.22.0 // indirect
151+
golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8 // indirect
152+
golang.org/x/mod v0.16.0 // indirect
153+
golang.org/x/net v0.24.0 // indirect
154+
golang.org/x/sync v0.7.0 // indirect
155+
golang.org/x/sys v0.19.0 // indirect
156+
golang.org/x/term v0.19.0 // indirect
136157
golang.org/x/text v0.14.0 // indirect
137-
golang.org/x/time v0.0.0-20220224211638-0e9765cccd65 // indirect
138-
golang.org/x/tools v0.9.1 // indirect
139-
google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d // indirect
140-
google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d // indirect
141-
google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect
142-
google.golang.org/grpc v1.59.0 // indirect
158+
golang.org/x/time v0.3.0 // indirect
159+
golang.org/x/tools v0.19.0 // indirect
160+
google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b // indirect
161+
google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b // indirect
162+
google.golang.org/genproto/googleapis/rpc v0.0.0-20231030173426-d783a09b4405 // indirect
143163
google.golang.org/protobuf v1.33.0 // indirect
144164
gopkg.in/errgo.v1 v1.0.1 // indirect
145165
gopkg.in/macaroon-bakery.v2 v2.0.1 // indirect
146166
gopkg.in/macaroon.v2 v2.1.0 // indirect
147167
gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
148168
gopkg.in/yaml.v2 v2.4.0 // indirect
149169
gopkg.in/yaml.v3 v3.0.1 // indirect
150-
lukechampine.com/uint128 v1.2.0 // indirect
151-
modernc.org/cc/v3 v3.40.0 // indirect
152-
modernc.org/ccgo/v3 v3.16.13 // indirect
153-
modernc.org/libc v1.22.2 // indirect
154-
modernc.org/mathutil v1.5.0 // indirect
155-
modernc.org/memory v1.4.0 // indirect
156-
modernc.org/opt v0.1.3 // indirect
157-
modernc.org/sqlite v1.20.3 // indirect
158-
modernc.org/strutil v1.1.3 // indirect
159-
modernc.org/token v1.0.1 // indirect
170+
modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 // indirect
171+
modernc.org/libc v1.49.3 // indirect
172+
modernc.org/mathutil v1.6.0 // indirect
173+
modernc.org/memory v1.8.0 // indirect
174+
modernc.org/sqlite v1.29.10 // indirect
175+
modernc.org/strutil v1.2.0 // indirect
176+
modernc.org/token v1.1.0 // indirect
160177
sigs.k8s.io/yaml v1.2.0 // indirect
161178
)
162179

163180
// We want to format raw bytes as hex instead of base64. The forked version
164181
// allows us to specify that as an option.
165182
replace google.golang.org/protobuf => github.com/lightninglabs/protobuf-go-hex-display v1.30.0-hex-display
166183

167-
go 1.21
184+
go 1.21.4

0 commit comments

Comments
 (0)