state

package
v0.1.0-alpha.1 Latest Latest
Warning

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

Go to latest
Published: Jan 15, 2026 License: Apache-2.0 Imports: 8 Imported by: 0

Documentation

Index

Constants

View Source
const (
	ShutdownReasonNormal         = "graceful shutdown (Ctrl+C)"
	ShutdownReasonStall          = "block fetch stalled - no RPC progress for 5+ minutes"
	ShutdownReasonLeaderSchedule = "leader schedule fetch failed from all RPC endpoints"
	ShutdownReasonError          = "replay error" // Will be suffixed with actual error
	ShutdownReasonCompleted      = "replay completed - reached end slot"
)

Shutdown reason constants - these are stored in the state file and should be human-readable without needing to look up what they mean.

View Source
const CurrentStateSchemaVersion uint32 = 1

CurrentStateSchemaVersion is the current version of the state file format. Increment this when making breaking changes to the state file structure.

View Source
const HistoryFileName = "mithril_state.history.jsonl"
View Source
const MaxHistoryEntries = 500

MaxHistoryEntries is the maximum number of history entries to retain.

View Source
const StateFileName = "mithril_state.json"

Variables

This section is empty.

Functions

func AppendHistory

func AppendHistory(accountsDbDir string, entry StateHistoryEntry) error

AppendHistory appends a history entry to the state history file. The history file is append-only JSONL format.

func DeleteState

func DeleteState(accountsDbDir string) error

DeleteState removes the state file from the accountsdb directory.

func PruneHistory

func PruneHistory(accountsDbDir string) error

PruneHistory removes old entries if history exceeds MaxHistoryEntries. Should be called on startup to prevent unbounded growth.

func RecordBootstrap

func RecordBootstrap(accountsDbDir string, slot uint64, bankhash, runID, version, commit, branch string) error

RecordBootstrap records a bootstrap event in the history.

func RecordCorrupted

func RecordCorrupted(accountsDbDir string, slot uint64, bankhash, runID, version, commit, branch, reason string) error

RecordCorrupted records a corruption event in the history.

func RecordRebuild

func RecordRebuild(accountsDbDir string, slot uint64, bankhash, version, commit, branch, reason string) error

RecordRebuild records when AccountsDB is about to be cleaned/rebuilt. This should be called BEFORE CleanAccountsDbDir to preserve the history.

func RecordResume

func RecordResume(accountsDbDir string, slot uint64, bankhash, runID, version, commit, branch string) error

RecordResume records a resume event in the history.

func RecordShutdown

func RecordShutdown(accountsDbDir string, slot uint64, bankhash, runID, version, commit, branch, reason string) error

RecordShutdown records a shutdown event in the history.

func ValidateAccountsDbArtifacts

func ValidateAccountsDbArtifacts(accountsDbDir string) error

ValidateAccountsDbArtifacts checks if expected AccountsDB artifacts exist. This provides an extra layer of validation beyond just checking the state file.

Types

type BankhashGetter

type BankhashGetter interface {
	GetBankHashForSlot(slot uint64) ([]byte, error)
}

BankhashGetter is an interface for getting bankhashes by slot. This is used for integrity validation without creating import cycles.

type BlockhashEntry

type BlockhashEntry struct {
	Blockhash            string `json:"blockhash"`
	LamportsPerSignature uint64 `json:"lamports_per_sig"`
}

BlockhashEntry represents a single entry in the RecentBlockhashes sysvar

type HistoryEvent

type HistoryEvent string

HistoryEvent represents the type of state change event.

const (
	HistoryEventBootstrap HistoryEvent = "bootstrap"
	HistoryEventShutdown  HistoryEvent = "shutdown"
	HistoryEventCorrupted HistoryEvent = "corrupted"
	HistoryEventResume    HistoryEvent = "resume"
	HistoryEventRebuild   HistoryEvent = "rebuild" // AccountsDB being cleaned/rebuilt
)

type MithrilState

type MithrilState struct {
	// =========================================================================
	// Schema & Run Lineage
	// =========================================================================
	StateSchemaVersion uint32 `json:"state_schema_version"`
	// Run lineage - tracks the chain of sessions that have used this AccountsDB
	RootRunID    string `json:"root_run_id,omitempty"`    // Run that built AccountsDB from snapshot (never changes)
	ParentRunID  string `json:"parent_run_id,omitempty"`  // Run we resumed from (empty if fresh start)
	CurrentRunID string `json:"current_run_id,omitempty"` // Run that last wrote this file

	// =========================================================================
	// Writer Metadata (who last wrote this file and why they stopped)
	// =========================================================================
	LastWriterVersion  string    `json:"last_writer_version,omitempty"`  // Semver tag (e.g., "v0.1.0" or "dev")
	LastWriterCommit   string    `json:"last_writer_commit,omitempty"`   // Git commit hash of writer binary
	LastWriterBranch   string    `json:"last_writer_branch,omitempty"`   // Git branch name (may be empty)
	LastShutdownReason string    `json:"last_shutdown_reason,omitempty"` // human-readable reason
	LastShutdownAt     time.Time `json:"last_shutdown_at,omitempty"`     // when shutdown occurred

	// =========================================================================
	// AccountsDB Origin (snapshot info - set once, never changes)
	// =========================================================================
	Stage          string        `json:"stage"`                        // "ready", "downloading", "building", "corrupted"
	SnapshotSlot   uint64        `json:"snapshot_slot"`                // Slot of the snapshot used to build AccountsDB
	SnapshotEpoch  uint64        `json:"snapshot_epoch,omitempty"`     // Epoch of the snapshot
	FullSnapshot   *SnapshotInfo `json:"full_snapshot,omitempty"`      // Full snapshot file info
	IncrSnapshot   *SnapshotInfo `json:"incr_snapshot,omitempty"`      // Incremental snapshot file info
	BuildCompleted time.Time     `json:"build_completed_at,omitempty"` // When AccountsDB build finished
	BuildStartedAt time.Time     `json:"build_started_at,omitempty"`   // When bootstrap started
	BuildMode      string        `json:"build_mode,omitempty"`         // "auto", "snapshot", "new-snapshot", "accountsdb"
	Cluster        string        `json:"cluster,omitempty"`            // "mainnet-beta", "testnet", "devnet"
	GenesisHash    string        `json:"genesis_hash,omitempty"`       // Base58 genesis hash from RPC

	// Corruption tracking - set when integrity check fails
	CorruptionReason     string    `json:"corruption_reason,omitempty"`
	CorruptionDetectedAt time.Time `json:"corruption_detected_at,omitempty"`

	// =========================================================================
	// Current Position (where we left off)
	// =========================================================================
	LastSlot     uint64 `json:"last_slot,omitempty"`     // Last successfully replayed slot
	LastEpoch    uint64 `json:"last_epoch,omitempty"`    // Epoch of last replayed slot
	LastBankhash string `json:"last_bankhash,omitempty"` // Bankhash of last replayed slot (base58)

	// LtHash and fee state
	LastAcctsLtHash          string `json:"last_accts_lt_hash,omitempty"`         // base64 encoded cumulative LtHash
	LastLamportsPerSignature uint64 `json:"last_lamports_per_sig,omitempty"`      // FeeRateGovernor.LamportsPerSignature
	LastPrevLamportsPerSig   uint64 `json:"last_prev_lamports_per_sig,omitempty"` // FeeRateGovernor.PrevLamportsPerSignature
	LastNumSignatures        uint64 `json:"last_num_signatures,omitempty"`        // SlotCtx.NumSignatures

	// Blockhash context - required because appendvec writes are not fsynced
	LastRecentBlockhashes []BlockhashEntry `json:"last_recent_blockhashes,omitempty"` // 150 entries, newest first
	LastEvictedBlockhash  string           `json:"last_evicted_blockhash,omitempty"`  // 151st blockhash (base58)
	LastBlockhash         string           `json:"last_blockhash,omitempty"`          // Blockhash of last slot (base58)

	// SlotHashes context - vote program needs accurate slot→hash mappings
	LastSlotHashes []SlotHashEntry `json:"last_slot_hashes,omitempty"` // up to 512 entries, newest first

	// ReplayCtx fields - so resume uses fresh values instead of stale manifest
	LastCapitalization          uint64  `json:"last_capitalization,omitempty"`    // Total lamports in circulation
	LastSlotsPerYear            float64 `json:"last_slots_per_year,omitempty"`    // Slots per year for inflation calc
	LastInflationInitial        float64 `json:"last_inflation_initial,omitempty"` // Inflation parameters
	LastInflationTerminal       float64 `json:"last_inflation_terminal,omitempty"`
	LastInflationTaper          float64 `json:"last_inflation_taper,omitempty"`
	LastInflationFoundation     float64 `json:"last_inflation_foundation,omitempty"`
	LastInflationFoundationTerm float64 `json:"last_inflation_foundation_term,omitempty"`

	// EpochStakes - computed at epoch boundaries, required for leader schedule on resume
	// Key: epoch number (leader schedule epoch), Value: JSON-serialized epoch stakes
	// These are NOT loaded from manifest - they are computed during replay and persisted.
	ComputedEpochStakes map[uint64]string `json:"computed_epoch_stakes,omitempty"`

	// =========================================================================
	// Legacy fields - kept for backwards compatibility
	// =========================================================================
	// TODO: Remove after v1.0 release
	LastCommit string    `json:"last_commit,omitempty"` // Deprecated: use last_writer_commit
	LastRunID  string    `json:"last_run_id,omitempty"` // Deprecated: use current_run_id
	LastRunAt  time.Time `json:"last_run_at,omitempty"` // Deprecated: tracked via last_shutdown_at
}

MithrilState tracks the current state of the mithril node. The state file serves as an atomic marker of validity - AccountsDB is valid if and only if this file exists with Stage == "ready".

func CheckAndLoadValidState

func CheckAndLoadValidState(accountsDbDir string) (*MithrilState, error)

CheckAndLoadValidState loads state and validates that AccountsDB is ready. Returns (state, nil) if valid, or (nil, nil) if state is invalid/missing. Returns (nil, error) only for unexpected errors.

func LoadState

func LoadState(accountsDbDir string) (*MithrilState, error)

LoadState loads the state file from the accountsdb directory. Returns nil and no error if the file doesn't exist. Handles migration from older schema versions automatically.

func NewReadyState

func NewReadyState(snapshotSlot uint64, snapshotEpoch uint64, fullSnapshotPath string, incrSnapshotPath string, incrBaseSlot uint64, incrSlot uint64) *MithrilState

NewReadyState creates a new state marking the AccountsDB as ready.

func NewReadyStateWithOpts

func NewReadyStateWithOpts(opts NewReadyStateOpts) *MithrilState

NewReadyStateWithOpts creates a new state with full options including cluster and version info.

func (*MithrilState) GetCurrentSlot

func (s *MithrilState) GetCurrentSlot() uint64

GetCurrentSlot returns the most recent slot (LastSlot if replayed, else SnapshotSlot).

func (*MithrilState) GetResumeSlot

func (s *MithrilState) GetResumeSlot() uint64

GetResumeSlot returns the slot to resume from. Returns LastSlot + 1 if replay has happened, otherwise SnapshotSlot + 1.

func (*MithrilState) HasResumeData

func (s *MithrilState) HasResumeData() bool

HasResumeData returns true if the state has resume context stored. This indicates the state was saved during a graceful shutdown with full context.

func (*MithrilState) IsCorrupted

func (s *MithrilState) IsCorrupted() bool

IsCorrupted returns true if the state indicates AccountsDB is corrupted.

func (*MithrilState) IsReady

func (s *MithrilState) IsReady() bool

IsReady returns true if the state indicates AccountsDB is valid and ready.

func (*MithrilState) IsStale

func (s *MithrilState) IsStale(latestSlot uint64, threshold uint64) bool

IsStale returns true if the state is significantly behind the given slot.

func (*MithrilState) MarkCorrupted

func (s *MithrilState) MarkCorrupted(accountsDbDir string, reason string) error

MarkCorrupted updates the state file to indicate AccountsDB is corrupted. This persists the corruption status so the next startup knows to rebuild.

func (*MithrilState) Save

func (s *MithrilState) Save(accountsDbDir string) error

Save writes the state to the accountsdb directory.

func (*MithrilState) SetClusterInfo

func (s *MithrilState) SetClusterInfo(cluster, genesisHash string)

SetClusterInfo updates the cluster and genesis hash in the state. Should be called on first run after upgrade if genesis hash is missing.

func (*MithrilState) UpdateLastSlot

func (s *MithrilState) UpdateLastSlot(accountsDbDir string, slot uint64, bankhash []byte) error

UpdateLastSlot updates the last slot and bankhash in the state file. This should be called after successfully committing a slot during replay.

func (*MithrilState) UpdateOnShutdown

func (s *MithrilState) UpdateOnShutdown(accountsDbDir string, slot uint64, bankhash []byte, ctx *ShutdownContext) error

UpdateOnShutdown updates the state file with full shutdown context. This handles the run lineage: the current session's RunID becomes CurrentRunID, and if this is a resume, the previous CurrentRunID becomes ParentRunID.

func (*MithrilState) ValidateAgainstBankhashDB

func (s *MithrilState) ValidateAgainstBankhashDB(bankhashDb BankhashGetter) error

ValidateAgainstBankhashDB checks if AccountsDB has been modified beyond state file. This detects cases where the process was killed (Ctrl+Z, kill -9) without updating the state file, leaving AccountsDB in an inconsistent state.

func (*MithrilState) ValidateGenesisHash

func (s *MithrilState) ValidateGenesisHash(expectedGenesisHash string) error

ValidateGenesisHash checks if the stored genesis hash matches the expected value. Returns an error if there's a mismatch (prevents mainnet/testnet mixups). Returns nil if state has no genesis hash stored (first run after upgrade).

type NewReadyStateOpts

type NewReadyStateOpts struct {
	SnapshotSlot     uint64
	SnapshotEpoch    uint64
	FullSnapshotPath string
	IncrSnapshotPath string
	IncrBaseSlot     uint64
	IncrSlot         uint64
	BuildMode        string // "auto", "snapshot", "new-snapshot", "accountsdb"
	BuildStartedAt   time.Time
	Cluster          string // "mainnet-beta", "testnet", "devnet"
	GenesisHash      string // Base58 genesis hash
	WriterVersion    string // Semver tag
	WriterCommit     string // Git commit hash
}

NewReadyStateOpts contains options for creating a new ready state.

type ShutdownContext

type ShutdownContext struct {
	// Current session's run ID (becomes CurrentRunID in state file)
	RunID string

	// Writer info
	WriterVersion string // Semver tag (e.g., "v0.1.0" or "dev")
	WriterCommit  string // Git commit hash
	WriterBranch  string // Git branch name (may be empty if not available)

	// Shutdown reason
	ShutdownReason string // Why the session ended (see ShutdownReason* constants)

	// Epoch of the last replayed slot
	Epoch uint64

	// LtHash and fee state
	AcctsLtHash          string // base64 encoded
	LamportsPerSignature uint64
	PrevLamportsPerSig   uint64
	NumSignatures        uint64

	// Blockhash context
	RecentBlockhashes []BlockhashEntry // 150 entries, newest first
	EvictedBlockhash  string           // base58 encoded, 151st blockhash
	LastBlockhash     string           // base58 encoded, blockhash of last slot (parent for next)

	// SlotHashes context - vote program uses this to verify slot→hash mappings
	SlotHashes []SlotHashEntry // up to 512 entries, newest first

	// ReplayCtx fields - so resume uses fresh values instead of stale manifest
	Capitalization          uint64  // Total lamports in circulation
	SlotsPerYear            float64 // Slots per year for inflation calc
	InflationInitial        float64
	InflationTerminal       float64
	InflationTaper          float64
	InflationFoundation     float64
	InflationFoundationTerm float64

	// EpochStakes - computed at epoch boundaries, required for leader schedule on resume
	// Key: epoch number, Value: JSON-serialized epoch stakes (as []byte)
	ComputedEpochStakes map[uint64][]byte
}

ShutdownContext contains the data to persist on graceful shutdown. This is passed to UpdateOnShutdown to save the current session state.

type SlotHashEntry

type SlotHashEntry struct {
	Slot uint64 `json:"slot"`
	Hash string `json:"hash"` // base58 encoded
}

SlotHashEntry represents a single entry in the SlotHashes sysvar

type SnapshotInfo

type SnapshotInfo struct {
	Path     string `json:"path"`
	Slot     uint64 `json:"slot"`
	BaseSlot uint64 `json:"base_slot,omitempty"` // only for incrementals
}

SnapshotInfo contains metadata about a downloaded snapshot file.

type StateHistoryEntry

type StateHistoryEntry struct {
	Timestamp time.Time    `json:"ts"`
	Event     HistoryEvent `json:"event"`
	Slot      uint64       `json:"slot"`
	Bankhash  string       `json:"bankhash,omitempty"`
	RunID     string       `json:"run_id,omitempty"`
	Version   string       `json:"version,omitempty"`
	Commit    string       `json:"commit,omitempty"`
	Branch    string       `json:"branch,omitempty"` // git branch name (may be empty)
	Reason    string       `json:"reason,omitempty"` // shutdown reason or corruption reason
}

StateHistoryEntry represents a single entry in the state history log.

func GetRecentHistory

func GetRecentHistory(accountsDbDir string, n int) ([]StateHistoryEntry, error)

GetRecentHistory returns the N most recent history entries.

func LoadHistory

func LoadHistory(accountsDbDir string) ([]StateHistoryEntry, error)

LoadHistory loads all history entries from the state history file. Returns empty slice if file doesn't exist.

Jump to

Keyboard shortcuts

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