From 4396fa7244f18f65a9ee96331fb17a8e9a778994 Mon Sep 17 00:00:00 2001 From: Chris Marslender Date: Tue, 11 Apr 2023 11:24:35 -0500 Subject: [PATCH 1/4] Add costs for types of tx --- internal/metrics/fullnode.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/internal/metrics/fullnode.go b/internal/metrics/fullnode.go index 6c98273..6ca3067 100644 --- a/internal/metrics/fullnode.go +++ b/internal/metrics/fullnode.go @@ -21,6 +21,14 @@ import ( // Metrics that are based on Full Node RPC calls are in this file +// Fee data is based on the estimates here https://github.com/Chia-Network/chia-blockchain/blob/37fcafa0d31358f6ff7276a78764a0cc7ffeb030/chia/rpc/full_node_rpc_api.py#L754 +const ( + CostSendXch = 9401710 + CostSendCat = 36382111 + CostTransferNFT = 74385541 + CostTakeOffer = 721393265 +) + // FullNodeServiceMetrics contains all metrics related to the full node type FullNodeServiceMetrics struct { // Holds a reference to the main metrics container this is a part of From f8914c02625514b7e40808cecdf71794c8c5e169 Mon Sep 17 00:00:00 2001 From: Chris Marslender Date: Tue, 11 Apr 2023 12:46:38 -0500 Subject: [PATCH 2/4] Get fee estimates when we get a new block --- go.mod | 2 +- go.sum | 4 +-- internal/metrics/fullnode.go | 51 ++++++++++++++++++++++++++++++++---- 3 files changed, 49 insertions(+), 8 deletions(-) diff --git a/go.mod b/go.mod index 81f80ab..fbb39fe 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/chia-network/chia-exporter go 1.18 require ( - github.com/chia-network/go-chia-libs v0.3.0 + github.com/chia-network/go-chia-libs v0.3.1 github.com/chia-network/go-modules v0.0.3 github.com/oschwald/maxminddb-golang v1.10.0 github.com/prometheus/client_golang v1.14.0 diff --git a/go.sum b/go.sum index fee0da8..51244b3 100644 --- a/go.sum +++ b/go.sum @@ -51,8 +51,8 @@ github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/chia-network/go-chia-libs v0.3.0 h1:/1q2MUxfMnzyLXZbIY1HhFtUiOvXnYbEoqORfcKnYRE= -github.com/chia-network/go-chia-libs v0.3.0/go.mod h1:yn3u6UDp5zdWvGY37PbPMK4HRW/GU8lw0psMx6J8sb0= +github.com/chia-network/go-chia-libs v0.3.1 h1:aDXj/aT1XUif3mjNYK4ufghNhE1fe4IfWh9nmas2sb0= +github.com/chia-network/go-chia-libs v0.3.1/go.mod h1:yn3u6UDp5zdWvGY37PbPMK4HRW/GU8lw0psMx6J8sb0= github.com/chia-network/go-modules v0.0.3 h1:hLYUW8Uqzt7fjTKIrIdqIfbui2Yw3NA+2El1sU4rT78= github.com/chia-network/go-modules v0.0.3/go.mod h1:9SHIGLdyHjZqbBxn87SUaBuHdaIolZPp68IJR8UujHE= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= diff --git a/internal/metrics/fullnode.go b/internal/metrics/fullnode.go index 6ca3067..f60a3ce 100644 --- a/internal/metrics/fullnode.go +++ b/internal/metrics/fullnode.go @@ -8,11 +8,10 @@ import ( "time" "github.com/chia-network/go-chia-libs/pkg/config" - log "github.com/sirupsen/logrus" - "github.com/chia-network/go-chia-libs/pkg/rpc" "github.com/chia-network/go-chia-libs/pkg/types" "github.com/prometheus/client_golang/prometheus" + log "github.com/sirupsen/logrus" wrappedPrometheus "github.com/chia-network/go-modules/pkg/prometheus" @@ -23,10 +22,10 @@ import ( // Fee data is based on the estimates here https://github.com/Chia-Network/chia-blockchain/blob/37fcafa0d31358f6ff7276a78764a0cc7ffeb030/chia/rpc/full_node_rpc_api.py#L754 const ( - CostSendXch = 9401710 - CostSendCat = 36382111 + CostSendXch = 9401710 + CostSendCat = 36382111 CostTransferNFT = 74385541 - CostTakeOffer = 721393265 + CostTakeOffer = 721393265 ) // FullNodeServiceMetrics contains all metrics related to the full node @@ -45,6 +44,9 @@ type FullNodeServiceMetrics struct { nodeHeightSynced *wrappedPrometheus.LazyGauge nodeSynced *wrappedPrometheus.LazyGauge + // Fee Metrics + feeEstimates *prometheus.GaugeVec + // BlockCount Metrics compactBlocks *wrappedPrometheus.LazyGauge uncompactBlocks *wrappedPrometheus.LazyGauge @@ -88,6 +90,8 @@ func (s *FullNodeServiceMetrics) InitMetrics() { s.nodeHeightSynced = s.metrics.newGauge(chiaServiceFullNode, "node_height_synced", "Current height of the node, when synced. This will register/unregister automatically depending on sync state, and should help make rate() more sane, when you don't want rate of syncing, only rate of the chain.") s.nodeSynced = s.metrics.newGauge(chiaServiceFullNode, "node_synced", "Indicates whether this node is currently synced") + s.feeEstimates = s.metrics.newGaugeVec(chiaServiceFullNode, "fee_estimate", "Estimate of fee required to get a particular transaction cost in a block within a specified timeframe", []string{"type", "cost", "time"}) + // BlockCount Metrics s.compactBlocks = s.metrics.newGauge(chiaServiceFullNode, "compact_blocks", "Number of fully compact blocks in this node's database") s.uncompactBlocks = s.metrics.newGauge(chiaServiceFullNode, "uncompact_blocks", "Number of uncompact blocks in this node's database") @@ -181,6 +185,7 @@ func (s *FullNodeServiceMetrics) ReceiveResponse(resp *types.WebsocketResponse) s.Block(resp) // Ask for block count metrics when we get a new block utils.LogErr(s.metrics.client.FullNodeService.GetBlockCountMetrics()) + go s.GetFeeEstimates() case "get_connections": s.GetConnections(resp) case "get_block_count_metrics": @@ -227,6 +232,42 @@ func (s *FullNodeServiceMetrics) GetBlockchainState(resp *types.WebsocketRespons s.maxBlockCost.Set(float64(state.BlockchainState.BlockMaxCost)) } +// GetFeeEstimates gets fee estimates for the main costs we're estimating, for 1, 5, 15 minute windows +// We do this via http requests via async on the websocket since the fee estimate response doesn't +// indicate which cost the estimate is for +func (s *FullNodeServiceMetrics) GetFeeEstimates() { + toCheck := map[string]uint64{ + "send-xch": CostSendXch, + "send-cat": CostSendCat, + "tx-nft": CostTransferNFT, + "take-offer": CostTakeOffer, + } + + for label, cost := range toCheck { + // Get some fee data + txEstimate, _, err := s.metrics.httpClient.FullNodeService.GetFeeEstimate(&rpc.GetFeeEstimateOptions{ + Cost: cost, + TargetTimes: []uint64{60, 300, 900}, + }) + if err != nil { + continue + } + estimates := txEstimate.Estimates.OrEmpty() + times := txEstimate.TargetTimes.OrEmpty() + if len(estimates) == 0 || len(times) == 0 || len(estimates) != len(times) { + continue + } + + for idx, estimate := range estimates { + targetTime := times[idx] + s.feeEstimates.WithLabelValues( + label, + fmt.Sprintf("%d", cost), + fmt.Sprintf("%d", targetTime)).Set(estimate) + } + } +} + // GetConnections handler for get_connections events func (s *FullNodeServiceMetrics) GetConnections(resp *types.WebsocketResponse) { connectionCountHelper(resp, s.connectionCount) From 76309e4c6cdfd986645dd58ec6517709fd2b8f01 Mon Sep 17 00:00:00 2001 From: Chris Marslender Date: Tue, 11 Apr 2023 12:48:57 -0500 Subject: [PATCH 3/4] Get fee estimates as part of initial data. Reset fee estimates when we lose the connection --- internal/metrics/fullnode.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/internal/metrics/fullnode.go b/internal/metrics/fullnode.go index f60a3ce..db58a9f 100644 --- a/internal/metrics/fullnode.go +++ b/internal/metrics/fullnode.go @@ -128,6 +128,7 @@ func (s *FullNodeServiceMetrics) InitialData() { // Ask for some initial data so we dont have to wait as long utils.LogErr(s.metrics.client.FullNodeService.GetBlockchainState()) // Also calls get_connections once we get the response utils.LogErr(s.metrics.client.FullNodeService.GetBlockCountMetrics()) + s.GetFeeEstimates() // Things that update in the background go func() { @@ -153,6 +154,8 @@ func (s *FullNodeServiceMetrics) Disconnected() { s.nodeHeightSynced.Unregister() s.nodeSynced.Unregister() + s.feeEstimates.Reset() + s.compactBlocks.Unregister() s.uncompactBlocks.Unregister() s.hintCount.Unregister() From dc01eb3f013a5ce5d6beec662803cd5518a8bfeb Mon Sep 17 00:00:00 2001 From: Chris Marslender Date: Tue, 11 Apr 2023 13:18:27 -0500 Subject: [PATCH 4/4] Debug logs --- internal/metrics/fullnode.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/internal/metrics/fullnode.go b/internal/metrics/fullnode.go index db58a9f..f750844 100644 --- a/internal/metrics/fullnode.go +++ b/internal/metrics/fullnode.go @@ -253,11 +253,13 @@ func (s *FullNodeServiceMetrics) GetFeeEstimates() { TargetTimes: []uint64{60, 300, 900}, }) if err != nil { + log.Debugf("Error getting tx estimate: %s\n", err.Error()) continue } estimates := txEstimate.Estimates.OrEmpty() times := txEstimate.TargetTimes.OrEmpty() if len(estimates) == 0 || len(times) == 0 || len(estimates) != len(times) { + log.Debugln("Unexpected TX estimate response (empty or mis-matched estimates/times)") continue }