config

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: 8 Imported by: 0

Documentation

Overview

Package config handles configuration loading and validation for buildoor.

Index

Constants

View Source
const (
	SourceDefault = "default"
	SourceCLI     = "cli"
	SourceUI      = "ui"
)

Source identifies which layer currently wins for a setting.

View Source
const (
	KeyScheduleMode      = "schedule.mode"
	KeyScheduleEveryNth  = "schedule.every_nth"
	KeyScheduleNextN     = "schedule.next_n"
	KeyScheduleStartSlot = "schedule.start_slot"

	KeyEPBSBuildStartTime     = "epbs.build_start_time"
	KeyEPBSBidStartTime       = "epbs.bid_start_time"
	KeyEPBSBidEndTime         = "epbs.bid_end_time"
	KeyEPBSBidMinAmount       = "epbs.bid_min_amount"
	KeyEPBSBidIncrease        = "epbs.bid_increase"
	KeyEPBSBidInterval        = "epbs.bid_interval"
	KeyEPBSBidSubsidy         = "epbs.bid_subsidy"
	KeyEPBSBidValueOverride   = "epbs.bid_value_override"
	KeyEPBSHeadVoteThreshold  = "epbs.head_vote_threshold_pct"
	KeyEPBSBidCandidate       = "epbs.bid_candidate"
	KeyEPBSBidCandidateSwitch = "epbs.bid_candidate_switch"
	KeyEPBSKeyStrategy        = "epbs.key_strategy"
	KeyEPBSBidKeysPerSlot     = "epbs.bid_keys_per_slot"
	KeyEPBSBidKeysPerStep     = "epbs.bid_keys_per_step"

	KeyRevealEnabled             = "reveal.enabled"
	KeyRevealGateMode            = "reveal.gate_mode"
	KeyRevealTimeMs              = "reveal.time_ms"
	KeyRevealVoteThreshold       = "reveal.vote_threshold_pct"
	KeyRevealBroadcastValidation = "reveal.broadcast_validation"
	KeyRevealMaxAttempts         = "reveal.max_attempts"
	KeyRevealRetryInterval       = "reveal.retry_interval_ms"
	KeyRevealRebindOnReorg       = "reveal.rebind_on_reorg"

	KeyBuildCandidateParentFull       = "build.candidate_parent_full"
	KeyBuildCandidateParentEmpty      = "build.candidate_parent_empty"
	KeyBuildCandidateGrandparentFull  = "build.candidate_grandparent_full"
	KeyBuildCandidateGrandparentEmpty = "build.candidate_grandparent_empty"
	KeyBuildParallel                  = "build.parallel"
	KeyBuildSpeculativeBuildTime      = "build.speculative_build_time_ms"
	KeyBuildAutoWeakHeadPct           = "build.auto_weak_head_pct"
	KeyBuildEnforceBidGasLimit        = "build.enforce_bid_gas_limit"

	KeyPayloadBuildTime          = "payload_build_time"
	KeyExtraData                 = "extra_data"
	KeyBuilderAPISubsidy         = "builder_api.block_value_subsidy_gwei"
	KeyBuilderAPIValueOverride   = "builder_api.value_override_gwei"
	KeyBuilderAPIServeCandidates = "builder_api.serve_candidates"
	KeyBuilderAPIOnDemandBuild   = "builder_api.on_demand_build"
	KeyBuilderAPIKeyStrategy     = "builder_api.key_strategy"

	KeySlotResultRetentionEpochs   = "slot_result_retention_epochs"
	KeySlotArtifactRetentionEpochs = "slot_artifact_retention_epochs"
	KeySlotArtifactCaptureEnabled  = "slot_artifact_capture_enabled"

	KeyDepositAmount  = "deposit_amount"
	KeyTopupThreshold = "topup_threshold"
	KeyTopupAmount    = "topup_amount"

	KeyBuilderKeysTargetCount = "builder_keys.target_count"
	KeyBuilderKeysMaxIndex    = "builder_keys.max_index"
	KeyBuilderKeysAutoDeposit = "builder_keys.auto_deposit"
	KeyBuilderKeysAutoExit    = "builder_keys.auto_exit"

	KeyEPBSEnabled       = "epbs_enabled"
	KeyBuilderAPIEnabled = "builder_api_enabled"
	KeyLifecycleEnabled  = "lifecycle_enabled"
)

Canonical settings keys. These are the persisted/override keys and are shared between the field registry (fields.go) and the API handlers that apply UI overrides, so the two never drift.

View Source
const (
	// CandidateModeAuto builds the candidate when live chain signals suggest
	// it may be needed (parent payload reveal status, parent block weakness).
	CandidateModeAuto = "auto"
	// CandidateModeAlways builds the candidate every scheduled slot.
	CandidateModeAlways = "always"
	// CandidateModeNever suppresses the candidate.
	CandidateModeNever = "never"
)

Candidate build modes: whether a build-parent candidate is built for a slot.

View Source
const (
	// RevealGateTime reveals at TimeMs into the slot.
	RevealGateTime = "time"
	// RevealGateVote reveals as soon as head-vote participation on the
	// committing block reaches VoteThresholdPct.
	RevealGateVote = "vote"
	// RevealGateVoteOrTime reveals at whichever gate opens first.
	RevealGateVoteOrTime = "vote_or_time"
	// RevealGateVoteAndTime reveals at TimeMs, but only once the vote
	// threshold is also reached (whichever happens last).
	RevealGateVoteAndTime = "vote_and_time"
)

Reveal gate modes: how the reveal moment of a won slot is decided.

View Source
const (
	BroadcastValidationGossip                   = "gossip"
	BroadcastValidationConsensus                = "consensus"
	BroadcastValidationConsensusAndEquivocation = "consensus_and_equivocation"
)

Broadcast validation levels for the envelope submission API (beacon-API broadcast_validation query parameter).

Variables

This section is empty.

Functions

func NormalizedCandidateMode added in v0.0.3

func NormalizedCandidateMode(mode, fallback string) string

NormalizedCandidateMode returns the candidate mode, falling back to the given default for unknown values (UI overrides are free-form strings).

func ServeCandidateAllowed added in v0.0.3

func ServeCandidateAllowed(policy, key string) bool

ServeCandidateAllowed reports whether the given serve policy allows answering from a payload classified as the given candidate key ("" = unclassified, always allowed under "all" and "canonical_only").

Types

type BuildConfig added in v0.0.3

type BuildConfig struct {
	// CandidateParentFull: the normal build on the head block and its payload.
	CandidateParentFull string `yaml:"candidate_parent_full" json:"candidate_parent_full"`
	// CandidateParentEmpty: build on the head block but on its execution
	// parent (head payload treated as withheld). Gloas only.
	CandidateParentEmpty string `yaml:"candidate_parent_empty" json:"candidate_parent_empty"`
	// CandidateGrandparentFull: build on the head block's parent (reorg).
	CandidateGrandparentFull string `yaml:"candidate_grandparent_full" json:"candidate_grandparent_full"`
	// CandidateGrandparentEmpty: reorg combined with a withheld grandparent
	// payload. Gloas only.
	CandidateGrandparentEmpty string `yaml:"candidate_grandparent_empty" json:"candidate_grandparent_empty"`

	// Parallel runs the selected candidate builds concurrently against the
	// EL, each with its own payload ID (default). Disable it to serialize
	// them — the canonical candidate builds first so it keeps its scheduled
	// start, and the speculative ones follow.
	Parallel bool `yaml:"parallel" json:"parallel"`

	// SpeculativeBuildTimeMs, when non-zero, is the EL build time granted to
	// speculative (non-parent_full) candidates instead of PayloadBuildTime.
	SpeculativeBuildTimeMs uint64 `yaml:"speculative_build_time_ms" json:"speculative_build_time_ms"`

	// AutoWeakHeadPct is the head-vote participation (percent) below which
	// the head block counts as contested and auto-mode grandparent
	// candidates arm. 0 disables the weak-head signal.
	AutoWeakHeadPct uint64 `yaml:"auto_weak_head_pct" json:"auto_weak_head_pct"`

	// EnforceBidGasLimit adjusts the built payload's gas limit to the exact
	// value the bid gossip rules require (EL parent gas limit stepped toward
	// the proposer's target) when the EL ignored the target. Disabled by
	// default: the override rewrites the block header after building.
	EnforceBidGasLimit bool `yaml:"enforce_bid_gas_limit" json:"enforce_bid_gas_limit"`
}

BuildConfig defines which build-parent candidates are built per slot and how the engine builds are sequenced. Candidates name the parent tuple a payload extends: the head block ("parent") or its parent ("grandparent", a deliberate reorg), each on the committed payload ("full") or on the payload it built upon ("empty", the Gloas payload-miss case).

func (*BuildConfig) CandidateMode added in v0.0.3

func (c *BuildConfig) CandidateMode(key string) string

CandidateMode returns the normalized mode configured for the given candidate key ("" for unknown keys).

type BuilderAPIConfig

type BuilderAPIConfig struct {
	// BuilderURL is this builder's publicly reachable URL (e.g. "https://builder.example.com").
	// Used to verify the auth.message.data field (set to the builder URL) in
	// SignedRequestAuthV1 messages from proposers. If empty, this validation is skipped.
	BuilderURL string `yaml:"builder_url" json:"builder_url"`

	// RequireRequestAuth controls whether a SignedRequestAuthV1 body is mandatory on
	// getExecutionPayloadBid requests. When true, requests without an auth body are
	// rejected with 401. When false (default), auth is optional — but if supplied it
	// is always fully validated.
	RequireRequestAuth bool `yaml:"require_request_auth" json:"require_request_auth"`

	// BlockValueSubsidyGwei is added to the bid value so the proposer sees a higher bid:
	// to the getHeader bid value in the Fulu Builder API, and to the block value that
	// forms bid.ExecutionPayment/Value in Gloas getExecutionPayloadBid calls.
	BlockValueSubsidyGwei uint64 `yaml:"block_value_subsidy_gwei" json:"block_value_subsidy_gwei"`

	// ValueOverrideGwei, when non-zero, replaces the served bid's total value
	// (block value + subsidy) with this absolute amount in gwei — an alternative
	// to the subsidy for testing. Per-slot action plans override this per slot.
	ValueOverrideGwei uint64 `yaml:"value_override_gwei" json:"value_override_gwei"`

	// ServeCandidates controls which built candidate payloads bid requests may
	// be answered from: "all" (default; serve whichever candidate matches the
	// requested parent), "canonical_only" (only parent_full and unclassified
	// payloads), or a comma-separated list of candidate keys.
	ServeCandidates string `yaml:"serve_candidates" json:"serve_candidates"`

	// OnDemandBuild builds a payload on the fly when a bid request asks for a
	// legal parent tuple no candidate covers yet (bounded by the request's
	// response budget).
	OnDemandBuild bool `yaml:"on_demand_build" json:"on_demand_build"`

	// KeyStrategy selects which managed builder key signs served bids. Unlike
	// p2p gossip there is no first-seen rule here, but the choice is sticky per
	// (slot, parent tuple) so a polling proposer keeps seeing the same builder.
	// Empty falls back to the ePBS key strategy.
	KeyStrategy string `yaml:"key_strategy" json:"key_strategy"`
}

BuilderAPIConfig defines configuration for the traditional Builder API (pre-ePBS).

func (*BuilderAPIConfig) ServeCandidateAllowed added in v0.0.3

func (c *BuilderAPIConfig) ServeCandidateAllowed(key string) bool

ServeCandidateAllowed applies the config's own serve policy.

type BuilderKeysConfig added in v0.0.3

type BuilderKeysConfig struct {
	// TargetCount is the number of builder keys kept registered and funded.
	// Raising it deposits new keys; lowering it exits surplus keys when AutoExit
	// is on. 0 is treated as 1.
	TargetCount uint64 `yaml:"target_count" json:"target_count"`

	// MaxIndex caps internal derivation, bounding both the target and the
	// startup discovery scan.
	MaxIndex uint64 `yaml:"max_index" json:"max_index"`

	// DiscoveryGap is how many consecutive never-used indices end the startup
	// scan for previously deposited keys.
	DiscoveryGap uint64 `yaml:"discovery_gap" json:"discovery_gap"`

	// AutoDeposit deposits new keys to reach TargetCount.
	AutoDeposit bool `yaml:"auto_deposit" json:"auto_deposit"`

	// AutoExit exits surplus keys when the managed count exceeds TargetCount.
	// Irreversible: an exited builder key cannot be reactivated until its
	// registry entry is reused by another builder's deposit.
	AutoExit bool `yaml:"auto_exit" json:"auto_exit"`
}

BuilderKeysConfig defines the managed builder key set: how many keys buildoor keeps registered and funded, and how far the internal derivation may reach.

Keys are derived from the entry key (see signer.DeriveInternalKey): internal index 0 is the entry key itself, so a TargetCount of 1 behaves exactly like a single-key deployment.

func (*BuilderKeysConfig) EffectiveTargetCount added in v0.0.3

func (c *BuilderKeysConfig) EffectiveTargetCount() uint64

EffectiveTargetCount returns the target key count clamped into the usable range: at least one key, and never more than the derivation cap allows (indices 0..MaxIndex, so MaxIndex+1 keys).

type BuilderState

type BuilderState struct {
	Pubkey            []byte
	Index             uint64
	IsRegistered      bool
	Balance           uint64 // Gwei
	DepositEpoch      uint64
	WithdrawableEpoch uint64
}

BuilderState represents the current state of a builder in the beacon chain.

type BuilderStats

type BuilderStats struct {
	SlotsBuilt     uint64
	BidsSubmitted  uint64
	BidsWon        uint64
	BlocksIncluded uint64 // Blocks where our payload was included
	TotalPaid      uint64 // Gwei paid for won bids
	RevealsSuccess uint64
	RevealsFailed  uint64
	RevealsSkipped uint64
}

BuilderStats tracks statistics for builder operations.

type Config

type Config struct {
	BuilderPrivkey string `yaml:"builder_privkey" json:"builder_privkey,omitempty"`
	// BuilderMnemonic, when set, derives the builder BLS key from this BIP-39 mnemonic and
	// BuilderKeyIndex using the standard validator key path m/12381/3600/{index}/0/0.
	// Mutually exclusive with BuilderPrivkey. json:"-" keeps the secret out of every JSON
	// serialization path (WebUI REST + SSE); YAML config loading is unaffected.
	BuilderMnemonic string `yaml:"builder_mnemonic" json:"-"`
	BuilderKeyIndex uint64 `yaml:"builder_key_index" json:"builder_key_index"`
	// BuilderKeys configures the managed set of internally derived builder keys
	// that the entry key (BuilderPrivkey / BuilderMnemonic+BuilderKeyIndex) roots.
	BuilderKeys       BuilderKeysConfig `yaml:"builder_keys" json:"builder_keys"`
	CLClient          string            `yaml:"cl_client" json:"cl_client,omitempty"`
	ELEngineAPI       string            `yaml:"el_engine_api" json:"el_engine_api,omitempty"`   // Engine API URL (required for payload building)
	ELJWTSecret       string            `yaml:"el_jwt_secret" json:"el_jwt_secret,omitempty"`   // Path to JWT secret file for engine API auth
	ELRPC             string            `yaml:"el_rpc" json:"el_rpc,omitempty"`                 // Optional: EL JSON-RPC for transactions (lifecycle only)
	WalletPrivkey     string            `yaml:"wallet_privkey" json:"wallet_privkey,omitempty"` // Optional: only if lifecycle enabled
	APIPort           int               `yaml:"api_port" json:"api_port"`                       // Optional, 0 = disabled
	AuthProviderURL   string            `yaml:"auth_provider_url" json:"auth_provider_url"`     // Optional: authenticatoor URL; when set, API requests must carry a JWT verified against the authenticatoor's JWKS. When empty, the API is unauthenticated.
	InjectHeadHTML    string            `yaml:"inject_head_html" json:"inject_head_html"`       // Optional: raw HTML snippet (e.g. analytics tags) injected into <head> of the served SPA. Falls back to BUILDOOR_INJECT_HEAD_HTML env var when empty.
	OverviewURL       string            `yaml:"overview_url" json:"overview_url"`               // Optional: URL of the multi-instance overview UI. When set, the dashboard renders an "Overview" entry in the top nav so operators get consistent navigation across instances.
	LifecycleEnabled  bool              `yaml:"lifecycle_enabled" json:"lifecycle_enabled"`
	EPBSEnabled       bool              `yaml:"epbs_enabled" json:"epbs_enabled"`               // Initial enabled state for ePBS (service available if Gloas fork is scheduled)
	BuilderAPIEnabled bool              `yaml:"builder_api_enabled" json:"builder_api_enabled"` // Initial enabled state for Builder API
	BuilderAPI        BuilderAPIConfig  `yaml:"builder_api" json:"builder_api"`                 // Builder API configuration
	DepositAmount     uint64            `yaml:"deposit_amount" json:"deposit_amount"`           // Gwei, default 10 ETH
	TopupThreshold    uint64            `yaml:"topup_threshold" json:"topup_threshold"`         // Gwei
	TopupAmount       uint64            `yaml:"topup_amount" json:"topup_amount"`               // Gwei
	DepositMaxFeeGwei uint64            `yaml:"deposit_max_fee" json:"deposit_max_fee"`
	Schedule          ScheduleConfig    `yaml:"schedule" json:"schedule"`
	EPBS              EPBSConfig        `yaml:"epbs" json:"epbs"`     // Time-scheduled ePBS config
	Reveal            RevealConfig      `yaml:"reveal" json:"reveal"` // Payload reveal config (shared by p2p bidder + Builder API)
	Build             BuildConfig       `yaml:"build" json:"build"`   // Payload build candidate policy
	Debug             bool              `yaml:"debug" json:"debug"`
	Pprof             bool              `yaml:"pprof" json:"pprof"`
	PayloadBuildTime  uint64            `yaml:"payload_build_time" json:"payload_build_time"` // The time given to the EL to build the payload after triggering the payload build via fcu (in ms)
	// ExtraData is the prefix injected into the built payload's extra-data field
	// (then padded with the EL's original extra data, truncated to 32 bytes). Used
	// to mark blocks built by this builder. Defaulted to "buildoor/" when empty.
	ExtraData       string                `yaml:"extra_data" json:"extra_data"`
	ValidatorRanges ValidatorRangesConfig `yaml:"validator_ranges" json:"validator_ranges"`
	// SlotResultRetentionEpochs is how many epochs of per-slot result history
	// (plans + outcome summaries) are kept before pruning, in memory and in the
	// state-db. Must be > 0.
	SlotResultRetentionEpochs uint64 `yaml:"slot_result_retention_epochs" json:"slot_result_retention_epochs"`
	// SlotArtifactRetentionEpochs is how many epochs of raw SSZ artifacts
	// (payloads, signed bids, envelopes) are kept in the slot_artifacts table.
	// Raw payloads dominate disk usage — lower this on disk-sensitive
	// deployments. Must be > 0.
	SlotArtifactRetentionEpochs uint64 `yaml:"slot_artifact_retention_epochs" json:"slot_artifact_retention_epochs"`
	// SlotArtifactCaptureEnabled toggles raw SSZ artifact capture. Result
	// summaries are recorded regardless.
	SlotArtifactCaptureEnabled bool `yaml:"slot_artifact_capture_enabled" json:"slot_artifact_capture_enabled"`
	// StateDBPath, when set, enables the optional SQLite state-db at this path.
	// It persists UI setting overrides, won blocks, validator registrations,
	// proposer preferences and an audit log across restarts. Startup-only and
	// never itself persisted. Empty disables persistence (in-memory only).
	StateDBPath string `yaml:"state_db" json:"state_db,omitempty"`
}

Config represents the complete configuration for the buildoor application.

func DefaultConfig

func DefaultConfig() *Config

DefaultConfig returns a configuration with sensible defaults. Timing fields default to 0, which means "auto-compute from slot time". Call ApplySlotDefaults after loading the chain spec to fill them in.

func (*Config) ApplySlotDefaults

func (c *Config) ApplySlotDefaults(slotTimeMs int64)

ApplySlotDefaults fills in zero-valued timing fields with slot-relative defaults. This is called after the chain spec is loaded so the slot duration is known.

Timing fields are tuned for a 12s slot and scaled linearly to the actual slot time (value = reference@12s * slotTimeMs / 12000):

BuildStartTime:  -2900ms @12s  (e.g. -1450ms @6s)
PayloadBuildTime: 2100ms @12s  (e.g.  1050ms @6s)
BidStartTime:     -400ms @12s  (e.g.  -200ms @6s)
BidEndTime:       -100ms @12s  (e.g.   -50ms @6s)
Reveal.TimeMs:    5000ms @12s  (e.g.  2500ms @6s)

Reveal.TimeMs (41.7% of the slot) is anchored to the Gloas/EIP-7732 deadlines: it sits after the attestation deadline (ATTESTATION_DUE_BPS_GLOAS, 25%) — so the builder has seen attestation weight on the block before committing to reveal — and comfortably before the hard payload deadline (PAYLOAD_DUE_BPS, 50% since consensus-specs#5414), after which the PTC votes the payload absent. The ~8% (1s @12s) margin before that deadline lets the envelope gossip to PTC members, who attest at 75% (PAYLOAD_ATTESTATION_DUE_BPS).

type EPBSConfig

type EPBSConfig struct {
	// BuildStartTime is milliseconds relative to the proposal slot start when we
	// start building. Negative values mean before the slot starts (e.g. -3000 =
	// 3 seconds before slot start). Positive values mean after slot start.
	// Set to 0 to build immediately when payload_attributes is received.
	// Default: -3000.
	BuildStartTime int64 `yaml:"build_start_time" json:"build_start_time"`

	// BidStartTime is milliseconds relative to slot start for first bid.
	// Can be negative to bid before slot starts.
	BidStartTime int64 `yaml:"bid_start_time" json:"bid_start_time"`

	// BidEndTime is milliseconds relative to slot start for last bid.
	BidEndTime int64 `yaml:"bid_end_time" json:"bid_end_time"`

	// BidMinAmount is the minimum bid amount in gwei.
	// Bids use max(blockValue, BidMinAmount) as the starting bid value.
	BidMinAmount uint64 `yaml:"bid_min_amount" json:"bid_min_amount"`

	// BidIncrease is the amount to increase bid per subsequent bid in gwei.
	BidIncrease uint64 `yaml:"bid_increase" json:"bid_increase"`

	// BidInterval is milliseconds between bids. 0 means single bid.
	BidInterval int64 `yaml:"bid_interval" json:"bid_interval"`

	// BidSubsidy is added to every bid in gwei so the bid clears the proposer's
	// local-EL threshold (the BN otherwise self-builds when its local EL value is higher).
	BidSubsidy uint64 `yaml:"bid_subsidy" json:"bid_subsidy"`

	// BidValueOverride, when non-zero, replaces the bid base value
	// (max(blockValue, BidMinAmount) + BidSubsidy) with this absolute amount in
	// gwei — an alternative to the subsidy for testing; allows underbidding the
	// block value. BidIncrease still applies per subsequent bid. Per-slot action
	// plans override this per slot.
	BidValueOverride uint64 `yaml:"bid_value_override" json:"bid_value_override"`

	// BidCandidate selects which built candidate payload the p2p bids commit
	// to: "auto" (default; match the chain view's current head and payload
	// status), a specific candidate key (parent_full, parent_empty,
	// grandparent_full, grandparent_empty), or "all" (gossip a bid for every
	// built candidate — deliberate multi-parent bidding for gossip testing;
	// most nodes propagate only a builder's first bid per slot).
	BidCandidate string `yaml:"bid_candidate" json:"bid_candidate"`

	// KeyStrategy selects which managed builder key signs each of a slot's
	// bids: round_robin (default), single, random or least_used. Each key bids
	// at most once per slot — the gossip rules ignore a builder's later bids —
	// so with several built candidates the strategy decides which keys cover
	// them.
	KeyStrategy string `yaml:"key_strategy" json:"key_strategy"`

	// BidKeysPerSlot caps how many distinct builder keys bid a slot. 0 means
	// no cap beyond the fleet itself; 1 reproduces single-key behaviour (one
	// gossiped bid per slot) regardless of how many candidates were built.
	BidKeysPerSlot uint64 `yaml:"bid_keys_per_slot" json:"bid_keys_per_slot"`

	// BidKeysPerStep is how many keys bid a payload per interval step, each
	// one value-increment higher than the last. 1 (default) walks the fleet up
	// the interval ladder one key at a time; 0 spends every remaining key at
	// once, so a whole slot can be bid from all active keys in parallel as
	// soon as the bid window opens.
	BidKeysPerStep uint64 `yaml:"bid_keys_per_step" json:"bid_keys_per_step"`

	// BidCandidateSwitch allows the auto selection to switch to a different
	// candidate mid-slot when the chain view changes. Default off: the first
	// gossiped candidate sticks (the gossip first-seen rule makes a switched
	// bid unlikely to propagate anyway).
	BidCandidateSwitch bool `yaml:"bid_candidate_switch" json:"bid_candidate_switch"`

	// HeadVoteThresholdPct is the head-vote participation threshold in percent
	// (0-100) the vote tracker reports against: crossing it fires an immediate
	// update with threshold_met set. 0 disables threshold checking. The default
	// (60) mirrors the Gloas builder payment quorum
	// (BUILDER_PAYMENT_THRESHOLD_NUMERATOR/DENOMINATOR = 6/10) — the
	// participation level at which the builder's payment actually settles.
	HeadVoteThresholdPct uint64 `yaml:"head_vote_threshold_pct" json:"head_vote_threshold_pct"`
}

EPBSConfig defines time-scheduled bidding parameters for ePBS.

type Field

type Field struct {
	// Key is the canonical persisted/override key, e.g. "epbs.bid_subsidy".
	Key string
	// FlagKey is the viper flag key, e.g. "epbs-bid-subsidy", used with
	// viper.IsSet for CLI-change detection.
	FlagKey string
	// contains filtered or unexported fields
}

Field describes a single mutable setting: how to read and write it on a Config, its canonical storage key, and the viper flag key used to detect operator-supplied (CLI/env/config) changes across restarts.

Only mutable settings are registered. Immutable startup-only fields (keys, client URLs, ports, the state-db path) are intentionally absent: they are never overridable via the UI and never persisted.

func Fields

func Fields() []Field

Fields returns the registry of all mutable settings, including the per-module enable flags (which are configured via CLI flags exactly like other settings and therefore follow the same default/cli/ui resolution).

func (Field) Decode

func (f Field) Decode(raw json.RawMessage) (any, error)

Decode parses a JSON value into the field's Go type.

func (Field) Encode

func (f Field) Encode(v any) (json.RawMessage, error)

Encode serialises a typed value to JSON for storage.

func (Field) Equal

func (f Field) Equal(a, b any) bool

Equal reports whether two typed values of this field are equal.

func (Field) Get

func (f Field) Get(c *Config) any

Get reads the field's value from c.

func (Field) Set

func (f Field) Set(c *Config, v any) error

Set writes v into the field on c (in place).

type RevealConfig added in v0.0.3

type RevealConfig struct {
	// Enabled globally enables payload reveals. A plan-custom slot still
	// force-activates its reveal (mirroring the bid/builder_api categories).
	Enabled bool `yaml:"enabled" json:"enabled"`

	// GateMode decides the reveal moment: time | vote | vote_or_time |
	// vote_and_time (see the RevealGate* constants). Unknown values fall
	// back to time.
	GateMode string `yaml:"gate_mode" json:"gate_mode"`

	// TimeMs is milliseconds relative to slot start for the time gate.
	// 0 = auto-compute from slot time (see ApplySlotDefaults).
	TimeMs int64 `yaml:"time_ms" json:"time_ms"`

	// VoteThresholdPct is the head-vote participation (percent of the slot's
	// attesting balance on the committing block) that opens the vote gate.
	VoteThresholdPct uint64 `yaml:"vote_threshold_pct" json:"vote_threshold_pct"`

	// BroadcastValidation is the validation level the beacon node must apply
	// before broadcasting the envelope: gossip (default) | consensus |
	// consensus_and_equivocation (recommended for builders against
	// unbundling via equivocating blocks). Unknown values fall back to
	// gossip.
	BroadcastValidation string `yaml:"broadcast_validation" json:"broadcast_validation"`

	// MaxAttempts is the total number of publish attempts per reveal.
	MaxAttempts uint64 `yaml:"max_attempts" json:"max_attempts"`

	// RetryIntervalMs is the wait between failed publish attempts.
	RetryIntervalMs int64 `yaml:"retry_interval_ms" json:"retry_interval_ms"`

	// RebindOnReorg re-binds a slot's reveal to a different beacon block when
	// the block the reveal was scheduled for is reorged out and our payload is
	// re-included under a sibling root: the envelope is rebuilt and re-signed
	// for the new root (the payload bytes are unchanged).
	RebindOnReorg bool `yaml:"rebind_on_reorg" json:"rebind_on_reorg"`
}

RevealConfig defines the payload reveal behaviour shared by both flows (p2p ePBS bidding and the Builder API): the reveal service publishes every won slot's envelope according to these settings, per-slot overridable via the action plan's reveal category.

func (*RevealConfig) NormalizedBroadcastValidation added in v0.0.3

func (c *RevealConfig) NormalizedBroadcastValidation() string

NormalizedBroadcastValidation returns the broadcast validation level, falling back to gossip for unknown values.

func (*RevealConfig) NormalizedGateMode added in v0.0.3

func (c *RevealConfig) NormalizedGateMode() string

NormalizedGateMode returns the gate mode, falling back to RevealGateTime for unknown values (UI overrides are free-form strings).

type ScheduleConfig

type ScheduleConfig struct {
	Mode      ScheduleMode `yaml:"mode" json:"mode"`             // all, every_nth, next_n
	EveryNth  uint64       `yaml:"every_nth" json:"every_nth"`   // For every_nth mode
	NextN     uint64       `yaml:"next_n" json:"next_n"`         // For next_n mode
	StartSlot uint64       `yaml:"start_slot" json:"start_slot"` // Optional start slot
}

ScheduleConfig defines when the builder should build blocks.

type ScheduleMode

type ScheduleMode string

ScheduleMode represents the scheduling strategy for block building.

const (
	// ScheduleModeAll builds for all slots.
	ScheduleModeAll ScheduleMode = "all"
	// ScheduleModeEveryN builds for every Nth slot.
	ScheduleModeEveryN ScheduleMode = "every_nth"
	// ScheduleModeNextN builds for the next N slots then stops.
	ScheduleModeNextN ScheduleMode = "next_n"
)

type Service

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

Service is the central authority for buildoor's mutable runtime configuration. It owns the effective Config every module reads and is the single writer, layering three sources: hardcoded defaults < CLI-supplied < UI override. CLI and UI are resolved by recency (a monotonic seq), not a fixed priority: a CLI value that changed since the last run wins over an older UI override, while an unchanged CLI flag lets a newer UI override win. UI overrides persist across restarts via the optional state-db. The effective Config is the same pointer handed to every module, so writes (applied in place under the service lock) are observed live by all readers.

func NewService

func NewService(effective, defaults *Config, supplied map[string]bool, store *db.Database, log logrus.FieldLogger) (*Service, error)

New constructs the settings service.

  • effective is the resolved operator config (defaults + flags/env/file, already slot-adjusted); it becomes the shared config modules read and is mutated in place to apply overrides.
  • defaults is a pristine, slot-adjusted default Config used as the floor.
  • supplied maps each field key to whether the operator explicitly provided it (viper.IsSet); only supplied keys form the CLI layer.
  • store is the optional state-db (may be disabled).

func (*Service) Load

func (s *Service) Load() *Config

Load returns the effective The returned pointer is the shared config modules read; callers must treat it as read-only.

func (*Service) OnChange

func (s *Service) OnChange(fn func())

OnChange registers a callback invoked (outside the service lock) after every applied change. Used to trigger module-side resets and re-reads.

func (*Service) Set

func (s *Service) Set(key string, raw json.RawMessage, actor string) error

Set applies a single UI override.

func (*Service) SetMany

func (s *Service) SetMany(updates map[string]json.RawMessage, actor string) error

SetMany applies a batch of UI overrides atomically: all values are validated and decoded first, then applied, persisted, and the effective config recomputed before subscribers are notified once.

type ValidatorRangesConfig

type ValidatorRangesConfig struct {
	// File is a path to a YAML file in the format produced by ethereum-package:
	//   "0-127": "01-geth-lighthouse"
	//   "128-255": "02-nethermind-teku"
	File string `yaml:"file" json:"file,omitempty"`

	// URL is fetched on startup and refreshed every 5 minutes.
	// Expected JSON: {"ranges": {"0-199": "prysm-ethrex-1", ...}}
	// Template: https://config.<network>.ethpandaops.io/api/v1/nodes/validator-ranges
	URL string `yaml:"url" json:"url,omitempty"`
}

ValidatorRangesConfig configures how to load validator index → client name mappings. If both are set, URL takes precedence.

Jump to

Keyboard shortcuts

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