Skip to content

Commit

Permalink
Merge pull request #87 from asymmetric-research/final-touches
Browse files Browse the repository at this point in the history
Final touches
  • Loading branch information
johnstonematt authored Feb 10, 2025
2 parents 48790ac + e578cc1 commit 60a87ab
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 35 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/go-test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ jobs:
run: go test -v -coverprofile=coverage.out ./...

- name: Upload coverage report
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: coverage-report
path: coverage.out
path: coverage.out
55 changes: 32 additions & 23 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,26 @@ and more configurability.
Below is a list of newly added metrics (see the [README](README.md)
for metric descriptions):

* `solana_account_balance` (<u><strong>[@johnstonematt](https://github.com/johnstonematt)</strong></u>)
* `solana_node_is_healthy` (<u><strong>[@GranderStark](https://github.com/GranderStark)</strong></u>)
* `solana_nude_num_slots_behind` (<u><strong>[@GranderStark](https://github.com/GranderStark)</strong></u>)
* `solana_node_minimum_ledger_slot` (<u><strong>[@GranderStark](https://github.com/GranderStark)</strong></u>)
* `solana_node_first_available_block` (<u><strong>[@GranderStark](https://github.com/GranderStark)</strong></u>)
* `solana_cluster_slots_by_epoch_total` (<u><strong>[@johnstonematt](https://github.com/johnstonematt)</strong></u>)
* `solana_validator_fee_rewards` (<u><strong>[@johnstonematt](https://github.com/johnstonematt)</strong></u>)
* `solana_validator_block_size` (<u><strong>[@johnstonematt](https://github.com/johnstonematt)</strong></u>)
* `solana_node_block_height` (<u><strong>[@GranderStark](https://github.com/GranderStark)</strong></u>)
* `solana_cluster_active_stake` (<u><strong>[@johnstonematt](https://github.com/johnstonematt)</strong></u>)
* `solana_cluster_last_vote` (<u><strong>[@johnstonematt](https://github.com/johnstonematt)</strong></u>)
* `solana_cluster_root_slot` (<u><strong>[@johnstonematt](https://github.com/johnstonematt)</strong></u>)
* `solana_cluster_validator_count` (<u><strong>[@johnstonematt](https://github.com/johnstonematt)</strong></u>)
* `solana_account_balance` (**[@johnstonematt](https://github.com/johnstonematt)**)
* `solana_node_is_healthy` (**[@GranderStark](https://github.com/GranderStark)**)
* `solana_node_num_slots_behind` (**[@GranderStark](https://github.com/GranderStark)**)
* `solana_node_minimum_ledger_slot` (**[@GranderStark](https://github.com/GranderStark)**)
* `solana_node_first_available_block` (**[@GranderStark](https://github.com/GranderStark)**)
* `solana_cluster_slots_by_epoch_total` (**[@johnstonematt](https://github.com/johnstonematt)**)
* `solana_validator_fee_rewards` (**[@johnstonematt](https://github.com/johnstonematt)**)
* `solana_validator_block_size` (**[@johnstonematt](https://github.com/johnstonematt)**)
* `solana_node_block_height` (**[@GranderStark](https://github.com/GranderStark)**)
* `solana_cluster_active_stake` (**[@johnstonematt](https://github.com/johnstonematt)**)
* `solana_cluster_last_vote` (**[@johnstonematt](https://github.com/johnstonematt)**)
* `solana_cluster_root_slot` (**[@johnstonematt](https://github.com/johnstonematt)**)
* `solana_cluster_validator_count` (**[@johnstonematt](https://github.com/johnstonematt)**)
* `solana_node_identity` (**[@impactdni2](https://github.com/impactdni2)**)
* `solana_node_is_active` (**[@andreclaro](https://github.com/andreclaro)**)
* `solana_foundation_min_required_version` (**[@qedgardo](https://github.com/qedgardo)**)

#### Renamed Metrics

The table below contains all metrics renamed in `v3.0.0` (<u><strong>[@johnstonematt](https://github.com/johnstonematt)</strong></u>):
The table below contains all metrics renamed in `v3.0.0` (**[@johnstonematt](https://github.com/johnstonematt)**):

| Old Name | New Name |
|---------------------------------------|------------------------------------------------|
Expand All @@ -50,14 +53,14 @@ Metrics were renamed to:

#### Label Updates

The following labels were renamed (<u><strong>[@johnstonematt](https://github.com/johnstonematt)</strong></u>):
The following labels were renamed (**[@johnstonematt](https://github.com/johnstonematt)**):
* `pubkey` was renamed to `votekey`, to clearly identity that it refers to the address of a validators vote account.

### Config Updates
#### New Config Parameters

Below is a list of newly added config parameters (see the [README](README.md)
for parameter descriptions) (<u><strong>[@johnstonematt](https://github.com/johnstonematt)</strong></u>):
for parameter descriptions) (**[@johnstonematt](https://github.com/johnstonematt)**):

* `-balance-address`
* `-nodekey`
Expand All @@ -67,10 +70,12 @@ for parameter descriptions) (<u><strong>[@johnstonematt](https://github.com/john
* `-light-mode`
* `-http-timeout`
* `-comprehensive-vote-account-tracking`
* `-active-identity`
* `epoch-cleanup-time`

#### Renamed Config Parameters

The table below contains all config parameters renamed in `v3.0.0` (<u><strong>[@johnstonematt](https://github.com/johnstonematt)</strong></u>):
The table below contains all config parameters renamed in `v3.0.0` (**[@johnstonematt](https://github.com/johnstonematt)**):

| Old Name | New Name |
|-------------------------------------|-------------------|
Expand All @@ -79,21 +84,25 @@ The table below contains all config parameters renamed in `v3.0.0` (<u><strong>[

#### Removed Config Parameters

The following metrics were removed (<u><strong>[@johnstonematt](https://github.com/johnstonematt)</strong></u>):
The following metrics were removed (**[@johnstonematt](https://github.com/johnstonematt)**):

* `votepubkey`. Configure validator tracking using the `-nodekey` parameter.

### General Updates

* The project was renamed from `solana_exporter` to `solana-exporter`, to conform with
[Go naming conventions](https://github.com/unknwon/go-code-convention/blob/main/en-US.md) (<u><strong>[@johnstonematt](https://github.com/johnstonematt)</strong></u>).
* Testing was significantly improved (<u><strong>[@johnstonematt](https://github.com/johnstonematt)</strong></u>).
[Go naming conventions](https://github.com/unknwon/go-code-convention/blob/main/en-US.md) (**[@johnstonematt](https://github.com/johnstonematt)**).
* Testing was significantly improved (**[@johnstonematt](https://github.com/johnstonematt)**).
* [klog](https://github.com/kubernetes/klog) logging was removed and replaced with [zap](https://github.com/uber-go/zap)
(<u><strong>[@johnstonematt](https://github.com/johnstonematt)</strong></u>)
* Easy usage (<u><strong>[@johnstonematt](https://github.com/johnstonematt)</strong></u>):
(**[@johnstonematt](https://github.com/johnstonematt)**)
* Easy usage (**[@johnstonematt](https://github.com/johnstonematt)**):
* The example dashboard was updated.
* An example prometheus config was added, as well as recording rules for tracking skip rate.

## New Contributors

* <u><strong>[@GranderStark](https://github.com/GranderStark)</strong></u> made their first contribution.
* **[@GranderStark](https://github.com/GranderStark)** made their first contribution in **[#33](https://github.com/asymmetric-research/solana-exporter/pull/33)**.
* **[@dylanschultzie](https://github.com/dylanschultzie)** made their first contribution in **[#49](https://github.com/asymmetric-research/solana-exporter/pull/49)**.
* **[@impactdni2](https://github.com/impactdni2)** made their first contribution in **[#83](https://github.com/asymmetric-research/solana-exporter/pull/83)**.
* **[@andreclaro](https://github.com/andreclaro)** made their first contribution in **[#84](https://github.com/asymmetric-research/solana-exporter/pull/84)**.
* **[@qedgardo](https://github.com/quedgardo)** made their first contribution in **[#85](https://github.com/asymmetric-research/solana-exporter/pull/85)**.
57 changes: 52 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,61 @@ solana-exporter \
-balance-address <ADDRESS_1> -balance-address <ADDRESS_2> \
-comprehensive-slot-tracking \
-monitor-block-sizes
-active-identity <MY_ACTIVE_IDENTITY>
```

![Solana Exporter Dashboard Sample](assets/solana-dashboard-screenshot.png)

### Features
#### Balance Tracking

Using the `-balance-address <ADDRESS>` configuration parameter, the exporter can be used to monitor any account's
SOL balance. This parameter can be set multiple times to track multiple accounts. Additionally, the balance of all
configured `-nodekey`'s is automatically tracked.

#### Block Sizes

If the `-monitor-block-sizes` flag is set, then the exporter will export the number of transactions (both vote-only and
non-vote transactions) in blocks produced by the monitored validators. This is a critical validator performance metric.

Cluster average block size can be inferred by dividing total network transactions by total block height.

#### Income Reporting

The exporter exports metrics regarding total priority fee revenue and inflation reward revenue earned by the
monitored validators.

#### Skip Rate

The exporter does not directly export skip rate, as this needs to be defined as an average over a desired timeframe.
However, the exporter does track the monitored validators leader slots and whether they are `valid` or `skipped`.

The example prometheus setup contains [recording rules](prometheus/solana-rules.yml) for measuring average skip rate
for both individual validators and a cluster-level over hourly, daily and epoch intervals.

#### Active/Passive Monitoring

The `solana_node_is_active` metric simply reports whether the node (on which the exporter is running) has the same
identity-keypair as that configured with the `-active-identity` flag. The `-active-identity` flag should be used to
specify the primary identity when using a
[non-delinquent backup validator](https://pumpkins-pool.gitbook.io/pumpkins-pool).

#### Light Mode

Certain metrics, such as validator leader slots, income, block size and active stake, are visible on-chain through any
trusted node. However, other metrics such as node health and block height can only be viewed from an exporter running
on the node in question. Thus, on a node in which fine margins of performance are of critical interest, the exporter
can be set to `-light-mode`. In light mode, it will only export metrics that cannot be viewed from other nodes.

This is particularly useful in setups that contain an important validator and utility RPC node - the exporter can be
run in light mode on the validator and in full capacity on the RPC node (configured to monitor the validator through
use of the `-nodekey` parameter).

#### General Performance and Health

In addition to the above features, the exporter provides key metrics for monitoring Solana node health and performance.
See [Metrics](#metrics) below for more details.

## Installation
### Build

Expand Down Expand Up @@ -49,6 +100,7 @@ The exporter is configured via the following command line arguments:
| `-rpc-url` | Solana RPC URL (including protocol and path), e.g., `"http://localhost:8899"` or `"https://api.mainnet-beta.solana.com"` | `"http://localhost:8899"` |
| `-slot-pace` | This is the time (in seconds) between slot-watching metric collections | `1` |
| `-active-identity` | Validator identity public key used to determine if the node is considered active in the `solana_node_is_active` metric. | N/A |
| `-epoch-cleanup-time` | The time to wait before cleaning old epoch metrics from the prometheus endpoint. | |

### Notes on Configuration

Expand Down Expand Up @@ -96,11 +148,6 @@ The tables below describes all the metrics collected by the `solana-exporter`:
| `solana_node_is_active` | Whether the node is active and participating in consensus. | `identity` |
| `solana_foundation_min_required_version` | Minimum required Solana version for the [solana foundation delegation program](https://solana.org/delegation-program) | `version`, `cluster` |

#### Light Mode

In `-light-mode`, the exporter will only track metrics that uniquely to the node being queried. These metric names
all begin with `solana_node_*`.

#### Vote Account Metrics

The following metrics are all received from the `getVoteAccounts` [RPC endpoint](https://solana.com/docs/rpc/http/getvoteaccounts):
Expand Down
6 changes: 1 addition & 5 deletions pkg/rpc/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,12 @@ const (
// CommitmentProcessed level represents a transaction that has been received by the network and included in a block.
CommitmentProcessed Commitment = "processed"

// Genesis hashes for different Solana clusters
DevnetGenesisHash = "EtWTRABZaYq6iMfeYKouRu166VU2xqa1wcaWoxPkrZBG"
TestnetGenesisHash = "4uhcVJyU9pJkvQyS88uRDiswHXSCkY3zQawwpjk2NsNY"
MainnetGenesisHash = "5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpKuc147dw2N9d"
)

// getClusterFromGenesisHash returns the cluster name based on the genesis hash
// GetClusterFromGenesisHash returns the cluster name based on the genesis hash
func GetClusterFromGenesisHash(hash string) (string, error) {
switch hash {
case DevnetGenesisHash:
Expand Down Expand Up @@ -133,7 +132,6 @@ func (c *Client) GetEpochInfo(ctx context.Context, commitment Commitment) (*Epoc
func (c *Client) GetVoteAccounts(ctx context.Context, commitment Commitment) (*VoteAccounts, error) {
// format params:
config := map[string]string{"commitment": string(commitment)}

var resp Response[VoteAccounts]
if err := getResponse(ctx, c, "getVoteAccounts", []any{config}, &resp); err != nil {
return nil, err
Expand Down Expand Up @@ -186,7 +184,6 @@ func (c *Client) GetBlockProduction(
"commitment": string(commitment),
"range": map[string]int64{"firstSlot": firstSlot, "lastSlot": lastSlot},
}

// make request:
var resp Response[contextualResult[BlockProduction]]
if err := getResponse(ctx, c, "getBlockProduction", []any{config}, &resp); err != nil {
Expand All @@ -213,7 +210,6 @@ func (c *Client) GetInflationReward(
) ([]InflationReward, error) {
// format params:
config := map[string]any{"commitment": string(commitment), "epoch": epoch}

var resp Response[[]InflationReward]
if err := getResponse(ctx, c, "getInflationReward", []any{addresses, config}, &resp); err != nil {
return nil, err
Expand Down

0 comments on commit 60a87ab

Please sign in to comment.