solana-validator-version-sync

module
v0.1.44 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 17, 2026 License: MIT

README

solana-validator-version-sync

A simple version synchronization manager for Solana validators, including SFDP compliance.

Run doublezero too? Keep it up to date too with doublezero-version-sync

solanna-validator-version-sync

Features

  • 👀 Version Monitoring: Continuously monitors the validator's current running version compared to latest available releases.
  • 👮 SFDP Compliance: Checks version requirements against SFDP (Solana Foundation Delegation Program) bounds.
  • ♻️ Sync Commands: Executes configurable commands when a version sync for the given validator client is required.
  • ⌚ Single-shot or recurring: Run once or on a specified interval
  • ✅ Multiple Clients: Supports agave, jito-solana, rakurai-validator, firedancer, and FireBAM validator client release monitoring.

Installation

From Source
git clone https://github.com/sol-strategies/solana-validator-version-sync.git
cd solana-validator-version-sync
make build
Download pre-built binary

Download the latest release from the Releases page.

Usage

Run Once
solana-validator-version-sync --config config.yaml run
Run Continuously
# can run this command as a systemd service
solana-validator-version-sync --config config.yaml run --on-interval 1h

Configuration

Create a configuration file (e.g., config.yml) with the following options (see config.yml for a working example):

log:
  level: info  # optional, default: info, one of debug|info|warn|error|fatal
  format: text # optional, default: text, one of text|logfmt|json

validator:
  client: agave                          # required, one of agave|jito-solana|rakurai-validator|firedancer|firebam (legacy alias: rakurai)
  # release_track: frankendancer         # required only for firebam, one of frankendancer|firedancer
  version_constraint: ">= 2.3.6, < 3.0.0" # required, a valid go-version semver constraint string - ref https://github.com/hashicorp/go-version
  rpc_url: http://127.0.0.1:8899         # optional, default: http:127.0.0.1:8899 - local validator rpc URL

  # Preferred: resolve the active validator identity from this vote account via getVoteAccounts.
  # The identity is considered active when the vote account is either current or delinquent.
  vote_account_pubkey: <VOTE_ACCOUNT_PUBKEY>

  # Optional passive identity. Public keys avoid reading private key material.
  identities:
    passive_pubkey: <PASSIVE_IDENTITY_PUBKEY>

cluster:
  name: testnet # required - one of mainnet-beta|testnet

sync:
  # Run sync commands even when the validator is active
  # Use with care, usually only for testnet.
  enabled_when_active: false # default: false

  # Run sync commands when no active validator is found in gossip
  # This safeguards against situations where all validators are passive and shouldn't be
  # version synced which would take them out of the would-be active validators pool
  enabled_when_no_active_leader_in_gossip: false # default: false

  # Ensure the target version satisfies SFDP requirements as reported by the API:
  # https://api.solana.org/api/epoch/required_versions
  enable_sfdp_compliance: true # default: false

  # Commands to run when there is a version change. They will run in the order they are declared.  
  # cmd, args, and environment values can be template strings and will be interpolated with the following variables:
  #  .ClusterName                 cluster the validator is running on
  #  .CommandIndex                index of the command in the commands array (zero-based)
  #  .CommandsCount               count of commands in the commands array
  #  .SyncIsSFDPComplianceEnabled true|false (value of sync.enable_sfdp_compliance)
  #  .ValidatorClient             client name (value of validator.client)
  #  .ValidatorReleaseTrack       firebam release track; empty for other clients
  #  .ValidatorIdentityPublicKey  public key of the validator's identity as reported by .ValidatorRPCURL
  #  .ValidatorRole               active|passive
  #  .ValidatorRoleIsActive       true|false
  #  .ValidatorRoleIsPassive      true|false
  #  .ValidatorRPCURL             RPC URL of the validator (value of validator.rpc_url)
  #  .VersionFrom                 current running version as reported by .ValidatorRPCURL
  #  .VersionTo                   sync target version (core semver only, e.g. "4.0.0")
  #  .VersionToTag                full upstream release tag for the sync target (e.g. "v4.0.0-beta.2-jito")
  commands:
    - name: "build"                                      # required - vanity name for logging purposes
      allow_failure: false                               # optional, default:false - when true, errors are logged and subsequent commands executed
      stream_output: true                                # optional, default: false - when true, command output streamed
      disabled: false                                    # optional, default: false - when true, command skipped
      inherit_environment: false                         # optional, default: false - when true, inherit parent env and overlay explicit environment values
      cmd: /home/solana/scripts/build-solana.sh          # required, supports templated string
      args: ["build", "--client={{ .ValidatorClient }}"] # optional, supports templated strings
      environment:                                       # optional, values support templated strings; set inherit_environment: true if these should augment the normal process environment
        TO_VERSION: "{{ .VersionTo }}"
    # ...

For jito-solana, Agave release notes are canonical for cluster eligibility. The sync manager selects the newest Agave-eligible version for which an equivalent Jito tag exists, regardless of the Jito release title prefix.

FireBAM

FireBAM publishes both Frankendancer and native Firedancer releases from the same repository. Select one track explicitly so a sync never migrates between implementations automatically:

validator:
  client: firebam
  release_track: frankendancer
  version_constraint: ">= 0.1100.0, < 1.0.0"
  rpc_url: http://127.0.0.1:8899
  identities:
    active_pubkey: <ACTIVE_IDENTITY_PUBKEY>

Use release_track: firedancer with an appropriate 1.x constraint for native Firedancer. The client and track are configuration-driven because the standard Solana getVersion response does not reliably distinguish FireBAM from upstream Firedancer.

Exactly one active identity source must be configured:

  • validator.vote_account_pubkey (preferred): dynamically resolves the active identity from the network.
  • validator.identities.active_pubkey: uses a configured identity public key directly.
  • validator.identities.active: legacy path to an active identity keypair file.

Native Firedancer v1+ and FireBAM with release_track: firedancer v1+ do not expose the getVoteAccounts RPC method. For those clients, configure validator.identities.active_pubkey or the legacy validator.identities.active keypair file; vote_account_pubkey cannot be used to discover the active identity. FireBAM with release_track: frankendancer retains standard vote-account discovery.

The passive identity is optional. Configure at most one of validator.identities.passive_pubkey or the legacy validator.identities.passive keypair path. When a passive identity is configured, any local identity matching neither active nor passive is treated as unknown and syncing is skipped. A configuration using only public keys does not read either keypair file.

For example, a static, file-free configuration is:

validator:
  client: agave
  version_constraint: ">= 2.3.6, < 3.0.0"
  rpc_url: http://127.0.0.1:8899
  identities:
    active_pubkey: <ACTIVE_IDENTITY_PUBKEY>
    passive_pubkey: <PASSIVE_IDENTITY_PUBKEY>

Legacy active and passive keypair paths remain supported for compatibility. When either is configured, the application prints a startup warning recommending the equivalent public-key or vote-account configuration. Public IP addresses are not used for role detection because gossip addresses are not an authoritative one-to-one mapping between hosts and voting identities.

If a command defines environment while inherit_environment remains false, the command runs with only the explicit environment block and does not inherit the parent process environment. Set inherit_environment: true when the command depends on inherited variables such as PATH, HOME, or service-injected credentials.

Development

Prerequisites
  • Go 1.26.5 or later
  • Make
  • Docker (for Docker development)
Local Development
# Build and run locally
make build
make dev

# Build for all platforms
make build-all

# Run tests
make test

# Clean build artifacts
make clean
Docker Development
# Start development environment with Docker Compose
make dev-docker

# Stop development environment
make dev-docker-stop

# Build Docker image
make docker-build

License

This project is licensed under the MIT License - see the LICENSE file for details.

Directories

Path Synopsis
cmd
internal
rpc

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL