p2p_bidder

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

Documentation

Overview

Package p2p_bidder implements the active p2p bidding flow of ePBS (bid windows, bid submission, competitor tracking, registration state).

Index

Constants

View Source
const (
	RegistrationStateUnknown             int32 = 0 // Not checked yet
	RegistrationStatePending             int32 = 1 // Deposit submitted, waiting for inclusion in beacon state
	RegistrationStateRegistered          int32 = 2 // Builder registered and deposit epoch finalized
	RegistrationStateWaitingGloas        int32 = 3 // Waiting for Gloas fork activation
	RegistrationStatePendingFinalization int32 = 4 // Builder in beacon state but deposit epoch not finalized
	RegistrationStateExiting             int32 = 5 // Exit submitted, withdrawable epoch set but not reached
	RegistrationStateExited              int32 = 6 // Withdrawable epoch passed, builder has exited
	RegistrationStateUnregistered        int32 = 7 // Builder not in beacon state and no deposit in progress
)

Registration state constants for the p2p bidder service.

View Source
const (
	// BidStatusSubmitted means the bid was constructed and gossiped.
	BidStatusSubmitted = "submitted"
	// BidStatusConstructed means the bid was built and signed, but the network
	// submission failed.
	BidStatusConstructed = "constructed"
	// BidStatusFailed means bid construction itself failed.
	BidStatusFailed = "failed"
)

Bid submission statuses reported via BidSubmissionEvent.Status.

Variables

This section is empty.

Functions

func RegistrationStateName

func RegistrationStateName(state int32) string

RegistrationStateName returns the string name for a registration state.

Types

type BidCreator

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

BidCreator builds ePBS bids via the shared payload_bidder and gossips them over p2p. It owns the p2p transport and the (caller-computed) bid economics; the bid construction and signing live in payload_bidder. The builder identity comes in per bid: which of the managed keys signs is a scheduler decision.

func NewBidCreator

func NewBidCreator(
	clClient bidSubmitter,
	chainSvc chain.Service,
	log logrus.FieldLogger,
) *BidCreator

NewBidCreator creates a new bid creator.

func (*BidCreator) CreateAndSubmitBid

func (c *BidCreator) CreateAndSubmitBid(
	ctx context.Context,
	key *builder_keys.Key,
	payload *payload_builder.Payload,
	bidValue uint64,
	bidTransform string,
) (*eth2all.SignedExecutionPayloadBid, error)

CreateAndSubmitBid builds, signs, and gossips a bid for the given payload at the supplied value, from the given builder key. The competitive bid value is decided by the scheduler; the ePBS p2p path takes no execution payment. The constructed signed bid is returned even when the network submission fails so callers can record the exact object that was built; it is nil only when construction itself failed.

type BidSubmissionEvent

type BidSubmissionEvent struct {
	Slot      phase0.Slot
	BlockHash [32]byte
	Value     uint64
	BidCount  int
	Success   bool
	Warning   string // Non-fatal warning (e.g. "no proposer preferences")
	Error     string

	// Status is one of BidStatusSubmitted/BidStatusConstructed/BidStatusFailed
	// for submission attempts (empty for pre-construction skip events).
	Status string
	// SignedBid is the constructed signed bid; nil when construction failed
	// (or for pre-construction skip events).
	SignedBid *eth2all.SignedExecutionPayloadBid
	// CompetitorHighGwei is the highest competitor bid known for the slot at
	// fire time (our own builder index excluded); nil when none is known.
	CompetitorHighGwei *uint64
}

BidSubmissionEvent represents a bid submission attempt (success or failure).

type BidTracker

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

BidTracker tracks bids observed on the p2p network for competition analysis.

func NewBidTracker

func NewBidTracker(registry *builder_keys.Registry, log logrus.FieldLogger) *BidTracker

NewBidTracker creates a new bid tracker. The key registry identifies which gossiped bids are ours: with several managed keys bidding the same slot, any of their builder indices must be excluded from competitor comparisons.

func (*BidTracker) Cleanup

func (t *BidTracker) Cleanup(olderThan phase0.Slot)

Cleanup removes old slot data.

func (*BidTracker) GetHighestBid

func (t *BidTracker) GetHighestBid(slot phase0.Slot) *TrackedBid

GetHighestBid returns the highest bid for a slot.

func (*BidTracker) GetHighestCompetitorBid added in v0.0.3

func (t *BidTracker) GetHighestCompetitorBid(
	slot phase0.Slot, parentHash phase0.Hash32,
) (uint64, bool)

GetHighestCompetitorBid returns the highest tracked bid value (gwei) for the slot excluding every key of ours, and whether any competitor bid is known. Unlike GetHighestBid it can never report one of our own bids back to us — which matters once several managed keys bid the same slot. A non-zero parentHash restricts the comparison to bids committing to the same execution parent (bids on other forks are not competing).

func (*BidTracker) GetOurBid

func (t *BidTracker) GetOurBid(slot phase0.Slot) *TrackedBid

GetOurBid returns our bid for a slot.

func (*BidTracker) GetSlotBids

func (t *BidTracker) GetSlotBids(slot phase0.Slot) *SlotBids

GetSlotBids returns all bids for a slot.

func (*BidTracker) IsOurs added in v0.0.3

func (t *BidTracker) IsOurs(builderIndex uint64) bool

IsOurs reports whether a gossiped bid's builder index belongs to the managed key set.

func (*BidTracker) TrackBid

func (t *BidTracker) TrackBid(bid *ExecutionPayloadBid, isOurs bool)

TrackBid adds a bid to the tracker.

type ExecutionPayloadBid

type ExecutionPayloadBid struct {
	ParentBlockHash  phase0.Hash32
	ParentBlockRoot  phase0.Root
	BlockHash        phase0.Hash32
	FeeRecipient     [20]byte
	GasLimit         uint64
	BuilderIndex     uint64
	Slot             phase0.Slot
	Value            uint64 // Gwei
	ExecutionPayment uint64 // Gwei
}

ExecutionPayloadBid represents a bid for an execution payload.

type Scheduler

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

Scheduler handles time-based bid scheduling. It uses a simple loop that checks current time and triggers actions.

func NewScheduler

func NewScheduler(
	chainSvc chain.Service,
	bidCreator *BidCreator,
	bidTracker *BidTracker,
	payloadCache *payload_builder.PayloadCache,
	service *Service,
	registry *builder_keys.Registry,
	propPrefsStore *memstore.Store[phase0.Slot, *gloasspec.SignedProposerPreferences],
	planSvc *action_plan.PlanService,
	cfg *config.Config,
	log logrus.FieldLogger,
) *Scheduler

NewScheduler creates a new scheduler. planSvc is the mandatory per-slot action plan service: every bid setting the scheduler acts on comes from its frozen slot snapshots, never from the live config — except the bid candidate selection, which is deliberately live (the whole point is choosing at bid time, after the plan froze).

func (*Scheduler) Cleanup

func (s *Scheduler) Cleanup(olderThan phase0.Slot)

Cleanup removes old state.

func (*Scheduler) GetBidTracker

func (s *Scheduler) GetBidTracker() *BidTracker

GetBidTracker returns the bid tracker.

func (*Scheduler) OnHeadChange added in v0.0.3

func (s *Scheduler) OnHeadChange(ctx context.Context, change *chain.HeadChangeEvent)

OnHeadChange reopens bidding for slots whose closing block was reorged out: with the block gone, the slot's proposer opportunity is live again for the rest of its bid window.

func (*Scheduler) OnHeadEvent

func (s *Scheduler) OnHeadEvent(event *beacon.HeadEvent)

OnHeadEvent closes bidding for the slot — once a block is produced, no more bids can make it.

func (*Scheduler) ProcessTick

func (s *Scheduler) ProcessTick(ctx context.Context)

ProcessTick is called frequently to check if any bids are due.

func (*Scheduler) Wait added in v0.0.3

func (s *Scheduler) Wait()

Wait blocks until every in-flight bid submission has finished. Called during shutdown, after the context is cancelled.

type Service

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

Service is the p2p bidder orchestrator that handles time-scheduled bidding. It submits bids during the slot's bid window, tracks competitor bids from the gossip stream, and maintains the builder's registration state. Once a slot's block is produced (head event), the bidder is done with that slot — reveals, inclusion tracking, and payment accounting live in the shared payload_bidder services.

func NewService

func NewService(
	clClient *beacon.Client,
	chainSvc chain.Service,
	registry *builder_keys.Registry,
	propPrefsStore *memstore.Store[phase0.Slot, *gloasspec.SignedProposerPreferences],
	planSvc *action_plan.PlanService,
	log logrus.FieldLogger,
) (*Service, error)

NewService creates a new p2p bidder service. propPrefsStore is the shared per-slot proposer preferences store (owned by payload_bidder.ProposerPreferencesService); it gates bidding — slots without a cached preference are skipped. It may be nil, in which case no bids are submitted. planSvc is the mandatory per-slot action plan service — the single scheduling/settings authority: the scheduler freezes each slot's plan on first evaluation and the frozen snapshot alone decides whether and how the slot is bid on (a plan may activate bidding for a slot even when ePBS is globally disabled).

func (*Service) FireBidSubmission

func (s *Service) FireBidSubmission(event *BidSubmissionEvent)

FireBidSubmission fires a bid submission event.

func (*Service) GetBidTracker

func (s *Service) GetBidTracker() *BidTracker

GetBidTracker returns the bid tracker.

func (*Service) GetBuilderIndex

func (s *Service) GetBuilderIndex() uint64

GetBuilderIndex returns the primary key's on-chain builder index (0 when it is not registered). Status reporting only — bids carry the index of the key that signed them.

func (*Service) GetBuilderPubkey

func (s *Service) GetBuilderPubkey() phase0.BLSPubKey

GetBuilderPubkey returns the primary key's public key.

func (*Service) GetRegistrationState

func (s *Service) GetRegistrationState() int32

GetRegistrationState returns the current registration state.

func (*Service) IsActive

func (s *Service) IsActive() bool

IsActive returns whether the builder can actively participate (registered or pending finalization).

func (*Service) IsEnabled

func (s *Service) IsEnabled() bool

IsEnabled returns whether the p2p bidder service is enabled (status reporting only; not consulted by the bid scheduler).

func (*Service) IsRegistered

func (s *Service) IsRegistered() bool

IsRegistered returns whether the builder has a valid index and its deposit is finalized.

func (*Service) RefreshRegistrationState

func (s *Service) RefreshRegistrationState()

RefreshRegistrationState re-evaluates the registration state from the chain service. Called periodically to detect state transitions (e.g. finalization, exit).

func (*Service) Registry added in v0.0.3

func (s *Service) Registry() *builder_keys.Registry

Registry returns the managed builder key set.

func (*Service) SetBuilderRegistered

func (s *Service) SetBuilderRegistered(index uint64)

SetBuilderRegistered re-evaluates the reported registration state when the lifecycle manager detects a registration. The builder index itself lives on the key registry; this only drives the status reporting.

func (*Service) SetEnabled

func (s *Service) SetEnabled(enabled bool)

SetEnabled sets the enabled state of the p2p bidder service. The flag is status reporting only (WebUI/API); the per-slot bid decision comes solely from the action plan's frozen snapshots.

func (*Service) SetRegistrationPending

func (s *Service) SetRegistrationPending()

SetRegistrationPending marks the builder as having a deposit in flight. Called by the lifecycle manager when a deposit is submitted.

A deposit only says something about the key it funds. Once any key of the fleet is active the builder can bid, so a deposit for some other key must not pull the reported state back to pending — the scheduler gates bidding on it, and a fleet ramping toward its target deposits continuously, which would otherwise suppress bidding for the whole ramp.

func (*Service) Start

func (s *Service) Start(ctx context.Context, builderSvc *payload_builder.Service) error

Start starts the p2p bidder service.

func (*Service) Stop

func (s *Service) Stop()

Stop stops the p2p bidder service.

func (*Service) SubscribeBidSubmissions

func (s *Service) SubscribeBidSubmissions(capacity int, blocking bool) *utils.Subscription[*BidSubmissionEvent]

SubscribeBidSubmissions subscribes to bid submission events. Blocking subscriptions never drop events (authoritative consumers, e.g. the slot results tracker); non-blocking ones drop on a full buffer (e.g. the WebUI SSE bridge).

type SlotBids

type SlotBids struct {
	Slot       phase0.Slot
	Bids       map[uint64]*TrackedBid // BuilderIndex -> Bid
	HighestBid *TrackedBid
	OurBid     *TrackedBid
	WinningBid *TrackedBid // Set after block inclusion
}

SlotBids holds all bids for a specific slot.

func NewSlotBids

func NewSlotBids(slot phase0.Slot) *SlotBids

NewSlotBids creates a new SlotBids instance for the given slot.

type SlotState

type SlotState struct {
	LastBidTime      time.Time
	LastBidHash      phase0.Hash32
	BidCount         int
	BidsClosed       bool        // Block received, no more bids possible
	ClosedByRoot     phase0.Root // block root that closed bidding (reopens if orphaned)
	NoPrefsWarnedFor bool        // Missing-preferences skip already reported for this slot
	NoKeyWarnedFor   bool        // No-ready-key skip already reported for this slot

	// PayloadBids tracks each payload's own bid progress, so multi-candidate
	// bidding ("all") does not starve the other candidates behind one payload's
	// interval gate.
	PayloadBids map[phase0.Hash32]*payloadBidState

	// BidCandidate is the candidate the auto selection committed to on the
	// first bid of the slot (sticky unless candidate switching is enabled).
	BidCandidate    chain.CandidateKey
	BidCandidateSet bool

	// UsedKeys holds the keys that already gossiped a bid for this slot. The
	// gossip rules ignore every bid a builder makes after its first for a slot,
	// so a key is SPENT once one of its bids reached the network — every later
	// bid, including an escalated re-bid of the very same payload, has to come
	// from a key that has not bid yet or it never propagates.
	UsedKeys map[uint64]struct{}

	// Frozen is the slot's immutable action-plan snapshot, resolved on the
	// first scheduler evaluation of the slot (nil until then).
	Frozen *action_plan.FrozenPlan
}

SlotState tracks the bidding state for a single slot.

type TrackedBid

type TrackedBid struct {
	Bid          *ExecutionPayloadBid
	BuilderIndex uint64
	ReceivedAt   time.Time
	IsOurs       bool
}

TrackedBid represents a bid being tracked for competition analysis.

Jump to

Keyboard shortcuts

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