mirror of
https://github.com/sigp/lighthouse.git
synced 2026-03-19 12:56:12 +00:00
Builder Specs v0.2.0 (#3134)
## Issue Addressed https://github.com/sigp/lighthouse/issues/3091 Extends https://github.com/sigp/lighthouse/pull/3062, adding pre-bellatrix block support on blinded endpoints and allowing the normal proposal flow (local payload construction) on blinded endpoints. This resulted in better fallback logic because the VC will not have to switch endpoints on failure in the BN <> Builder API, the BN can just fallback immediately and without repeating block processing that it shouldn't need to. We can also keep VC fallback from the VC<>BN API's blinded endpoint to full endpoint. ## Proposed Changes - Pre-bellatrix blocks on blinded endpoints - Add a new `PayloadCache` to the execution layer - Better fallback-from-builder logic ## Todos - [x] Remove VC transition logic - [x] Add logic to only enable builder flow after Merge transition finalization - [x] Tests - [x] Fix metrics - [x] Rustdocs Co-authored-by: Mac L <mjladson@pm.me> Co-authored-by: realbigsean <sean@sigmaprime.io>
This commit is contained in:
@@ -3,6 +3,7 @@ use crate::{
|
||||
http_metrics::metrics,
|
||||
initialized_validators::InitializedValidators,
|
||||
signing_method::{Error as SigningError, SignableMessage, SigningContext, SigningMethod},
|
||||
Config,
|
||||
};
|
||||
use account_utils::{validator_definitions::ValidatorDefinition, ZeroizeString};
|
||||
use parking_lot::{Mutex, RwLock};
|
||||
@@ -27,6 +28,7 @@ use types::{
|
||||
use validator_dir::ValidatorDir;
|
||||
|
||||
pub use crate::doppelganger_service::DoppelgangerStatus;
|
||||
use crate::preparation_service::ProposalData;
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum Error {
|
||||
@@ -52,6 +54,11 @@ impl From<SigningError> for Error {
|
||||
/// This acts as a maximum safe-guard against clock drift.
|
||||
const SLASHING_PROTECTION_HISTORY_EPOCHS: u64 = 512;
|
||||
|
||||
/// Currently used as the default gas limit in execution clients.
|
||||
///
|
||||
/// https://github.com/ethereum/builder-specs/issues/17
|
||||
const DEFAULT_GAS_LIMIT: u64 = 30_000_000;
|
||||
|
||||
struct LocalValidator {
|
||||
validator_dir: ValidatorDir,
|
||||
voting_keypair: Keypair,
|
||||
@@ -87,6 +94,8 @@ pub struct ValidatorStore<T, E: EthSpec> {
|
||||
doppelganger_service: Option<Arc<DoppelgangerService>>,
|
||||
slot_clock: T,
|
||||
fee_recipient_process: Option<Address>,
|
||||
gas_limit: Option<u64>,
|
||||
builder_proposals: bool,
|
||||
task_executor: TaskExecutor,
|
||||
_phantom: PhantomData<E>,
|
||||
}
|
||||
@@ -102,7 +111,7 @@ impl<T: SlotClock + 'static, E: EthSpec> ValidatorStore<T, E> {
|
||||
spec: ChainSpec,
|
||||
doppelganger_service: Option<Arc<DoppelgangerService>>,
|
||||
slot_clock: T,
|
||||
fee_recipient_process: Option<Address>,
|
||||
config: &Config,
|
||||
task_executor: TaskExecutor,
|
||||
log: Logger,
|
||||
) -> Self {
|
||||
@@ -115,7 +124,9 @@ impl<T: SlotClock + 'static, E: EthSpec> ValidatorStore<T, E> {
|
||||
log,
|
||||
doppelganger_service,
|
||||
slot_clock,
|
||||
fee_recipient_process,
|
||||
fee_recipient_process: config.fee_recipient,
|
||||
gas_limit: config.gas_limit,
|
||||
builder_proposals: config.builder_proposals,
|
||||
task_executor,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
@@ -146,6 +157,7 @@ impl<T: SlotClock + 'static, E: EthSpec> ValidatorStore<T, E> {
|
||||
|
||||
/// Insert a new validator to `self`, where the validator is represented by an EIP-2335
|
||||
/// keystore on the filesystem.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub async fn add_validator_keystore<P: AsRef<Path>>(
|
||||
&self,
|
||||
voting_keystore_path: P,
|
||||
@@ -153,12 +165,16 @@ impl<T: SlotClock + 'static, E: EthSpec> ValidatorStore<T, E> {
|
||||
enable: bool,
|
||||
graffiti: Option<GraffitiString>,
|
||||
suggested_fee_recipient: Option<Address>,
|
||||
gas_limit: Option<u64>,
|
||||
builder_proposals: Option<bool>,
|
||||
) -> Result<ValidatorDefinition, String> {
|
||||
let mut validator_def = ValidatorDefinition::new_keystore_with_password(
|
||||
voting_keystore_path,
|
||||
Some(password),
|
||||
graffiti.map(Into::into),
|
||||
suggested_fee_recipient,
|
||||
gas_limit,
|
||||
builder_proposals,
|
||||
)
|
||||
.map_err(|e| format!("failed to create validator definitions: {:?}", e))?;
|
||||
|
||||
@@ -200,6 +216,23 @@ impl<T: SlotClock + 'static, E: EthSpec> ValidatorStore<T, E> {
|
||||
Ok(validator_def)
|
||||
}
|
||||
|
||||
/// Returns `ProposalData` for the provided `pubkey` if it exists in `InitializedValidators`.
|
||||
/// `ProposalData` fields include defaulting logic described in `get_fee_recipient_defaulting`,
|
||||
/// `get_gas_limit_defaulting`, and `get_builder_proposals_defaulting`.
|
||||
pub fn proposal_data(&self, pubkey: &PublicKeyBytes) -> Option<ProposalData> {
|
||||
self.validators
|
||||
.read()
|
||||
.validator(pubkey)
|
||||
.map(|validator| ProposalData {
|
||||
validator_index: validator.get_index(),
|
||||
fee_recipient: self
|
||||
.get_fee_recipient_defaulting(validator.get_suggested_fee_recipient()),
|
||||
gas_limit: self.get_gas_limit_defaulting(validator.get_gas_limit()),
|
||||
builder_proposals: self
|
||||
.get_builder_proposals_defaulting(validator.get_builder_proposals()),
|
||||
})
|
||||
}
|
||||
|
||||
/// Attempts to resolve the pubkey to a validator index.
|
||||
///
|
||||
/// It may return `None` if the `pubkey` is:
|
||||
@@ -366,9 +399,12 @@ impl<T: SlotClock + 'static, E: EthSpec> ValidatorStore<T, E> {
|
||||
pub fn get_fee_recipient(&self, validator_pubkey: &PublicKeyBytes) -> Option<Address> {
|
||||
// If there is a `suggested_fee_recipient` in the validator definitions yaml
|
||||
// file, use that value.
|
||||
self.suggested_fee_recipient(validator_pubkey)
|
||||
// If there's nothing in the file, try the process-level default value.
|
||||
.or(self.fee_recipient_process)
|
||||
self.get_fee_recipient_defaulting(self.suggested_fee_recipient(validator_pubkey))
|
||||
}
|
||||
|
||||
pub fn get_fee_recipient_defaulting(&self, fee_recipient: Option<Address>) -> Option<Address> {
|
||||
// If there's nothing in the file, try the process-level default value.
|
||||
fee_recipient.or(self.fee_recipient_process)
|
||||
}
|
||||
|
||||
/// Returns the suggested_fee_recipient from `validator_definitions.yml` if any.
|
||||
@@ -379,6 +415,45 @@ impl<T: SlotClock + 'static, E: EthSpec> ValidatorStore<T, E> {
|
||||
.suggested_fee_recipient(validator_pubkey)
|
||||
}
|
||||
|
||||
/// Returns the gas limit for the given public key. The priority order for fetching
|
||||
/// the gas limit is:
|
||||
///
|
||||
/// 1. validator_definitions.yml
|
||||
/// 2. process level gas limit
|
||||
/// 3. `DEFAULT_GAS_LIMIT`
|
||||
pub fn get_gas_limit(&self, validator_pubkey: &PublicKeyBytes) -> u64 {
|
||||
self.get_gas_limit_defaulting(self.validators.read().gas_limit(validator_pubkey))
|
||||
}
|
||||
|
||||
fn get_gas_limit_defaulting(&self, gas_limit: Option<u64>) -> u64 {
|
||||
// If there is a `gas_limit` in the validator definitions yaml
|
||||
// file, use that value.
|
||||
gas_limit
|
||||
// If there's nothing in the file, try the process-level default value.
|
||||
.or(self.gas_limit)
|
||||
// If there's no process-level default, use the `DEFAULT_GAS_LIMIT`.
|
||||
.unwrap_or(DEFAULT_GAS_LIMIT)
|
||||
}
|
||||
|
||||
/// Returns a `bool` for the given public key that denotes whther this validator should use the
|
||||
/// builder API. The priority order for fetching this value is:
|
||||
///
|
||||
/// 1. validator_definitions.yml
|
||||
/// 2. process level flag
|
||||
pub fn get_builder_proposals(&self, validator_pubkey: &PublicKeyBytes) -> bool {
|
||||
// If there is a `suggested_fee_recipient` in the validator definitions yaml
|
||||
// file, use that value.
|
||||
self.get_builder_proposals_defaulting(
|
||||
self.validators.read().builder_proposals(validator_pubkey),
|
||||
)
|
||||
}
|
||||
|
||||
fn get_builder_proposals_defaulting(&self, builder_proposals: Option<bool>) -> bool {
|
||||
builder_proposals
|
||||
// If there's nothing in the file, try the process-level default value.
|
||||
.unwrap_or(self.builder_proposals)
|
||||
}
|
||||
|
||||
pub async fn sign_block<Payload: ExecPayload<E>>(
|
||||
&self,
|
||||
validator_pubkey: PublicKeyBytes,
|
||||
|
||||
Reference in New Issue
Block a user