Documentation
¶
Overview ¶
Package lifecycle provides builder lifecycle management (deposit, balance, exit) as an ePBS sub-concern.
Index ¶
- Variables
- func BuildBuilderDepositCalldata(pubkey []byte, withdrawalCredentials []byte, amountGwei uint64, ...) ([]byte, error)
- func BuildBuilderExitCalldata(pubkey []byte) ([]byte, error)
- func BuilderWithdrawalCredentials(walletAddress common.Address) [32]byte
- func GweiToWei(gwei uint64) *big.Int
- func ReadQueueFee(ctx context.Context, reader contractReader, contract common.Address) (fee *big.Int, active bool, err error)
- func ValidatorWithdrawalCredentials(walletAddress common.Address) [32]byte
- type BalanceService
- type BuilderState
- type DepositService
- func (s *DepositService) CreateDeposit(ctx context.Context, key *builder_keys.Key, amountGwei uint64) error
- func (s *DepositService) CreateDeposits(ctx context.Context, keys []*builder_keys.Key, amountGwei uint64) ([]error, error)
- func (s *DepositService) CreateTopup(ctx context.Context, key *builder_keys.Key, amountGwei uint64) error
- func (s *DepositService) IsBuilderRegistered(key *builder_keys.Key) (bool, *BuilderState, error)
- type EarlyDepositService
- type ExitService
- type LifecycleEvent
- type Manager
- func (m *Manager) CheckAndTopup(ctx context.Context, key *builder_keys.Key) error
- func (m *Manager) EnsureBuilderRegistered(ctx context.Context, key *builder_keys.Key) error
- func (m *Manager) GetBuilderState() *BuilderState
- func (m *Manager) GetPaymentTracker() *payload_bidder.PaymentTracker
- func (m *Manager) GetWallet() *wallet.Wallet
- func (m *Manager) InitiateExit(ctx context.Context, key *builder_keys.Key) error
- func (m *Manager) IsEnabled() bool
- func (m *Manager) Reconcile()
- func (m *Manager) Registry() *builder_keys.Registry
- func (m *Manager) SetDepositPendingCallback(cb func())
- func (m *Manager) SetEnabled(enabled bool)
- func (m *Manager) SetEventCallback(cb func(*LifecycleEvent))
- func (m *Manager) SetPaymentTracker(payments *payload_bidder.PaymentTracker)
- func (m *Manager) SetRegistrationCallback(cb func(index uint64))
- func (m *Manager) Start(ctx context.Context) error
- func (m *Manager) Stop()
- func (m *Manager) TopupKey(ctx context.Context, key *builder_keys.Key, amountGwei uint64) error
- func (m *Manager) WaitForRegistration(ctx context.Context, key *builder_keys.Key, timeout time.Duration) error
Constants ¶
This section is empty.
Variables ¶
var ( // BuilderDepositContractAddress is the EIP-8282 builder deposit predeploy. BuilderDepositContractAddress = common.HexToAddress("0x0000bFF46984e3725691FA540a8C7589300D8282") // BuilderExitContractAddress is the EIP-8282 builder exit predeploy. BuilderExitContractAddress = common.HexToAddress("0x000064D678505ad48F8cCb093BC65613800E8282") )
Builder system-contract addresses (EIP-8282 predeploys, injected by the EL at the Amsterdam fork). Hard-coded per the current EIP-8282 draft (ethereum-genesis-generator#300); ReadQueueFee verifies code exists at the address before any request is submitted, so a stale address fails loudly instead of sending value transfers to an empty account.
var ErrBuilderExited = errors.New("builder has exited and cannot be reactivated; deposits are disabled until the pubkey leaves the builder registry")
ErrBuilderExited is returned when a deposit/top-up targets a builder whose exit has been initiated. Exited builders can never be reactivated: the deposit would only top up the exited registry entry and be withdrawn back to the wallet by the sweep. The pubkey becomes depositable again only once it leaves the builder registry (its index is reused by a different builder's deposit).
var ErrContractNotActive = errors.New("builder deposit contract not active yet")
ErrContractNotActive is returned while the builder deposit contract still holds the pre-fork excess inhibitor (before GLOAS_FORK_EPOCH), so deposits can't be submitted yet.
var ErrContractNotDeployed = errors.New("builder system contract not deployed")
ErrContractNotDeployed is returned when a builder system contract has no code at its expected address. Before the Amsterdam fork this is normal (the EL injects the predeploys at the fork); after the fork it means the network uses different addresses than this build expects.
var ErrDepositFeeTooHigh = errors.New("builder deposit queue fee exceeds configured limit")
ErrDepositFeeTooHigh is returned when the builder deposit contract's current queue fee exceeds the operator's configured limit (DepositMaxFeeGwei). It is a signal to delay the deposit/top-up and retry later, not a hard failure.
var ErrNoDepositContract = errors.New("no validator deposit contract address in spec")
ErrNoDepositContract is returned when the beacon spec does not advertise a regular validator deposit contract address, so early onboarding cannot submit a deposit.
Functions ¶
func BuildBuilderDepositCalldata ¶
func BuildBuilderDepositCalldata( pubkey []byte, withdrawalCredentials []byte, amountGwei uint64, signature []byte, ) ([]byte, error)
BuildBuilderDepositCalldata builds the 184-byte builder deposit request calldata: pubkey(48) ++ withdrawal_credentials(32) ++ amount(8, big-endian gwei) ++ signature(96). The source address is implicit in the deposit signature.
func BuildBuilderExitCalldata ¶
BuildBuilderExitCalldata builds the 48-byte builder exit request calldata (the builder pubkey). The source address is the transaction sender (msg.sender), which must match the builder's registered execution address.
func BuilderWithdrawalCredentials ¶
BuilderWithdrawalCredentials builds the withdrawal credentials for an EIP-8282 builder deposit. Format: 0xB0 + 00...00 (11 zero bytes) + wallet_address (20 bytes).
func ReadQueueFee ¶
func ReadQueueFee( ctx context.Context, reader contractReader, contract common.Address, ) (fee *big.Int, active bool, err error)
ReadQueueFee reads the current per-request queue fee (in wei) for a builder system contract. It returns active=false while the contract still holds the pre-fork excess inhibitor (i.e. before GLOAS_FORK_EPOCH), signalling the caller to wait. The returned fee prices in queueFeeHeadroom extra slots for safety.
It returns ErrContractNotDeployed when there is no code at the contract address: an empty account reads slot 0 as zero, which would otherwise look like an active contract with an empty queue, and requests sent there confirm as plain value transfers without ever reaching the beacon chain.
func ValidatorWithdrawalCredentials ¶
ValidatorWithdrawalCredentials builds the withdrawal credentials for the pre-Gloas early-onboarding deposit, which is submitted through the regular validator deposit contract. Format: 0xB0 + 00...00 (11 zero bytes) + wallet_address (20 bytes).
Types ¶
type BalanceService ¶
type BalanceService struct {
// contains filtered or unexported fields
}
BalanceService monitors builder key balances and performs automatic top-ups. Balances come from the key registry, which resolves them from the same epoch snapshot for the whole key set, so monitoring hundreds of keys costs one pass rather than one beacon query per key.
func NewBalanceService ¶
func NewBalanceService( cfg *config.Config, chainSvc chain.Service, registry *builder_keys.Registry, depositSvc *DepositService, log logrus.FieldLogger, ) *BalanceService
NewBalanceService creates a new balance service.
func (*BalanceService) CheckAndTopup ¶
func (s *BalanceService) CheckAndTopup(ctx context.Context, key *builder_keys.Key) (uint64, error)
CheckAndTopup tops the key up when its balance is below the threshold. It returns the amount deposited in gwei, or 0 when no top-up was needed — the caller credits exactly that to the live balance rather than guessing it.
func (*BalanceService) GetEffectiveBalance ¶
func (s *BalanceService) GetEffectiveBalance(key *builder_keys.Key) (uint64, error)
GetEffectiveBalance returns the key's spendable balance: the chain balance plus local adjustments (top-ups credited, revealed payments debited) minus the pending payments the beacon state still owes out of it.
func (*BalanceService) NeedsTopup ¶
func (s *BalanceService) NeedsTopup(key *builder_keys.Key) (bool, uint64, error)
NeedsTopup checks whether a key needs a top-up and returns the required amount. It returns ErrBuilderExited for a key whose exit has been initiated: after the sweep zeroes the balance a top-up would otherwise trigger every cooldown, cycling funds wallet -> exited entry -> (64 epochs locked) -> wallet forever.
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 DepositService ¶
type DepositService struct {
// contains filtered or unexported fields
}
DepositService handles builder deposits and top-ups via the EIP-8282 builder deposit system contract. It is key-agnostic: every operation names the builder key it acts on, so one service serves the whole managed key set.
func NewDepositService ¶
func NewDepositService( cfg *config.Config, chainSvc chain.Service, w *wallet.Wallet, log logrus.FieldLogger, ) (*DepositService, error)
NewDepositService creates a new deposit service.
func (*DepositService) CreateDeposit ¶
func (s *DepositService) CreateDeposit( ctx context.Context, key *builder_keys.Key, amountGwei uint64, ) error
CreateDeposit creates and sends an EIP-8282 builder deposit transaction for the given key. It is also used for top-ups (which are simply additional deposits for the same pubkey).
Before submitting it reads the contract's current per-request queue fee and, when DepositMaxFeeGwei is set, returns ErrDepositFeeTooHigh if the fee exceeds the limit so the caller can delay and retry. The transaction value is stake + queue fee.
func (*DepositService) CreateDeposits ¶ added in v0.0.3
func (s *DepositService) CreateDeposits( ctx context.Context, keys []*builder_keys.Key, amountGwei uint64, ) ([]error, error)
CreateDeposits submits deposits for several keys as one batch and returns the per-key errors (nil for the keys that landed). Batching matters because every deposit is serialized on the same funding key: bringing a fleet up one confirmed transaction at a time costs a block per key.
The queue fee is read once for the whole batch — it is a property of the contract, not of a key — so a fee over the operator's limit defers the whole batch with a single error rather than per key.
func (*DepositService) CreateTopup ¶
func (s *DepositService) CreateTopup( ctx context.Context, key *builder_keys.Key, amountGwei uint64, ) error
CreateTopup creates and sends a top-up transaction (an additional deposit).
func (*DepositService) IsBuilderRegistered ¶
func (s *DepositService) IsBuilderRegistered(key *builder_keys.Key) (bool, *BuilderState, error)
IsBuilderRegistered checks if the given builder key is registered on the beacon chain.
type EarlyDepositService ¶
type EarlyDepositService struct {
// contains filtered or unexported fields
}
EarlyDepositService submits a pre-Gloas builder onboarding deposit via the regular validator deposit contract. Both paths use 0xB0 withdrawal credentials, but unlike the post-fork builder deposit (EIP-8282 predeploy, DOMAIN_BUILDER_DEPOSIT), an early deposit is signed with the validator deposit domain — i.e. it is an ordinary validator deposit that sits in the beacon state's pending_deposits queue and is converted into a builder at the Gloas fork boundary.
func NewEarlyDepositService ¶
func NewEarlyDepositService( cfg *config.Config, chainSvc chain.Service, w *wallet.Wallet, log logrus.FieldLogger, ) (*EarlyDepositService, error)
NewEarlyDepositService creates a new early deposit service.
func (*EarlyDepositService) CreateEarlyDeposits ¶ added in v0.0.3
func (s *EarlyDepositService) CreateEarlyDeposits( ctx context.Context, keys []*builder_keys.Key, amountGwei uint64, ) ([]error, error)
CreateEarlyDeposits builds, signs and sends validator deposits for the given keys as one batch, returning the per-key errors (nil for the keys that landed).
The deposits use 0xB0 (BUILDER_WITHDRAWAL_PREFIX) withdrawal credentials pointing at the funding wallet and are signed with the validator deposit domain over GENESIS_FORK_VERSION. They do not race each other: they sit in the pending-deposit queue together and the Gloas transition converts them all.
func (*EarlyDepositService) HasPendingDeposit ¶
func (s *EarlyDepositService) HasPendingDeposit(key *builder_keys.Key) bool
HasPendingDeposit reports whether the key's pubkey is already present in the beacon state's pending_deposits queue. It is used after a restart to avoid submitting a duplicate early deposit while a prior one is still waiting in the queue.
type ExitService ¶
type ExitService struct {
// contains filtered or unexported fields
}
ExitService handles builder exits via the EIP-8282 builder exit system contract.
Unlike a validator voluntary exit (a BLS-signed beacon message), a builder exit is an execution-layer transaction to the builder exit predeploy carrying only the builder pubkey as calldata. The source is the transaction sender (msg.sender), which must match the builder's registered execution address — i.e. the funding wallet that supplied the withdrawal credentials at deposit time. A per-request queue fee is paid as msg.value.
func NewExitService ¶
func NewExitService( chainSvc chain.Service, w *wallet.Wallet, log logrus.FieldLogger, ) *ExitService
NewExitService creates a new exit service.
func (*ExitService) CreateExit ¶
func (s *ExitService) CreateExit(ctx context.Context, key *builder_keys.Key) error
CreateExit submits a builder exit request transaction for the given key.
Exits always proceed regardless of the configured deposit fee limit (unlike deposits/top-ups, which are delayed when the fee is too high), so the operator can always withdraw. The queue fee is read from the contract and paid as msg.value.
type LifecycleEvent ¶
type LifecycleEvent struct {
Action string // "deposit", "topup", "exit", "state_change", "waiting_gloas", "balance_topup"
Message string // Human-readable description
Status string // "info", "success", "warning", "error"
}
LifecycleEvent represents a lifecycle action for UI logging.
type Manager ¶
type Manager struct {
// contains filtered or unexported fields
}
Manager orchestrates builder lifecycle operations.
func NewManager ¶
func NewManager( cfg *config.Config, clClient *beacon.Client, chainSvc chain.Service, registry *builder_keys.Registry, w *wallet.Wallet, log logrus.FieldLogger, ) (*Manager, error)
NewManager creates a new lifecycle manager.
func (*Manager) CheckAndTopup ¶
CheckAndTopup tops the given key up when its balance is below the threshold.
func (*Manager) EnsureBuilderRegistered ¶
EnsureBuilderRegistered checks whether the given builder key is registered and deposits if needed. This is the synchronous version used by CLI commands (e.g. cmd/deposit.go) and the lifecycle API.
func (*Manager) GetBuilderState ¶
func (m *Manager) GetBuilderState() *BuilderState
GetBuilderState returns the current builder state.
func (*Manager) GetPaymentTracker ¶ added in v0.0.2
func (m *Manager) GetPaymentTracker() *payload_bidder.PaymentTracker
GetPaymentTracker returns the shared payment tracker.
func (*Manager) InitiateExit ¶
InitiateExit submits a builder exit request for the given key via the builder exit system contract.
func (*Manager) Reconcile ¶ added in v0.0.3
func (m *Manager) Reconcile()
Reconcile requests an immediate reconcile pass. Called when the target key count changes so a UI edit acts within a second rather than at the next tick.
func (*Manager) Registry ¶ added in v0.0.3
func (m *Manager) Registry() *builder_keys.Registry
Registry returns the managed builder key set.
func (*Manager) SetDepositPendingCallback ¶
func (m *Manager) SetDepositPendingCallback(cb func())
SetDepositPendingCallback sets the callback invoked when a deposit is submitted.
func (*Manager) SetEnabled ¶
SetEnabled sets whether the lifecycle manager is actively managing the builder.
func (*Manager) SetEventCallback ¶
func (m *Manager) SetEventCallback(cb func(*LifecycleEvent))
SetEventCallback sets the callback invoked when lifecycle events occur (for UI logging).
func (*Manager) SetPaymentTracker ¶ added in v0.0.2
func (m *Manager) SetPaymentTracker(payments *payload_bidder.PaymentTracker)
SetPaymentTracker sets the shared payment tracker for the balance service and stores it for direct access.
func (*Manager) SetRegistrationCallback ¶
SetRegistrationCallback sets the callback invoked when builder registration completes.
func (*Manager) Start ¶
Start starts the lifecycle manager with async registration and balance monitoring.
func (*Manager) TopupKey ¶ added in v0.0.3
TopupKey submits a top-up deposit for the key regardless of its current balance — the operator asked for it explicitly. amountGwei of 0 uses the configured top-up amount.
func (*Manager) WaitForRegistration ¶
func (m *Manager) WaitForRegistration( ctx context.Context, key *builder_keys.Key, timeout time.Duration, ) error
WaitForRegistration waits for the given builder key to be registered.