mirror of
https://github.com/sigp/lighthouse.git
synced 2026-03-15 19:02:42 +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:
@@ -140,6 +140,8 @@ pub async fn create_validators_mnemonic<P: AsRef<Path>, T: 'static + SlotClock,
|
||||
request.enable,
|
||||
request.graffiti.clone(),
|
||||
request.suggested_fee_recipient,
|
||||
request.gas_limit,
|
||||
request.builder_proposals,
|
||||
)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
@@ -154,6 +156,8 @@ pub async fn create_validators_mnemonic<P: AsRef<Path>, T: 'static + SlotClock,
|
||||
description: request.description.clone(),
|
||||
graffiti: request.graffiti.clone(),
|
||||
suggested_fee_recipient: request.suggested_fee_recipient,
|
||||
gas_limit: request.gas_limit,
|
||||
builder_proposals: request.builder_proposals,
|
||||
voting_pubkey,
|
||||
eth1_deposit_tx_data: eth2_serde_utils::hex::encode(ð1_deposit_data.rlp),
|
||||
deposit_gwei: request.deposit_gwei,
|
||||
|
||||
@@ -205,6 +205,8 @@ fn import_single_keystore<T: SlotClock + 'static, E: EthSpec>(
|
||||
true,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
))
|
||||
.map_err(|e| format!("failed to initialize validator: {:?}", e))?;
|
||||
|
||||
|
||||
@@ -413,6 +413,8 @@ pub fn serve<T: 'static + SlotClock + Clone, E: EthSpec>(
|
||||
let voting_password = body.password.clone();
|
||||
let graffiti = body.graffiti.clone();
|
||||
let suggested_fee_recipient = body.suggested_fee_recipient;
|
||||
let gas_limit = body.gas_limit;
|
||||
let builder_proposals = body.builder_proposals;
|
||||
|
||||
let validator_def = {
|
||||
if let Some(handle) = task_executor.handle() {
|
||||
@@ -423,6 +425,8 @@ pub fn serve<T: 'static + SlotClock + Clone, E: EthSpec>(
|
||||
body.enable,
|
||||
graffiti,
|
||||
suggested_fee_recipient,
|
||||
gas_limit,
|
||||
builder_proposals,
|
||||
))
|
||||
.map_err(|e| {
|
||||
warp_utils::reject::custom_server_error(format!(
|
||||
@@ -469,6 +473,8 @@ pub fn serve<T: 'static + SlotClock + Clone, E: EthSpec>(
|
||||
voting_public_key: web3signer.voting_public_key,
|
||||
graffiti: web3signer.graffiti,
|
||||
suggested_fee_recipient: web3signer.suggested_fee_recipient,
|
||||
gas_limit: web3signer.gas_limit,
|
||||
builder_proposals: web3signer.builder_proposals,
|
||||
description: web3signer.description,
|
||||
signing_definition: SigningDefinition::Web3Signer(
|
||||
Web3SignerDefinition {
|
||||
@@ -515,18 +521,32 @@ pub fn serve<T: 'static + SlotClock + Clone, E: EthSpec>(
|
||||
let initialized_validators_rw_lock = validator_store.initialized_validators();
|
||||
let mut initialized_validators = initialized_validators_rw_lock.write();
|
||||
|
||||
match initialized_validators.is_enabled(&validator_pubkey) {
|
||||
None => Err(warp_utils::reject::custom_not_found(format!(
|
||||
match (
|
||||
initialized_validators.is_enabled(&validator_pubkey),
|
||||
initialized_validators.validator(&validator_pubkey.compress()),
|
||||
) {
|
||||
(None, _) => Err(warp_utils::reject::custom_not_found(format!(
|
||||
"no validator for {:?}",
|
||||
validator_pubkey
|
||||
))),
|
||||
Some(enabled) if enabled == body.enabled => Ok(()),
|
||||
Some(_) => {
|
||||
(Some(is_enabled), Some(initialized_validator))
|
||||
if Some(is_enabled) == body.enabled
|
||||
&& initialized_validator.get_gas_limit() == body.gas_limit
|
||||
&& initialized_validator.get_builder_proposals()
|
||||
== body.builder_proposals =>
|
||||
{
|
||||
Ok(())
|
||||
}
|
||||
(Some(_), _) => {
|
||||
if let Some(handle) = task_executor.handle() {
|
||||
handle
|
||||
.block_on(
|
||||
initialized_validators
|
||||
.set_validator_status(&validator_pubkey, body.enabled),
|
||||
initialized_validators.set_validator_definition_fields(
|
||||
&validator_pubkey,
|
||||
body.enabled,
|
||||
body.gas_limit,
|
||||
body.builder_proposals,
|
||||
),
|
||||
)
|
||||
.map_err(|e| {
|
||||
warp_utils::reject::custom_server_error(format!(
|
||||
|
||||
@@ -123,6 +123,8 @@ fn import_single_remotekey<T: SlotClock + 'static, E: EthSpec>(
|
||||
voting_public_key: pubkey,
|
||||
graffiti: None,
|
||||
suggested_fee_recipient: None,
|
||||
gas_limit: None,
|
||||
builder_proposals: None,
|
||||
description: String::from("Added by remotekey API"),
|
||||
signing_definition: SigningDefinition::Web3Signer(Web3SignerDefinition {
|
||||
url,
|
||||
|
||||
@@ -83,6 +83,7 @@ impl ApiTester {
|
||||
let mut config = Config::default();
|
||||
config.validator_dir = validator_dir.path().into();
|
||||
config.secrets_dir = secrets_dir.path().into();
|
||||
config.fee_recipient = Some(TEST_DEFAULT_FEE_RECIPIENT);
|
||||
|
||||
let spec = E::default_spec();
|
||||
|
||||
@@ -103,7 +104,7 @@ impl ApiTester {
|
||||
spec,
|
||||
Some(Arc::new(DoppelgangerService::new(log.clone()))),
|
||||
slot_clock,
|
||||
Some(TEST_DEFAULT_FEE_RECIPIENT),
|
||||
&config,
|
||||
executor.clone(),
|
||||
log.clone(),
|
||||
));
|
||||
@@ -270,6 +271,8 @@ impl ApiTester {
|
||||
description: format!("boi #{}", i),
|
||||
graffiti: None,
|
||||
suggested_fee_recipient: None,
|
||||
gas_limit: None,
|
||||
builder_proposals: None,
|
||||
deposit_gwei: E::default_spec().max_effective_balance,
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
@@ -401,6 +404,8 @@ impl ApiTester {
|
||||
keystore,
|
||||
graffiti: None,
|
||||
suggested_fee_recipient: None,
|
||||
gas_limit: None,
|
||||
builder_proposals: None,
|
||||
};
|
||||
|
||||
self.client
|
||||
@@ -419,6 +424,8 @@ impl ApiTester {
|
||||
keystore,
|
||||
graffiti: None,
|
||||
suggested_fee_recipient: None,
|
||||
gas_limit: None,
|
||||
builder_proposals: None,
|
||||
};
|
||||
|
||||
let response = self
|
||||
@@ -455,6 +462,8 @@ impl ApiTester {
|
||||
description: format!("{}", i),
|
||||
graffiti: None,
|
||||
suggested_fee_recipient: None,
|
||||
gas_limit: None,
|
||||
builder_proposals: None,
|
||||
voting_public_key: kp.pk,
|
||||
url: format!("http://signer_{}.com/", i),
|
||||
root_certificate_path: None,
|
||||
@@ -484,7 +493,7 @@ impl ApiTester {
|
||||
let validator = &self.client.get_lighthouse_validators().await.unwrap().data[index];
|
||||
|
||||
self.client
|
||||
.patch_lighthouse_validators(&validator.voting_pubkey, enabled)
|
||||
.patch_lighthouse_validators(&validator.voting_pubkey, Some(enabled), None, None)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@@ -521,6 +530,56 @@ impl ApiTester {
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
pub async fn set_gas_limit(self, index: usize, gas_limit: u64) -> Self {
|
||||
let validator = &self.client.get_lighthouse_validators().await.unwrap().data[index];
|
||||
|
||||
self.client
|
||||
.patch_lighthouse_validators(&validator.voting_pubkey, None, Some(gas_limit), None)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
pub async fn assert_gas_limit(self, index: usize, gas_limit: u64) -> Self {
|
||||
let validator = &self.client.get_lighthouse_validators().await.unwrap().data[index];
|
||||
|
||||
assert_eq!(
|
||||
self.validator_store.get_gas_limit(&validator.voting_pubkey),
|
||||
gas_limit
|
||||
);
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
pub async fn set_builder_proposals(self, index: usize, builder_proposals: bool) -> Self {
|
||||
let validator = &self.client.get_lighthouse_validators().await.unwrap().data[index];
|
||||
|
||||
self.client
|
||||
.patch_lighthouse_validators(
|
||||
&validator.voting_pubkey,
|
||||
None,
|
||||
None,
|
||||
Some(builder_proposals),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
pub async fn assert_builder_proposals(self, index: usize, builder_proposals: bool) -> Self {
|
||||
let validator = &self.client.get_lighthouse_validators().await.unwrap().data[index];
|
||||
|
||||
assert_eq!(
|
||||
self.validator_store
|
||||
.get_builder_proposals(&validator.voting_pubkey),
|
||||
builder_proposals
|
||||
);
|
||||
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
struct HdValidatorScenario {
|
||||
@@ -583,6 +642,8 @@ fn routes_with_invalid_auth() {
|
||||
description: <_>::default(),
|
||||
graffiti: <_>::default(),
|
||||
suggested_fee_recipient: <_>::default(),
|
||||
gas_limit: <_>::default(),
|
||||
builder_proposals: <_>::default(),
|
||||
deposit_gwei: <_>::default(),
|
||||
}])
|
||||
.await
|
||||
@@ -612,13 +673,15 @@ fn routes_with_invalid_auth() {
|
||||
keystore,
|
||||
graffiti: <_>::default(),
|
||||
suggested_fee_recipient: <_>::default(),
|
||||
gas_limit: <_>::default(),
|
||||
builder_proposals: <_>::default(),
|
||||
})
|
||||
.await
|
||||
})
|
||||
.await
|
||||
.test_with_invalid_auth(|client| async move {
|
||||
client
|
||||
.patch_lighthouse_validators(&PublicKeyBytes::empty(), false)
|
||||
.patch_lighthouse_validators(&PublicKeyBytes::empty(), Some(false), None, None)
|
||||
.await
|
||||
})
|
||||
.await
|
||||
@@ -735,6 +798,74 @@ fn validator_enabling() {
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn validator_gas_limit() {
|
||||
let runtime = build_runtime();
|
||||
let weak_runtime = Arc::downgrade(&runtime);
|
||||
runtime.block_on(async {
|
||||
ApiTester::new(weak_runtime)
|
||||
.await
|
||||
.create_hd_validators(HdValidatorScenario {
|
||||
count: 2,
|
||||
specify_mnemonic: false,
|
||||
key_derivation_path_offset: 0,
|
||||
disabled: vec![],
|
||||
})
|
||||
.await
|
||||
.assert_enabled_validators_count(2)
|
||||
.assert_validators_count(2)
|
||||
.set_gas_limit(0, 500)
|
||||
.await
|
||||
.assert_gas_limit(0, 500)
|
||||
.await
|
||||
// Update gas limit while validator is disabled.
|
||||
.set_validator_enabled(0, false)
|
||||
.await
|
||||
.assert_enabled_validators_count(1)
|
||||
.assert_validators_count(2)
|
||||
.set_gas_limit(0, 1000)
|
||||
.await
|
||||
.set_validator_enabled(0, true)
|
||||
.await
|
||||
.assert_enabled_validators_count(2)
|
||||
.assert_gas_limit(0, 1000)
|
||||
.await
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn validator_builder_proposals() {
|
||||
let runtime = build_runtime();
|
||||
let weak_runtime = Arc::downgrade(&runtime);
|
||||
runtime.block_on(async {
|
||||
ApiTester::new(weak_runtime)
|
||||
.await
|
||||
.create_hd_validators(HdValidatorScenario {
|
||||
count: 2,
|
||||
specify_mnemonic: false,
|
||||
key_derivation_path_offset: 0,
|
||||
disabled: vec![],
|
||||
})
|
||||
.await
|
||||
.assert_enabled_validators_count(2)
|
||||
.assert_validators_count(2)
|
||||
.set_builder_proposals(0, true)
|
||||
.await
|
||||
// Test setting builder proposals while the validator is disabled
|
||||
.set_validator_enabled(0, false)
|
||||
.await
|
||||
.assert_enabled_validators_count(1)
|
||||
.assert_validators_count(2)
|
||||
.set_builder_proposals(0, false)
|
||||
.await
|
||||
.set_validator_enabled(0, true)
|
||||
.await
|
||||
.assert_enabled_validators_count(2)
|
||||
.assert_builder_proposals(0, false)
|
||||
.await
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keystore_validator_creation() {
|
||||
let runtime = build_runtime();
|
||||
|
||||
@@ -39,6 +39,8 @@ fn web3signer_validator_with_pubkey(pubkey: PublicKey) -> Web3SignerValidatorReq
|
||||
description: "".into(),
|
||||
graffiti: None,
|
||||
suggested_fee_recipient: None,
|
||||
gas_limit: None,
|
||||
builder_proposals: None,
|
||||
voting_public_key: pubkey,
|
||||
url: web3_signer_url(),
|
||||
root_certificate_path: None,
|
||||
@@ -465,7 +467,7 @@ fn import_and_delete_conflicting_web3_signer_keystores() {
|
||||
for pubkey in &pubkeys {
|
||||
tester
|
||||
.client
|
||||
.patch_lighthouse_validators(pubkey, false)
|
||||
.patch_lighthouse_validators(pubkey, Some(false), None, None)
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user