counted block size by vote vs non-vote tx
This commit is contained in:
parent
e46d20d68e
commit
6fa9afb6aa
|
@ -13,20 +13,24 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
SkipStatusLabel = "status"
|
||||
StateLabel = "state"
|
||||
NodekeyLabel = "nodekey"
|
||||
VotekeyLabel = "votekey"
|
||||
VersionLabel = "version"
|
||||
AddressLabel = "address"
|
||||
EpochLabel = "epoch"
|
||||
IdentityLabel = "identity"
|
||||
SkipStatusLabel = "status"
|
||||
StateLabel = "state"
|
||||
NodekeyLabel = "nodekey"
|
||||
VotekeyLabel = "votekey"
|
||||
VersionLabel = "version"
|
||||
AddressLabel = "address"
|
||||
EpochLabel = "epoch"
|
||||
IdentityLabel = "identity"
|
||||
TransactionTypeLabel = "transaction_type"
|
||||
|
||||
StatusSkipped = "skipped"
|
||||
StatusValid = "valid"
|
||||
|
||||
StateCurrent = "current"
|
||||
StateDelinquent = "delinquent"
|
||||
|
||||
TransactionTypeVote = "vote"
|
||||
TransactionTypeTotal = "total"
|
||||
)
|
||||
|
||||
type SolanaCollector struct {
|
||||
|
|
|
@ -42,7 +42,7 @@ type SlotWatcher struct {
|
|||
InflationRewardsMetric *prometheus.GaugeVec
|
||||
FeeRewardsMetric *prometheus.CounterVec
|
||||
BlockSizeMetric *prometheus.GaugeVec
|
||||
BlockHeight *prometheus.GaugeVec
|
||||
BlockHeightMetric *prometheus.GaugeVec
|
||||
}
|
||||
|
||||
func NewSlotWatcher(client rpc.Provider, config *ExporterConfig) *SlotWatcher {
|
||||
|
@ -111,9 +111,9 @@ func NewSlotWatcher(client rpc.Provider, config *ExporterConfig) *SlotWatcher {
|
|||
Name: "solana_block_size",
|
||||
Help: fmt.Sprintf("Number of transactions per block, grouped by %s", NodekeyLabel),
|
||||
},
|
||||
[]string{NodekeyLabel},
|
||||
[]string{NodekeyLabel, TransactionTypeLabel},
|
||||
),
|
||||
BlockHeight: prometheus.NewGaugeVec(
|
||||
BlockHeightMetric: prometheus.NewGaugeVec(
|
||||
prometheus.GaugeOpts{
|
||||
Name: "solana_block_height",
|
||||
Help: fmt.Sprintf("The current block height of the node, grouped by %s", IdentityLabel),
|
||||
|
@ -134,7 +134,7 @@ func NewSlotWatcher(client rpc.Provider, config *ExporterConfig) *SlotWatcher {
|
|||
watcher.InflationRewardsMetric,
|
||||
watcher.FeeRewardsMetric,
|
||||
watcher.BlockSizeMetric,
|
||||
watcher.BlockHeight,
|
||||
watcher.BlockHeightMetric,
|
||||
} {
|
||||
if err := prometheus.Register(collector); err != nil {
|
||||
var (
|
||||
|
@ -179,7 +179,7 @@ func (c *SlotWatcher) WatchSlots(ctx context.Context) {
|
|||
|
||||
c.TotalTransactionsMetric.Set(float64(epochInfo.TransactionCount))
|
||||
c.SlotHeightMetric.Set(float64(epochInfo.AbsoluteSlot))
|
||||
c.BlockHeight.WithLabelValues(c.config.Identity).Set(float64(epochInfo.BlockHeight))
|
||||
c.BlockHeightMetric.WithLabelValues(c.config.Identity).Set(float64(epochInfo.BlockHeight))
|
||||
|
||||
// if we get here, then the tracking numbers are set, so this is a "normal" run.
|
||||
// start by checking if we have progressed since last run:
|
||||
|
@ -363,13 +363,11 @@ func (c *SlotWatcher) fetchAndEmitBlockInfos(ctx context.Context, endSlot int64)
|
|||
|
||||
// fetchAndEmitSingleBlockInfo fetches and emits the fee reward + block size for a single block.
|
||||
func (c *SlotWatcher) fetchAndEmitSingleBlockInfo(
|
||||
ctx context.Context, identity string, epoch int64, slot int64,
|
||||
ctx context.Context, nodekey string, epoch int64, slot int64,
|
||||
) error {
|
||||
var transactionDetails string
|
||||
transactionDetails := "none"
|
||||
if c.config.MonitorBlockSizes {
|
||||
transactionDetails = "accounts"
|
||||
} else {
|
||||
transactionDetails = "none"
|
||||
transactionDetails = "full"
|
||||
}
|
||||
block, err := c.client.GetBlock(ctx, rpc.CommitmentConfirmed, slot, transactionDetails)
|
||||
if err != nil {
|
||||
|
@ -388,19 +386,25 @@ func (c *SlotWatcher) fetchAndEmitSingleBlockInfo(
|
|||
if reward.RewardType == "fee" {
|
||||
// make sure we haven't made a logic issue or something:
|
||||
assertf(
|
||||
reward.Pubkey == identity,
|
||||
reward.Pubkey == nodekey,
|
||||
"fetching fee reward for %v but got fee reward for %v",
|
||||
identity,
|
||||
nodekey,
|
||||
reward.Pubkey,
|
||||
)
|
||||
amount := float64(reward.Lamports) / float64(rpc.LamportsInSol)
|
||||
c.FeeRewardsMetric.WithLabelValues(identity, toString(epoch)).Add(amount)
|
||||
c.FeeRewardsMetric.WithLabelValues(nodekey, toString(epoch)).Add(amount)
|
||||
}
|
||||
}
|
||||
|
||||
// track block size:
|
||||
if c.config.MonitorBlockSizes {
|
||||
c.BlockSizeMetric.WithLabelValues(identity).Set(float64(len(block.Transactions)))
|
||||
c.BlockSizeMetric.WithLabelValues(nodekey, TransactionTypeTotal).Set(float64(len(block.Transactions)))
|
||||
// now count and emit votes:
|
||||
voteCount, err := CountVoteTransactions(block)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.BlockHeightMetric.WithLabelValues(nodekey, TransactionTypeVote).Set(float64(voteCount))
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
|
@ -2,12 +2,15 @@ package main
|
|||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/asymmetric-research/solana_exporter/pkg/rpc"
|
||||
"github.com/asymmetric-research/solana_exporter/pkg/slog"
|
||||
"slices"
|
||||
)
|
||||
|
||||
const VoteProgram = "Vote111111111111111111111111111111111111111"
|
||||
|
||||
func assertf(condition bool, format string, args ...any) {
|
||||
logger := slog.Get()
|
||||
if !condition {
|
||||
|
@ -121,3 +124,22 @@ func GetEpochBounds(info *rpc.EpochInfo) (int64, int64) {
|
|||
firstSlot := info.AbsoluteSlot - info.SlotIndex
|
||||
return firstSlot, firstSlot + info.SlotsInEpoch - 1
|
||||
}
|
||||
|
||||
func CountVoteTransactions(block *rpc.Block) (int, error) {
|
||||
txData, err := json.Marshal(block.Transactions)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("failed to marshal transactions: %w", err)
|
||||
}
|
||||
var transactions []rpc.FullTransaction
|
||||
if err := json.Unmarshal(txData, &transactions); err != nil {
|
||||
return 0, fmt.Errorf("failed to unmarshal transactions: %w", err)
|
||||
}
|
||||
|
||||
voteCount := 0
|
||||
for _, tx := range transactions {
|
||||
if slices.Contains(tx.Transaction.Message.AccountKeys, VoteProgram) {
|
||||
voteCount++
|
||||
}
|
||||
}
|
||||
return voteCount, nil
|
||||
}
|
||||
|
|
|
@ -98,9 +98,18 @@ type (
|
|||
RewardType string `json:"rewardType"`
|
||||
Commission uint8 `json:"commission"`
|
||||
}
|
||||
|
||||
Identity struct {
|
||||
Identity string `json:"identity"`
|
||||
}
|
||||
|
||||
FullTransaction struct {
|
||||
Transaction struct {
|
||||
Message struct {
|
||||
AccountKeys []string `json:"accountKeys"`
|
||||
} `json:"message"`
|
||||
} `json:"transaction"`
|
||||
}
|
||||
)
|
||||
|
||||
func (e *RPCError) Error() string {
|
||||
|
|
Loading…
Reference in New Issue