chain

package
v0.0.3 Latest Latest
Warning

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

Go to latest
Published: Aug 12, 2026 License: GPL-3.0 Imports: 28 Imported by: 0

Documentation

Overview

Package chain provides epoch-level state management and builder information caching.

Index

Constants

View Source
const BuilderIndexFlag uint64 = 1 << 40
View Source
const (

	// EtherGweiFactor is the number of Gwei in 1 ETH.
	EtherGweiFactor = phase0.Gwei(1_000_000_000)
)
View Source
const FarFutureEpoch = uint64(0xFFFFFFFFFFFFFFFF)

FarFutureEpoch is the sentinel value indicating a builder/validator has not exited.

Variables

AllCandidateKeys lists every candidate key in canonical priority order.

Functions

func BeaconVersion

func BeaconVersion(v enginev.DataVersion) (version.DataVersion, error)

BeaconVersion maps an Engine API (execution) data version back to the canonical beacon (consensus) fork that introduced it.

func EngineVersion

func EngineVersion(v version.DataVersion) (enginev.DataVersion, error)

EngineVersion maps a beacon (consensus) fork to the Engine API (execution) data version whose payload structures it carries. It errors for pre-merge forks (phase0/altair), which have no execution payload.

func HasBuilderExited added in v0.0.3

func HasBuilderExited(info *BuilderInfo) bool

HasBuilderExited returns true when the builder's exit has been initiated (withdrawable epoch set). Per the Gloas spec an exited builder can never be reactivated: a deposit for its pubkey only tops up the exited entry and is withdrawn back to the execution address by the sweep (pushing the withdrawable epoch out by MIN_BUILDER_WITHDRAWABILITY_DELAY if the entry was already swept). The pubkey only becomes depositable again once the entry's index is reused by a different builder's deposit and the pubkey leaves the registry (info == nil).

func IsBuilderActive

func IsBuilderActive(info *BuilderInfo, finalizedEpoch uint64) bool

IsBuilderActive returns true when a builder's deposit has been finalized and the builder has not exited. Pass the result of GetBuilderByPubkey and GetFinalizedEpoch.

func IsValidCandidateKey added in v0.0.3

func IsValidCandidateKey(key string) bool

IsValidCandidateKey reports whether the given string names a candidate key.

Types

type ActiveIndiceIndex

type ActiveIndiceIndex uint32

ActiveIndiceIndex is a uint32 index into the active validators array.

type BlobScheduleEntry

type BlobScheduleEntry struct {
	Epoch            uint64
	MaxBlobsPerBlock uint64
}

BlobScheduleEntry represents a single entry in the BLOB_SCHEDULE.

type BuilderInfo

type BuilderInfo struct {
	Index             uint64
	Pubkey            phase0.BLSPubKey
	Balance           uint64
	Active            bool
	DepositEpoch      uint64
	WithdrawableEpoch uint64
	PendingPayments   uint64 // Sum of pending payments from BuilderPendingPayments in state
}

BuilderInfo represents information about a builder from the beacon state.

type CandidateKey added in v0.0.3

type CandidateKey string

CandidateKey identifies a build-parent candidate for a slot: which beacon block and which execution payload the build extends. "parent" and "grandparent" are positions on the canonical head chain at resolution time, so after missed slots they name the last existing blocks, not fixed slot offsets.

const (
	// CandidateParentFull: build on the head block and its committed payload.
	CandidateParentFull CandidateKey = "parent_full"
	// CandidateParentEmpty: build on the head block but on the execution
	// payload it built upon (the head block's own payload treated as
	// withheld). Gloas+ only.
	CandidateParentEmpty CandidateKey = "parent_empty"
	// CandidateGrandparentFull: build on the head block's parent and its
	// committed payload (a deliberate reorg of the head block).
	CandidateGrandparentFull CandidateKey = "grandparent_full"
	// CandidateGrandparentEmpty: build on the head block's parent but on the
	// payload it built upon (reorg of the head block combined with the
	// grandparent's payload treated as withheld). Gloas+ only.
	CandidateGrandparentEmpty CandidateKey = "grandparent_empty"
)

type CandidateParent added in v0.0.3

type CandidateParent struct {
	Key             CandidateKey
	ParentBlockRoot phase0.Root
	ParentSlot      phase0.Slot
	ParentBlockHash phase0.Hash32
	// ELParentGasLimit is the gas limit of the execution block identified by
	// ParentBlockHash (0 = unknown). Committed gas limits come from the bid
	// (Gloas) or the embedded payload (pre-Gloas).
	ELParentGasLimit uint64
	// ELParentNumber is the block number of the execution block identified by
	// ParentBlockHash (0 = unknown; Gloas blocks require the revealed
	// envelope to learn it).
	ELParentNumber uint64
	// ParentPayloadStatus is the reveal status of the beacon parent block's
	// own committed payload. Full candidates are only viable when it is (or
	// becomes) revealed; empty candidates when it stays withheld.
	ParentPayloadStatus PayloadStatus
}

CandidateParent is one resolved build-parent candidate for a slot.

type ChainSpec

type ChainSpec struct {
	// SecondsPerSlot is the slot duration, taken from SLOT_DURATION_MS when the
	// beacon node serves it (EIP-7782 networks keep serving a stale
	// SECONDS_PER_SLOT preset default alongside it) and from SECONDS_PER_SLOT
	// otherwise.
	SecondsPerSlot time.Duration
	SlotsPerEpoch  uint64

	// Duty calculation parameters
	ShuffleRoundCount          uint64
	TargetCommitteeSize        uint64
	MaxCommitteesPerSlot       uint64
	MaxEffectiveBalance        uint64
	MaxEffectiveBalanceElectra uint64
	EpochsPerHistoricalVector  uint64
	MinSeedLookahead           uint64

	// Pending-deposit processing parameters (Electra). Used to estimate how many
	// pending deposits drain per epoch when timing the pre-Gloas early onboarding
	// deposit (see pkg/lifecycle pending-deposit simulation).
	MinPerEpochChurnLimit               uint64
	ChurnLimitQuotient                  uint64
	MaxPerEpochActivationExitChurnLimit uint64
	MaxPendingDepositsPerEpoch          uint64
	MinActivationBalance                uint64
	EffectiveBalanceIncrement           uint64
	MaxWithdrawalsPerPayload            uint64

	// Domain types
	DomainBeaconProposer      phase0.DomainType
	DomainBeaconAttester      phase0.DomainType
	DomainPtcAttester         phase0.DomainType
	DomainProposerPreferences phase0.DomainType

	// Fork epochs and versions (nil if not configured)
	ForkSchedule []ForkSchedule

	// Blob schedule (BPO - Blob Parameters Only)
	BlobSchedule []BlobScheduleEntry

	// ePBS parameters
	PtcSize uint64
	// PAYLOAD_DUE_BPS: the builder payload reveal deadline as basis points of
	// the slot duration (Gloas). A block whose payload has not been seen by
	// this offset is treated as empty by payload timeliness voting.
	PayloadDueBps uint64

	// Deposit contract
	DepositContractAddress *common.Address
}

ChainSpec holds chain specification parameters.

func ParseChainSpec

func ParseChainSpec(specData map[string]string, rawData map[string]json.RawMessage) (*ChainSpec, error)

ParseChainSpec parses the chain specification from the spec data.

func (*ChainSpec) GetForkEpoch

func (s *ChainSpec) GetForkEpoch(fork version.DataVersion) phase0.Epoch

GetForkEpoch returns the epoch of a given fork.

func (*ChainSpec) GetForkVersion

func (s *ChainSpec) GetForkVersion(fork version.DataVersion) (phase0.Version, error)

GetForkVersion returns the fork version for a given fork.

func (*ChainSpec) IsForkActive

func (s *ChainSpec) IsForkActive(fork version.DataVersion, epoch phase0.Epoch) bool

IsForkActive checks if a fork is active for a given epoch.

func (*ChainSpec) IsForkScheduled

func (s *ChainSpec) IsForkScheduled(fork version.DataVersion) bool

IsForkScheduled checks if a fork is scheduled.

type DutyState

type DutyState struct {
	RandaoMix           *phase0.Hash32
	NextRandaoMix       *phase0.Hash32
	GetRandaoMixes      func() []phase0.Root
	GetActiveCount      func() uint64
	GetEffectiveBalance func(index ActiveIndiceIndex) phase0.Gwei
}

DutyState holds the state data needed for duty calculations.

type EpochStats

type EpochStats struct {
	Version        version.DataVersion
	Epoch          phase0.Epoch
	FinalizedEpoch phase0.Epoch
	StateSlot      phase0.Slot

	// Validator data
	ActiveValidators  uint64
	ValidatorCount    uint64
	ActiveIndices     []phase0.ValidatorIndex
	EffectiveBalances []uint32 // Effective balance in full ETH units

	// Builder data (for lifecycle management, Gloas only).
	// Populated (possibly empty) for any Gloas+ state; nil for pre-Gloas epochs.
	Builders []*BuilderInfo

	// Total active effective balance (gwei). Used to estimate the activation-exit
	// churn limit for pending-deposit processing (early-onboarding timing).
	TotalActiveBalance uint64

	// Pending-deposit queue data (Electra+). Used to time the pre-Gloas early
	// onboarding deposit so it is still queued at the fork boundary.
	PendingDeposits           []PendingDepositInfo
	DepositBalanceToConsume   uint64 // gwei
	Eth1DepositIndex          uint64
	DepositRequestsStartIndex uint64

	// Pre-computed duties
	RandaoMix      phase0.Hash32
	NextRandaoMix  phase0.Hash32
	ProposerDuties []phase0.ValidatorIndex // [slot_index] -> validator index
	AttesterDuties [][][]ActiveIndiceIndex // [slot_index][committee_index][member] -> active indice index
	PtcDuties      [][]ActiveIndiceIndex   // [slot_index][ptc_member] -> active indice index (Gloas only)
}

EpochStats holds cached statistics for an epoch computed from beacon state.

type ForkSchedule

type ForkSchedule struct {
	Fork    version.DataVersion
	Version phase0.Version
	Epoch   phase0.Epoch
}

type HeadChangeEvent added in v0.0.3

type HeadChangeEvent struct {
	Old            *beacon.BlockInfo // nil on the first observed head
	New            *beacon.BlockInfo
	ReorgDepth     uint64
	CommonAncestor phase0.Root
}

HeadChangeEvent is fired for every accepted head switch. ReorgDepth is 0 for a normal chain extension; for a reorg it is the number of slots between the old head and the common ancestor. CommonAncestor is zero when the fork point is deeper than the scan window.

type HeadTracker added in v0.0.3

type HeadTracker struct {
	// contains filtered or unexported fields
}

HeadTracker maintains buildoor's own view of the canonical chain: the current head, a bounded block-by-root ancestry cache, and per-block payload reveal status (Gloas). It is the validation oracle for payload-attributes sanitization and the source of build-parent candidates.

func NewHeadTracker added in v0.0.3

func NewHeadTracker(
	clClient *beacon.Client,
	chainSpec *ChainSpec,
	genesis *beacon.Genesis,
	log logrus.FieldLogger,
) *HeadTracker

NewHeadTracker creates a new head tracker.

func (*HeadTracker) CurrentHead added in v0.0.3

func (h *HeadTracker) CurrentHead() *beacon.BlockInfo

CurrentHead returns the most recently observed head block (nil until the first head event resolves).

func (*HeadTracker) FinalityInfo added in v0.0.3

func (h *HeadTracker) FinalityInfo() *beacon.FinalityInfo

FinalityInfo returns the finality checkpoint execution hashes cached for the current head (nil until the first refresh completes). Refreshed once per head change, so build paths never pay the beacon-API round trips.

func (*HeadTracker) GetBlock added in v0.0.3

func (h *HeadTracker) GetBlock(ctx context.Context, root phase0.Root) (*beacon.BlockInfo, error)

GetBlock resolves a block by root through the shared ancestry cache, fetching from the beacon node on a miss.

func (*HeadTracker) GetPayloadStatus added in v0.0.3

func (h *HeadTracker) GetPayloadStatus(root phase0.Root) PayloadStatus

GetPayloadStatus returns the reveal status of the block's committed payload. Unknown blocks report Pending. Pre-Gloas blocks are always Revealed (the payload is embedded in the block).

func (*HeadTracker) IsCanonical added in v0.0.3

func (h *HeadTracker) IsCanonical(ctx context.Context, root phase0.Root) bool

IsCanonical reports whether the given root is on the current head's ancestry within the retention window.

func (*HeadTracker) LookupBlock added in v0.0.3

func (h *HeadTracker) LookupBlock(root phase0.Root) (*beacon.BlockInfo, bool)

LookupBlock returns a cached block by root without ever fetching, for callers that must not block (UI event assembly, hot paths).

func (*HeadTracker) LookupELParentMeta added in v0.0.3

func (h *HeadTracker) LookupELParentMeta(
	ctx context.Context, fromRoot phase0.Root, execHash phase0.Hash32,
) (number, gasLimit uint64)

LookupELParentMeta returns the block number and gas limit of the execution block identified by execHash from already-known data only: the committing beacon block's own fields and the envelope-metadata cache. It never performs a beacon-API fetch, so build hot paths never block on one (payload-available events prefetch the metadata in the background).

func (*HeadTracker) PrimeBlock added in v0.0.3

func (h *HeadTracker) PrimeBlock(info *beacon.BlockInfo)

PrimeBlock contributes an already-resolved block to the shared ancestry cache (also derives payload-status evidence for its parent).

func (*HeadTracker) PrimeHead added in v0.0.3

func (h *HeadTracker) PrimeHead(info *beacon.BlockInfo)

PrimeHead seeds the tracker with an already-resolved head block (cached and adopted as current head unless an equal-or-newer head is known). Live head events take over from the first processed event.

func (*HeadTracker) ResolveCandidates added in v0.0.3

func (h *HeadTracker) ResolveCandidates(ctx context.Context, slot phase0.Slot) ([]*CandidateParent, error)

ResolveCandidates derives the build-parent candidates for the given slot from the current head chain. The head must be older than the target slot. Empty variants are only produced under Gloas; a variant whose parent tuple duplicates another is dropped.

func (*HeadTracker) ResolveELParentMeta added in v0.0.3

func (h *HeadTracker) ResolveELParentMeta(
	ctx context.Context, fromRoot phase0.Root, execHash phase0.Hash32,
) (number, gasLimit uint64)

ResolveELParentMeta resolves the block number and gas limit of the execution block identified by execHash, walking the beacon ancestry from fromRoot to find the block that committed it (best-effort; zeros when unknown). May fetch from the beacon node — do not call from build hot paths; use LookupELParentMeta there.

func (*HeadTracker) Start added in v0.0.3

func (h *HeadTracker) Start(ctx context.Context)

Start starts the head tracker's event loop.

func (*HeadTracker) Stop added in v0.0.3

func (h *HeadTracker) Stop()

Stop stops the head tracker and waits for its loop to exit.

func (*HeadTracker) SubscribeHeadChanges added in v0.0.3

func (h *HeadTracker) SubscribeHeadChanges() *utils.Subscription[*HeadChangeEvent]

SubscribeHeadChanges returns a subscription for head switch events (including reorgs).

type HeadVoteTracker

type HeadVoteTracker struct {
	// contains filtered or unexported fields
}

HeadVoteTracker tracks per-slot attestation participation by aggregating raw single_attestation events (streaming in from the Gloas attester deadline at 25% of the slot) into per-root bitmaps against locally computed attester duties. Raw singles are the ONLY participation source — aggregates are deliberately not subscribed (they arrive at the 50% aggregate deadline, which is also the payload reveal deadline, far too late to be useful). Instead, every imported block's attestations serve as the ground truth to measure how much of the vote our singles view actually covered: a node without subscribe-all-subnets only sees singles on its duty subnets, and a sustained miss flags the tracking as unreliable. Updates are throttled to percent-steps on a flush interval; crossing the configured participation threshold fires immediately.

func NewHeadVoteTracker

func NewHeadVoteTracker(
	cfg *config.Config,
	chainSvc Service,
	clClient *beacon.Client,
	log logrus.FieldLogger,
) *HeadVoteTracker

NewHeadVoteTracker creates a new head vote tracker.

func (*HeadVoteTracker) GetParticipation added in v0.0.3

func (t *HeadVoteTracker) GetParticipation(slot phase0.Slot, root phase0.Root) (HeadVoteUpdate, bool)

GetParticipation returns the current participation snapshot for a tracked (slot, beacon block root) pair; ok is false when the pair is not tracked.

func (*HeadVoteTracker) GetSubnetCoverage added in v0.0.3

func (t *HeadVoteTracker) GetSubnetCoverage() SubnetCoverage

GetSubnetCoverage returns the current subnet coverage summary.

func (*HeadVoteTracker) GetVoteDetail added in v0.0.3

func (t *HeadVoteTracker) GetVoteDetail(slot phase0.Slot, root phase0.Root) (VoteDetail, bool)

GetVoteDetail returns the per-attester vote detail for a slot. A zero root resolves the slot's primary root. ok is false when the (slot, root) pair is not tracked.

func (*HeadVoteTracker) Start

func (t *HeadVoteTracker) Start(ctx context.Context)

Start starts the head vote tracker.

func (*HeadVoteTracker) Stop

func (t *HeadVoteTracker) Stop()

Stop stops the head vote tracker.

func (*HeadVoteTracker) SubscribeBlocks added in v0.0.3

SubscribeBlocks returns a subscription for imported blocks (the full fork-agnostic signed block — a byproduct of the coverage measurement's block fetch; at most one per imported block, none while a fetch is still in flight). Consumers reduce it to whatever shape they need.

func (*HeadVoteTracker) SubscribeCoverage added in v0.0.3

func (t *HeadVoteTracker) SubscribeCoverage() *utils.Subscription[*SubnetCoverage]

SubscribeCoverage returns a subscription for subnet coverage updates (at most one per imported block).

func (*HeadVoteTracker) SubscribeUpdates

func (t *HeadVoteTracker) SubscribeUpdates() *utils.Subscription[*HeadVoteUpdate]

SubscribeUpdates returns a subscription for head vote updates.

type HeadVoteUpdate

type HeadVoteUpdate struct {
	Slot             phase0.Slot
	BlockRoot        phase0.Root
	ParticipationPct float64
	ParticipationETH uint64
	TotalSlotETH     uint64
	VoteCount        int
	TotalMembers     int
	ThresholdPct     float64 // effective threshold at fire time (0 = disabled)
	ThresholdMet     bool
	Timestamp        int64
}

HeadVoteUpdate is dispatched when head vote participation changes.

type PayloadStatus added in v0.0.3

type PayloadStatus string

PayloadStatus is the reveal status of a Gloas block's committed execution payload. Pre-Gloas blocks embed their payload and are always Revealed.

const (
	// PayloadStatusPending: no reveal evidence yet and the reveal deadline has
	// not passed.
	PayloadStatusPending PayloadStatus = "pending"
	// PayloadStatusRevealed: the payload was seen (payload-available event or
	// a child block built on it).
	PayloadStatusRevealed PayloadStatus = "revealed"
	// PayloadStatusEmpty: the payload is treated as withheld — either a child
	// block built past it, or the reveal deadline passed without evidence
	// (provisional until contrary evidence arrives).
	PayloadStatusEmpty PayloadStatus = "empty"
)

type PendingDepositInfo

type PendingDepositInfo struct {
	Pubkey phase0.BLSPubKey
	Amount uint64 // gwei
	Slot   phase0.Slot
}

PendingDepositInfo is a single entry of the beacon state's pending_deposits queue, reduced to the fields needed to model Electra deposit-queue draining and to identify our own (early-onboarding) deposit after a restart.

type Service

type Service interface {
	Start(ctx context.Context) error
	Stop() error

	// Chain state accessors
	GetChainSpec() *ChainSpec
	GetGenesis() *beacon.Genesis
	SlotToTime(slot phase0.Slot) time.Time
	TimeToSlot(t time.Time) phase0.Slot
	GetCurrentEpoch() phase0.Epoch
	GetCurrentSlot() phase0.Slot
	GetCurrentFork() version.DataVersion
	ActiveForkAtEpoch(epoch phase0.Epoch) version.DataVersion
	GetForkVersion() (phase0.Version, error)
	GetEpochOfSlot(slot phase0.Slot) phase0.Epoch

	// Epoch stats access
	GetCurrentEpochStats() *EpochStats
	GetEpochStats(epoch phase0.Epoch) *EpochStats

	// Subscriptions
	SubscribeEpochStats() *utils.Subscription[*EpochStats]

	// Head vote tracking
	GetHeadVoteTracker() *HeadVoteTracker

	// Canonical head / ancestry / payload-status view
	GetHeadTracker() *HeadTracker

	// Finality
	GetFinalizedEpoch() phase0.Epoch

	// Builder access
	GetBuilderByIndex(index uint64) *BuilderInfo
	GetBuilderByPubkey(pubkey phase0.BLSPubKey) *BuilderInfo
	GetBuilders() []*BuilderInfo

	// Validator access
	GetValidatorPubkeyByIndex(index phase0.ValidatorIndex) *phase0.BLSPubKey

	// RefreshBuilders re-fetches the beacon state to pick up new builder registrations.
	RefreshBuilders(ctx context.Context) error
}

Service interface defines the chain service operations.

func NewService

func NewService(
	cfg *config.Config,
	clClient *beacon.Client,
	chainSpec *ChainSpec,
	genesis *beacon.Genesis,
	log logrus.FieldLogger,
) Service

NewService creates a new chain service.

type SubnetCoverage added in v0.0.3

type SubnetCoverage struct {
	Slots     int     // measured blocks in the window
	Attesters int     // total attesters counted across the window
	SeenPct   float64 // percent of those attesters seen as singles beforehand
	Low       bool    // sustained miss above coverageMissThreshold
}

SubnetCoverage summarizes how many of the attesters that landed in recent blocks were previously seen as raw single attestations.

type VoteAttester added in v0.0.3

type VoteAttester struct {
	Index    phase0.ValidatorIndex
	SeenAtMs int32 // ms offset from slot start; -1 = never seen as a raw single
	InBlock  bool  // attested on chain per the next-block ground truth
}

VoteAttester is one committee member's vote observation.

type VoteDetail added in v0.0.3

type VoteDetail struct {
	Slot         phase0.Slot
	BlockRoot    phase0.Root
	TotalMembers int
	Attesters    []VoteAttester
}

VoteDetail is a per-attester snapshot of one (slot, root) vote state, consumed by the WebUI's vote-arrival heatmap.

Jump to

Keyboard shortcuts

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