mirror of
https://github.com/sigp/lighthouse.git
synced 2026-05-30 04:37:13 +00:00
Expose additional builder booster related flags in the vc (#5086)
* expose builder booster flags in vc, enable options in validator endpoints, update tests * resolve failing test * fix issues related to CreateConfig and MoveConfig * remove unneeded val, change how boost factor flag logic in the vc, add some additional documentation * fix typos * fix typos * assume builder-proosals flag if one of other two vc builder flags are present * fmt * typo * typo * Fix CLI help text * Prioritise per validator builder boost configurations over CLI flags. * Add http test for builder boost factor with process defaults. * Fix issue with PATCH request * Add prefer builder proposals * Add more builder boost factor tests. --------- Co-authored-by: Mac L <mjladson@pm.me> Co-authored-by: Jimmy Chen <jchen.tc@gmail.com> Co-authored-by: Paul Hauner <paul@paulhauner.com>
This commit is contained in:
@@ -325,14 +325,7 @@ impl<T: SlotClock + 'static, E: EthSpec> BlockService<T, E> {
|
||||
|
||||
if self.validator_store.produce_block_v3() {
|
||||
for validator_pubkey in proposers {
|
||||
let builder_proposals = self
|
||||
.validator_store
|
||||
.get_builder_proposals(&validator_pubkey);
|
||||
// Translate `builder_proposals` to a boost factor. Builder proposals set to `true`
|
||||
// requires no boost factor, it just means "use a builder proposal if the BN returns
|
||||
// one". On the contrary, `builder_proposals: false` indicates a preference for
|
||||
// local payloads, so we set the builder boost factor to 0.
|
||||
let builder_boost_factor = if !builder_proposals { Some(0) } else { None };
|
||||
let builder_boost_factor = self.get_builder_boost_factor(&validator_pubkey);
|
||||
let service = self.clone();
|
||||
let log = log.clone();
|
||||
self.inner.context.executor.spawn(
|
||||
@@ -853,6 +846,36 @@ impl<T: SlotClock + 'static, E: EthSpec> BlockService<T, E> {
|
||||
|
||||
Ok::<_, BlockError>(unsigned_block)
|
||||
}
|
||||
|
||||
/// Returns the builder boost factor of the given public key.
|
||||
/// The priority order for fetching this value is:
|
||||
///
|
||||
/// 1. validator_definitions.yml
|
||||
/// 2. process level flag
|
||||
fn get_builder_boost_factor(&self, validator_pubkey: &PublicKeyBytes) -> Option<u64> {
|
||||
// Apply per validator configuration first.
|
||||
let validator_builder_boost_factor = self
|
||||
.validator_store
|
||||
.determine_validator_builder_boost_factor(validator_pubkey);
|
||||
|
||||
// Fallback to process-wide configuration if needed.
|
||||
let maybe_builder_boost_factor = validator_builder_boost_factor.or_else(|| {
|
||||
self.validator_store
|
||||
.determine_default_builder_boost_factor()
|
||||
});
|
||||
|
||||
if let Some(builder_boost_factor) = maybe_builder_boost_factor {
|
||||
// if builder boost factor is set to 100 it should be treated
|
||||
// as None to prevent unnecessary calculations that could
|
||||
// lead to loss of information.
|
||||
if builder_boost_factor == 100 {
|
||||
return None;
|
||||
}
|
||||
return Some(builder_boost_factor);
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub enum UnsignedBlock<E: EthSpec> {
|
||||
|
||||
@@ -349,4 +349,22 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> {
|
||||
.default_value("500")
|
||||
.takes_value(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("builder-boost-factor")
|
||||
.long("builder-boost-factor")
|
||||
.value_name("UINT64")
|
||||
.help("Defines the boost factor, \
|
||||
a percentage multiplier to apply to the builder's payload value \
|
||||
when choosing between a builder payload header and payload from \
|
||||
the local execution node.")
|
||||
.conflicts_with("prefer-builder-proposals")
|
||||
.takes_value(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("prefer-builder-proposals")
|
||||
.long("prefer-builder-proposals")
|
||||
.help("If this flag is set, Lighthouse will always prefer blocks \
|
||||
constructed by builders, regardless of payload value.")
|
||||
.takes_value(false),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -77,6 +77,10 @@ pub struct Config {
|
||||
pub validator_registration_batch_size: usize,
|
||||
/// Enables block production via the block v3 endpoint. This configuration option can be removed post deneb.
|
||||
pub produce_block_v3: bool,
|
||||
/// Specifies the boost factor, a percentage multiplier to apply to the builder's payload value.
|
||||
pub builder_boost_factor: Option<u64>,
|
||||
/// If true, Lighthouse will prefer builder proposals, if available.
|
||||
pub prefer_builder_proposals: bool,
|
||||
}
|
||||
|
||||
impl Default for Config {
|
||||
@@ -118,6 +122,8 @@ impl Default for Config {
|
||||
enable_latency_measurement_service: true,
|
||||
validator_registration_batch_size: 500,
|
||||
produce_block_v3: false,
|
||||
builder_boost_factor: None,
|
||||
prefer_builder_proposals: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -346,6 +352,10 @@ impl Config {
|
||||
config.produce_block_v3 = true;
|
||||
}
|
||||
|
||||
if cli_args.is_present("prefer-builder-proposals") {
|
||||
config.prefer_builder_proposals = true;
|
||||
}
|
||||
|
||||
config.gas_limit = cli_args
|
||||
.value_of("gas-limit")
|
||||
.map(|gas_limit| {
|
||||
@@ -365,6 +375,8 @@ impl Config {
|
||||
);
|
||||
}
|
||||
|
||||
config.builder_boost_factor = parse_optional(cli_args, "builder-boost-factor")?;
|
||||
|
||||
config.enable_latency_measurement_service =
|
||||
parse_optional(cli_args, "latency-measurement-service")?.unwrap_or(true);
|
||||
|
||||
|
||||
@@ -148,6 +148,8 @@ pub async fn create_validators_mnemonic<P: AsRef<Path>, T: 'static + SlotClock,
|
||||
request.suggested_fee_recipient,
|
||||
request.gas_limit,
|
||||
request.builder_proposals,
|
||||
request.builder_boost_factor,
|
||||
request.prefer_builder_proposals,
|
||||
)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
|
||||
@@ -224,6 +224,8 @@ fn import_single_keystore<T: SlotClock + 'static, E: EthSpec>(
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
))
|
||||
.map_err(|e| format!("failed to initialize validator: {:?}", e))?;
|
||||
|
||||
|
||||
@@ -565,6 +565,8 @@ pub fn serve<T: 'static + SlotClock + Clone, E: EthSpec>(
|
||||
let suggested_fee_recipient = body.suggested_fee_recipient;
|
||||
let gas_limit = body.gas_limit;
|
||||
let builder_proposals = body.builder_proposals;
|
||||
let builder_boost_factor = body.builder_boost_factor;
|
||||
let prefer_builder_proposals = body.prefer_builder_proposals;
|
||||
|
||||
let validator_def = {
|
||||
if let Some(handle) = task_executor.handle() {
|
||||
@@ -577,6 +579,8 @@ pub fn serve<T: 'static + SlotClock + Clone, E: EthSpec>(
|
||||
suggested_fee_recipient,
|
||||
gas_limit,
|
||||
builder_proposals,
|
||||
builder_boost_factor,
|
||||
prefer_builder_proposals,
|
||||
))
|
||||
.map_err(|e| {
|
||||
warp_utils::reject::custom_server_error(format!(
|
||||
@@ -625,6 +629,8 @@ pub fn serve<T: 'static + SlotClock + Clone, E: EthSpec>(
|
||||
suggested_fee_recipient: web3signer.suggested_fee_recipient,
|
||||
gas_limit: web3signer.gas_limit,
|
||||
builder_proposals: web3signer.builder_proposals,
|
||||
builder_boost_factor: web3signer.builder_boost_factor,
|
||||
prefer_builder_proposals: web3signer.prefer_builder_proposals,
|
||||
description: web3signer.description,
|
||||
signing_definition: SigningDefinition::Web3Signer(
|
||||
Web3SignerDefinition {
|
||||
@@ -691,8 +697,12 @@ pub fn serve<T: 'static + SlotClock + Clone, E: EthSpec>(
|
||||
(Some(is_enabled), Some(initialized_validator))
|
||||
if Some(is_enabled) == body.enabled
|
||||
&& initialized_validator.get_gas_limit() == body.gas_limit
|
||||
&& initialized_validator.get_builder_boost_factor()
|
||||
== body.builder_boost_factor
|
||||
&& initialized_validator.get_builder_proposals()
|
||||
== body.builder_proposals
|
||||
&& initialized_validator.get_prefer_builder_proposals()
|
||||
== body.prefer_builder_proposals
|
||||
&& initialized_validator.get_graffiti() == maybe_graffiti =>
|
||||
{
|
||||
Ok(())
|
||||
@@ -706,6 +716,8 @@ pub fn serve<T: 'static + SlotClock + Clone, E: EthSpec>(
|
||||
body.enabled,
|
||||
body.gas_limit,
|
||||
body.builder_proposals,
|
||||
body.builder_boost_factor,
|
||||
body.prefer_builder_proposals,
|
||||
body.graffiti,
|
||||
),
|
||||
)
|
||||
|
||||
@@ -125,6 +125,8 @@ fn import_single_remotekey<T: SlotClock + 'static, E: EthSpec>(
|
||||
suggested_fee_recipient: None,
|
||||
gas_limit: None,
|
||||
builder_proposals: None,
|
||||
builder_boost_factor: None,
|
||||
prefer_builder_proposals: None,
|
||||
description: String::from("Added by remotekey API"),
|
||||
signing_definition: SigningDefinition::Web3Signer(Web3SignerDefinition {
|
||||
url,
|
||||
|
||||
@@ -315,6 +315,8 @@ impl ApiTester {
|
||||
suggested_fee_recipient: None,
|
||||
gas_limit: None,
|
||||
builder_proposals: None,
|
||||
builder_boost_factor: None,
|
||||
prefer_builder_proposals: None,
|
||||
deposit_gwei: E::default_spec().max_effective_balance,
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
@@ -447,6 +449,8 @@ impl ApiTester {
|
||||
suggested_fee_recipient: None,
|
||||
gas_limit: None,
|
||||
builder_proposals: None,
|
||||
builder_boost_factor: None,
|
||||
prefer_builder_proposals: None,
|
||||
};
|
||||
|
||||
self.client
|
||||
@@ -467,6 +471,8 @@ impl ApiTester {
|
||||
suggested_fee_recipient: None,
|
||||
gas_limit: None,
|
||||
builder_proposals: None,
|
||||
builder_boost_factor: None,
|
||||
prefer_builder_proposals: None,
|
||||
};
|
||||
|
||||
let response = self
|
||||
@@ -511,6 +517,8 @@ impl ApiTester {
|
||||
request_timeout_ms: None,
|
||||
client_identity_path: None,
|
||||
client_identity_password: None,
|
||||
builder_boost_factor: None,
|
||||
prefer_builder_proposals: None,
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
@@ -534,7 +542,15 @@ impl ApiTester {
|
||||
let validator = &self.client.get_lighthouse_validators().await.unwrap().data[index];
|
||||
|
||||
self.client
|
||||
.patch_lighthouse_validators(&validator.voting_pubkey, Some(enabled), None, None, None)
|
||||
.patch_lighthouse_validators(
|
||||
&validator.voting_pubkey,
|
||||
Some(enabled),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@@ -582,6 +598,8 @@ impl ApiTester {
|
||||
Some(gas_limit),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
@@ -610,6 +628,8 @@ impl ApiTester {
|
||||
None,
|
||||
Some(builder_proposals),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@@ -52,6 +52,12 @@ struct ApiTester {
|
||||
|
||||
impl ApiTester {
|
||||
pub async fn new() -> Self {
|
||||
let mut config = Config::default();
|
||||
config.fee_recipient = Some(TEST_DEFAULT_FEE_RECIPIENT);
|
||||
Self::new_with_config(config).await
|
||||
}
|
||||
|
||||
pub async fn new_with_config(mut config: Config) -> Self {
|
||||
let log = test_logger();
|
||||
|
||||
let validator_dir = tempdir().unwrap();
|
||||
@@ -70,10 +76,8 @@ impl ApiTester {
|
||||
let api_secret = ApiSecret::create_or_open(validator_dir.path()).unwrap();
|
||||
let api_pubkey = api_secret.api_token();
|
||||
|
||||
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();
|
||||
|
||||
@@ -271,6 +275,8 @@ impl ApiTester {
|
||||
suggested_fee_recipient: None,
|
||||
gas_limit: None,
|
||||
builder_proposals: None,
|
||||
builder_boost_factor: None,
|
||||
prefer_builder_proposals: None,
|
||||
deposit_gwei: E::default_spec().max_effective_balance,
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
@@ -404,6 +410,8 @@ impl ApiTester {
|
||||
suggested_fee_recipient: None,
|
||||
gas_limit: None,
|
||||
builder_proposals: None,
|
||||
builder_boost_factor: None,
|
||||
prefer_builder_proposals: None,
|
||||
};
|
||||
|
||||
self.client
|
||||
@@ -424,6 +432,8 @@ impl ApiTester {
|
||||
suggested_fee_recipient: None,
|
||||
gas_limit: None,
|
||||
builder_proposals: None,
|
||||
builder_boost_factor: None,
|
||||
prefer_builder_proposals: None,
|
||||
};
|
||||
|
||||
let response = self
|
||||
@@ -462,6 +472,8 @@ impl ApiTester {
|
||||
suggested_fee_recipient: None,
|
||||
gas_limit: None,
|
||||
builder_proposals: None,
|
||||
builder_boost_factor: None,
|
||||
prefer_builder_proposals: None,
|
||||
voting_public_key: kp.pk,
|
||||
url: format!("http://signer_{}.com/", i),
|
||||
root_certificate_path: None,
|
||||
@@ -518,7 +530,15 @@ impl ApiTester {
|
||||
let validator = &self.client.get_lighthouse_validators().await.unwrap().data[index];
|
||||
|
||||
self.client
|
||||
.patch_lighthouse_validators(&validator.voting_pubkey, Some(enabled), None, None, None)
|
||||
.patch_lighthouse_validators(
|
||||
&validator.voting_pubkey,
|
||||
Some(enabled),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@@ -566,6 +586,8 @@ impl ApiTester {
|
||||
Some(gas_limit),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
@@ -594,6 +616,50 @@ impl ApiTester {
|
||||
None,
|
||||
Some(builder_proposals),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
pub async fn set_builder_boost_factor(self, index: usize, builder_boost_factor: u64) -> Self {
|
||||
let validator = &self.client.get_lighthouse_validators().await.unwrap().data[index];
|
||||
|
||||
self.client
|
||||
.patch_lighthouse_validators(
|
||||
&validator.voting_pubkey,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
Some(builder_boost_factor),
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
pub async fn set_prefer_builder_proposals(
|
||||
self,
|
||||
index: usize,
|
||||
prefer_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,
|
||||
None,
|
||||
None,
|
||||
Some(prefer_builder_proposals),
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
@@ -613,6 +679,64 @@ impl ApiTester {
|
||||
self
|
||||
}
|
||||
|
||||
pub async fn assert_builder_boost_factor(
|
||||
self,
|
||||
index: usize,
|
||||
builder_boost_factor: Option<u64>,
|
||||
) -> Self {
|
||||
let validator = &self.client.get_lighthouse_validators().await.unwrap().data[index];
|
||||
|
||||
assert_eq!(
|
||||
self.validator_store
|
||||
.get_builder_boost_factor(&validator.voting_pubkey),
|
||||
builder_boost_factor
|
||||
);
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
pub async fn assert_validator_derived_builder_boost_factor(
|
||||
self,
|
||||
index: usize,
|
||||
builder_boost_factor: Option<u64>,
|
||||
) -> Self {
|
||||
let validator = &self.client.get_lighthouse_validators().await.unwrap().data[index];
|
||||
|
||||
assert_eq!(
|
||||
self.validator_store
|
||||
.determine_validator_builder_boost_factor(&validator.voting_pubkey),
|
||||
builder_boost_factor
|
||||
);
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
pub fn assert_default_builder_boost_factor(self, builder_boost_factor: Option<u64>) -> Self {
|
||||
assert_eq!(
|
||||
self.validator_store
|
||||
.determine_default_builder_boost_factor(),
|
||||
builder_boost_factor
|
||||
);
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
pub async fn assert_prefer_builder_proposals(
|
||||
self,
|
||||
index: usize,
|
||||
prefer_builder_proposals: bool,
|
||||
) -> Self {
|
||||
let validator = &self.client.get_lighthouse_validators().await.unwrap().data[index];
|
||||
|
||||
assert_eq!(
|
||||
self.validator_store
|
||||
.get_prefer_builder_proposals(&validator.voting_pubkey),
|
||||
prefer_builder_proposals
|
||||
);
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
pub async fn set_graffiti(self, index: usize, graffiti: &str) -> Self {
|
||||
let validator = &self.client.get_lighthouse_validators().await.unwrap().data[index];
|
||||
let graffiti_str = GraffitiString::from_str(graffiti).unwrap();
|
||||
@@ -622,6 +746,8 @@ impl ApiTester {
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
Some(graffiti_str),
|
||||
)
|
||||
.await
|
||||
@@ -741,6 +867,8 @@ async fn routes_with_invalid_auth() {
|
||||
gas_limit: <_>::default(),
|
||||
builder_proposals: <_>::default(),
|
||||
deposit_gwei: <_>::default(),
|
||||
builder_boost_factor: <_>::default(),
|
||||
prefer_builder_proposals: <_>::default(),
|
||||
}])
|
||||
.await
|
||||
})
|
||||
@@ -771,6 +899,8 @@ async fn routes_with_invalid_auth() {
|
||||
suggested_fee_recipient: <_>::default(),
|
||||
gas_limit: <_>::default(),
|
||||
builder_proposals: <_>::default(),
|
||||
builder_boost_factor: <_>::default(),
|
||||
prefer_builder_proposals: <_>::default(),
|
||||
})
|
||||
.await
|
||||
})
|
||||
@@ -783,6 +913,8 @@ async fn routes_with_invalid_auth() {
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
})
|
||||
@@ -980,6 +1112,100 @@ async fn validator_builder_proposals() {
|
||||
.await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn validator_builder_boost_factor() {
|
||||
ApiTester::new()
|
||||
.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_boost_factor(0, 120)
|
||||
.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_boost_factor(0, 80)
|
||||
.await
|
||||
.set_validator_enabled(0, true)
|
||||
.await
|
||||
.assert_enabled_validators_count(2)
|
||||
.assert_builder_boost_factor(0, Some(80))
|
||||
.await;
|
||||
}
|
||||
|
||||
/// Verifies the builder boost factors translated from the `builder_proposals`,
|
||||
/// `prefer_builder_proposals` and `builder_boost_factor` values.
|
||||
#[tokio::test]
|
||||
async fn validator_derived_builder_boost_factor_with_process_defaults() {
|
||||
let config = Config {
|
||||
builder_proposals: true,
|
||||
prefer_builder_proposals: false,
|
||||
builder_boost_factor: Some(80),
|
||||
..Config::default()
|
||||
};
|
||||
ApiTester::new_with_config(config)
|
||||
.await
|
||||
.create_hd_validators(HdValidatorScenario {
|
||||
count: 3,
|
||||
specify_mnemonic: false,
|
||||
key_derivation_path_offset: 0,
|
||||
disabled: vec![],
|
||||
})
|
||||
.await
|
||||
.assert_default_builder_boost_factor(Some(80))
|
||||
.assert_validator_derived_builder_boost_factor(0, None)
|
||||
.await
|
||||
.set_builder_proposals(0, false)
|
||||
.await
|
||||
.assert_validator_derived_builder_boost_factor(0, Some(0))
|
||||
.await
|
||||
.set_builder_boost_factor(1, 120)
|
||||
.await
|
||||
.assert_validator_derived_builder_boost_factor(1, Some(120))
|
||||
.await
|
||||
.set_prefer_builder_proposals(2, true)
|
||||
.await
|
||||
.assert_validator_derived_builder_boost_factor(2, Some(u64::MAX))
|
||||
.await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn prefer_builder_proposals_validator() {
|
||||
ApiTester::new()
|
||||
.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_prefer_builder_proposals(0, false)
|
||||
.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_prefer_builder_proposals(0, true)
|
||||
.await
|
||||
.set_validator_enabled(0, true)
|
||||
.await
|
||||
.assert_enabled_validators_count(2)
|
||||
.assert_prefer_builder_proposals(0, true)
|
||||
.await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn validator_graffiti() {
|
||||
ApiTester::new()
|
||||
|
||||
@@ -43,6 +43,8 @@ fn web3signer_validator_with_pubkey(pubkey: PublicKey) -> Web3SignerValidatorReq
|
||||
suggested_fee_recipient: None,
|
||||
gas_limit: None,
|
||||
builder_proposals: None,
|
||||
builder_boost_factor: None,
|
||||
prefer_builder_proposals: None,
|
||||
voting_public_key: pubkey,
|
||||
url: web3_signer_url(),
|
||||
root_certificate_path: None,
|
||||
@@ -468,7 +470,7 @@ async fn import_and_delete_conflicting_web3_signer_keystores() {
|
||||
for pubkey in &pubkeys {
|
||||
tester
|
||||
.client
|
||||
.patch_lighthouse_validators(pubkey, Some(false), None, None, None)
|
||||
.patch_lighthouse_validators(pubkey, Some(false), None, None, None, None, None)
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
@@ -131,6 +131,8 @@ pub struct InitializedValidator {
|
||||
suggested_fee_recipient: Option<Address>,
|
||||
gas_limit: Option<u64>,
|
||||
builder_proposals: Option<bool>,
|
||||
builder_boost_factor: Option<u64>,
|
||||
prefer_builder_proposals: Option<bool>,
|
||||
/// The validators index in `state.validators`, to be updated by an external service.
|
||||
index: Option<u64>,
|
||||
}
|
||||
@@ -159,6 +161,14 @@ impl InitializedValidator {
|
||||
self.gas_limit
|
||||
}
|
||||
|
||||
pub fn get_builder_boost_factor(&self) -> Option<u64> {
|
||||
self.builder_boost_factor
|
||||
}
|
||||
|
||||
pub fn get_prefer_builder_proposals(&self) -> Option<bool> {
|
||||
self.prefer_builder_proposals
|
||||
}
|
||||
|
||||
pub fn get_builder_proposals(&self) -> Option<bool> {
|
||||
self.builder_proposals
|
||||
}
|
||||
@@ -335,6 +345,8 @@ impl InitializedValidator {
|
||||
suggested_fee_recipient: def.suggested_fee_recipient,
|
||||
gas_limit: def.gas_limit,
|
||||
builder_proposals: def.builder_proposals,
|
||||
builder_boost_factor: def.builder_boost_factor,
|
||||
prefer_builder_proposals: def.prefer_builder_proposals,
|
||||
index: None,
|
||||
})
|
||||
}
|
||||
@@ -815,6 +827,22 @@ impl InitializedValidators {
|
||||
.and_then(|v| v.builder_proposals)
|
||||
}
|
||||
|
||||
/// Returns the `builder_boost_factor` for a given public key specified in the
|
||||
/// `ValidatorDefinitions`.
|
||||
pub fn builder_boost_factor(&self, public_key: &PublicKeyBytes) -> Option<u64> {
|
||||
self.validators
|
||||
.get(public_key)
|
||||
.and_then(|v| v.builder_boost_factor)
|
||||
}
|
||||
|
||||
/// Returns the `prefer_builder_proposals` for a given public key specified in the
|
||||
/// `ValidatorDefinitions`.
|
||||
pub fn prefer_builder_proposals(&self, public_key: &PublicKeyBytes) -> Option<bool> {
|
||||
self.validators
|
||||
.get(public_key)
|
||||
.and_then(|v| v.prefer_builder_proposals)
|
||||
}
|
||||
|
||||
/// Returns an `Option` of a reference to an `InitializedValidator` for a given public key specified in the
|
||||
/// `ValidatorDefinitions`.
|
||||
pub fn validator(&self, public_key: &PublicKeyBytes) -> Option<&InitializedValidator> {
|
||||
@@ -835,12 +863,15 @@ impl InitializedValidators {
|
||||
/// or `InitializedValidator`. The same logic applies to `builder_proposals` and `graffiti`.
|
||||
///
|
||||
/// Saves the `ValidatorDefinitions` to file, even if no definitions were changed.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub async fn set_validator_definition_fields(
|
||||
&mut self,
|
||||
voting_public_key: &PublicKey,
|
||||
enabled: Option<bool>,
|
||||
gas_limit: Option<u64>,
|
||||
builder_proposals: Option<bool>,
|
||||
builder_boost_factor: Option<u64>,
|
||||
prefer_builder_proposals: Option<bool>,
|
||||
graffiti: Option<GraffitiString>,
|
||||
) -> Result<(), Error> {
|
||||
if let Some(def) = self
|
||||
@@ -862,6 +893,12 @@ impl InitializedValidators {
|
||||
if let Some(graffiti) = graffiti.clone() {
|
||||
def.graffiti = Some(graffiti);
|
||||
}
|
||||
if let Some(builder_boost_factor) = builder_boost_factor {
|
||||
def.builder_boost_factor = Some(builder_boost_factor);
|
||||
}
|
||||
if let Some(prefer_builder_proposals) = prefer_builder_proposals {
|
||||
def.prefer_builder_proposals = Some(prefer_builder_proposals);
|
||||
}
|
||||
}
|
||||
|
||||
self.update_validators().await?;
|
||||
@@ -880,6 +917,12 @@ impl InitializedValidators {
|
||||
if let Some(graffiti) = graffiti {
|
||||
val.graffiti = Some(graffiti.into());
|
||||
}
|
||||
if let Some(builder_boost_factor) = builder_boost_factor {
|
||||
val.builder_boost_factor = Some(builder_boost_factor);
|
||||
}
|
||||
if let Some(prefer_builder_proposals) = prefer_builder_proposals {
|
||||
val.prefer_builder_proposals = Some(prefer_builder_proposals);
|
||||
}
|
||||
}
|
||||
|
||||
self.definitions
|
||||
|
||||
@@ -98,6 +98,8 @@ pub struct ValidatorStore<T, E: EthSpec> {
|
||||
gas_limit: Option<u64>,
|
||||
builder_proposals: bool,
|
||||
produce_block_v3: bool,
|
||||
prefer_builder_proposals: bool,
|
||||
builder_boost_factor: Option<u64>,
|
||||
task_executor: TaskExecutor,
|
||||
_phantom: PhantomData<E>,
|
||||
}
|
||||
@@ -130,6 +132,8 @@ impl<T: SlotClock + 'static, E: EthSpec> ValidatorStore<T, E> {
|
||||
gas_limit: config.gas_limit,
|
||||
builder_proposals: config.builder_proposals,
|
||||
produce_block_v3: config.produce_block_v3,
|
||||
prefer_builder_proposals: config.prefer_builder_proposals,
|
||||
builder_boost_factor: config.builder_boost_factor,
|
||||
task_executor,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
@@ -178,6 +182,8 @@ impl<T: SlotClock + 'static, E: EthSpec> ValidatorStore<T, E> {
|
||||
suggested_fee_recipient: Option<Address>,
|
||||
gas_limit: Option<u64>,
|
||||
builder_proposals: Option<bool>,
|
||||
builder_boost_factor: Option<u64>,
|
||||
prefer_builder_proposals: Option<bool>,
|
||||
) -> Result<ValidatorDefinition, String> {
|
||||
let mut validator_def = ValidatorDefinition::new_keystore_with_password(
|
||||
voting_keystore_path,
|
||||
@@ -186,6 +192,8 @@ impl<T: SlotClock + 'static, E: EthSpec> ValidatorStore<T, E> {
|
||||
suggested_fee_recipient,
|
||||
gas_limit,
|
||||
builder_proposals,
|
||||
builder_boost_factor,
|
||||
prefer_builder_proposals,
|
||||
)
|
||||
.map_err(|e| format!("failed to create validator definitions: {:?}", e))?;
|
||||
|
||||
@@ -474,7 +482,7 @@ impl<T: SlotClock + 'static, E: EthSpec> ValidatorStore<T, E> {
|
||||
.unwrap_or(DEFAULT_GAS_LIMIT)
|
||||
}
|
||||
|
||||
/// Returns a `bool` for the given public key that denotes whther this validator should use the
|
||||
/// Returns a `bool` for the given public key that denotes whether this validator should use the
|
||||
/// builder API. The priority order for fetching this value is:
|
||||
///
|
||||
/// 1. validator_definitions.yml
|
||||
@@ -487,12 +495,91 @@ impl<T: SlotClock + 'static, E: EthSpec> ValidatorStore<T, E> {
|
||||
)
|
||||
}
|
||||
|
||||
/// Returns a `u64` for the given public key that denotes the builder boost factor. The priority order for fetching this value is:
|
||||
///
|
||||
/// 1. validator_definitions.yml
|
||||
/// 2. process level flag
|
||||
pub fn get_builder_boost_factor(&self, validator_pubkey: &PublicKeyBytes) -> Option<u64> {
|
||||
self.validators
|
||||
.read()
|
||||
.builder_boost_factor(validator_pubkey)
|
||||
.or(self.builder_boost_factor)
|
||||
}
|
||||
|
||||
/// Returns a `bool` for the given public key that denotes whether this validator should prefer a
|
||||
/// builder payload. The priority order for fetching this value is:
|
||||
///
|
||||
/// 1. validator_definitions.yml
|
||||
/// 2. process level flag
|
||||
pub fn get_prefer_builder_proposals(&self, validator_pubkey: &PublicKeyBytes) -> bool {
|
||||
self.validators
|
||||
.read()
|
||||
.prefer_builder_proposals(validator_pubkey)
|
||||
.unwrap_or(self.prefer_builder_proposals)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
/// Translate the per validator `builder_proposals`, `builder_boost_factor` and
|
||||
/// `prefer_builder_proposals` to a boost factor, if available.
|
||||
/// - If `prefer_builder_proposals` is true, set boost factor to `u64::MAX` to indicate a
|
||||
/// preference for builder payloads.
|
||||
/// - If `builder_boost_factor` is a value other than None, return its value as the boost factor.
|
||||
/// - If `builder_proposals` is set to false, set boost factor to 0 to indicate a preference for
|
||||
/// local payloads.
|
||||
/// - Else return `None` to indicate no preference between builder and local payloads.
|
||||
pub fn determine_validator_builder_boost_factor(
|
||||
&self,
|
||||
validator_pubkey: &PublicKeyBytes,
|
||||
) -> Option<u64> {
|
||||
let validator_prefer_builder_proposals = self
|
||||
.validators
|
||||
.read()
|
||||
.prefer_builder_proposals(validator_pubkey);
|
||||
|
||||
if matches!(validator_prefer_builder_proposals, Some(true)) {
|
||||
return Some(u64::MAX);
|
||||
}
|
||||
|
||||
self.validators
|
||||
.read()
|
||||
.builder_boost_factor(validator_pubkey)
|
||||
.or_else(|| {
|
||||
if matches!(
|
||||
self.validators.read().builder_proposals(validator_pubkey),
|
||||
Some(false)
|
||||
) {
|
||||
return Some(0);
|
||||
}
|
||||
None
|
||||
})
|
||||
}
|
||||
|
||||
/// Translate the process-wide `builder_proposals`, `builder_boost_factor` and
|
||||
/// `prefer_builder_proposals` configurations to a boost factor.
|
||||
/// - If `prefer_builder_proposals` is true, set boost factor to `u64::MAX` to indicate a
|
||||
/// preference for builder payloads.
|
||||
/// - If `builder_boost_factor` is a value other than None, return its value as the boost factor.
|
||||
/// - If `builder_proposals` is set to false, set boost factor to 0 to indicate a preference for
|
||||
/// local payloads.
|
||||
/// - Else return `None` to indicate no preference between builder and local payloads.
|
||||
pub fn determine_default_builder_boost_factor(&self) -> Option<u64> {
|
||||
if self.prefer_builder_proposals {
|
||||
return Some(u64::MAX);
|
||||
}
|
||||
self.builder_boost_factor.or({
|
||||
if self.builder_proposals {
|
||||
Some(0)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn sign_block<Payload: AbstractExecPayload<E>>(
|
||||
&self,
|
||||
validator_pubkey: PublicKeyBytes,
|
||||
|
||||
Reference in New Issue
Block a user