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:
parent
612eaf2d41
commit
f9e36c94ed
@ -284,6 +284,8 @@ pub fn cli_run(matches: &ArgMatches, validator_dir: PathBuf) -> Result<(), Strin
|
|||||||
suggested_fee_recipient,
|
suggested_fee_recipient,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
)
|
)
|
||||||
.map_err(|e| format!("Unable to create new validator definition: {:?}", e))?;
|
.map_err(|e| format!("Unable to create new validator definition: {:?}", e))?;
|
||||||
|
|
||||||
|
@ -427,7 +427,7 @@ Example Response Body
|
|||||||
|
|
||||||
## `PATCH /lighthouse/validators/:voting_pubkey`
|
## `PATCH /lighthouse/validators/:voting_pubkey`
|
||||||
|
|
||||||
Update some values for the validator with `voting_pubkey`. Possible fields: `enabled`, `gas_limit`, `builder_proposals`,
|
Update some values for the validator with `voting_pubkey`. Possible fields: `enabled`, `gas_limit`, `builder_proposals`, `builder_boost_factor`, `prefer_builder_proposals`
|
||||||
and `graffiti`. The following example updates a validator from `enabled: true` to `enabled: false`.
|
and `graffiti`. The following example updates a validator from `enabled: true` to `enabled: false`.
|
||||||
|
|
||||||
### HTTP Specification
|
### HTTP Specification
|
||||||
|
@ -31,6 +31,18 @@ blinded blocks, you should use the following flag:
|
|||||||
lighthouse vc --builder-proposals
|
lighthouse vc --builder-proposals
|
||||||
```
|
```
|
||||||
With the `--builder-proposals` flag, the validator client will ask for blinded blocks for all validators it manages.
|
With the `--builder-proposals` flag, the validator client will ask for blinded blocks for all validators it manages.
|
||||||
|
|
||||||
|
```
|
||||||
|
lighthouse vc --prefer-builder-proposals
|
||||||
|
```
|
||||||
|
With the `--prefer-builder-proposals` flag, the validator client will always prefer blinded blocks, regardless of the payload value, for all validators it manages.
|
||||||
|
|
||||||
|
```
|
||||||
|
lighthouse vc --builder-boost-factor <INTEGER>
|
||||||
|
```
|
||||||
|
With the `--builder-boost-factor` flag, a percentage multiplier is applied to the builder's payload value when choosing between a
|
||||||
|
builder payload header and payload from the paired execution node.
|
||||||
|
|
||||||
In order to configure whether a validator queries for blinded blocks check out [this section.](#validator-client-configuration)
|
In order to configure whether a validator queries for blinded blocks check out [this section.](#validator-client-configuration)
|
||||||
|
|
||||||
## Multiple builders
|
## Multiple builders
|
||||||
@ -46,9 +58,9 @@ relays, run one of the following services and configure lighthouse to use it wit
|
|||||||
In the validator client you can configure gas limit and fee recipient on a per-validator basis. If no gas limit is
|
In the validator client you can configure gas limit and fee recipient on a per-validator basis. If no gas limit is
|
||||||
configured, Lighthouse will use a default gas limit of 30,000,000, which is the current default value used in execution
|
configured, Lighthouse will use a default gas limit of 30,000,000, which is the current default value used in execution
|
||||||
engines. You can also enable or disable use of external builders on a per-validator basis rather than using
|
engines. You can also enable or disable use of external builders on a per-validator basis rather than using
|
||||||
`--builder-proposals`, which enables external builders for all validators. In order to manage these configurations
|
`--builder-proposals`, `--builder-boost-factor` or `--prefer-builder-proposals`, which apply builder related preferences for all validators.
|
||||||
per-validator, you can either make updates to the `validator_definitions.yml` file or you can use the HTTP requests
|
In order to manage these configurations per-validator, you can either make updates to the `validator_definitions.yml` file
|
||||||
described below.
|
or you can use the HTTP requests described below.
|
||||||
|
|
||||||
Both the gas limit and fee recipient will be passed along as suggestions to connected builders. If there is a discrepancy
|
Both the gas limit and fee recipient will be passed along as suggestions to connected builders. If there is a discrepancy
|
||||||
in either, it will *not* keep you from proposing a block with the builder. This is because the bounds on gas limit are
|
in either, it will *not* keep you from proposing a block with the builder. This is because the bounds on gas limit are
|
||||||
|
@ -56,6 +56,9 @@ FLAGS:
|
|||||||
machine. Note that logs can often contain sensitive information about your validator and so this flag should
|
machine. Note that logs can often contain sensitive information about your validator and so this flag should
|
||||||
be used with caution. For Windows users, the log file permissions will be inherited from the parent folder.
|
be used with caution. For Windows users, the log file permissions will be inherited from the parent folder.
|
||||||
--metrics Enable the Prometheus metrics HTTP server. Disabled by default.
|
--metrics Enable the Prometheus metrics HTTP server. Disabled by default.
|
||||||
|
--prefer-builder-proposals
|
||||||
|
If this flag is set, Lighthouse will always prefer blocks constructed by builders, regardless of payload
|
||||||
|
value.
|
||||||
--produce-block-v3
|
--produce-block-v3
|
||||||
Enable block production via the block v3 endpoint for this validator client. This should only be enabled
|
Enable block production via the block v3 endpoint for this validator client. This should only be enabled
|
||||||
when paired with a beacon node that has this endpoint implemented. This flag will be enabled by default in
|
when paired with a beacon node that has this endpoint implemented. This flag will be enabled by default in
|
||||||
@ -80,6 +83,9 @@ OPTIONS:
|
|||||||
Comma-separated list of beacon API topics to broadcast to all beacon nodes. Possible values are: none,
|
Comma-separated list of beacon API topics to broadcast to all beacon nodes. Possible values are: none,
|
||||||
attestations, blocks, subscriptions, sync-committee. Default (when flag is omitted) is to broadcast
|
attestations, blocks, subscriptions, sync-committee. Default (when flag is omitted) is to broadcast
|
||||||
subscriptions only.
|
subscriptions only.
|
||||||
|
--builder-boost-factor <UINT64>
|
||||||
|
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.
|
||||||
--builder-registration-timestamp-override <builder-registration-timestamp-override>
|
--builder-registration-timestamp-override <builder-registration-timestamp-override>
|
||||||
This flag takes a unix timestamp value that will be used to override the timestamp used in the builder api
|
This flag takes a unix timestamp value that will be used to override the timestamp used in the builder api
|
||||||
registration
|
registration
|
||||||
|
@ -42,6 +42,9 @@ OPTIONS:
|
|||||||
A HTTP(S) address of a beacon node using the beacon-API. If this value is provided, an error will be raised
|
A HTTP(S) address of a beacon node using the beacon-API. If this value is provided, an error will be raised
|
||||||
if any validator key here is already known as a validator by that beacon node. This helps prevent the same
|
if any validator key here is already known as a validator by that beacon node. This helps prevent the same
|
||||||
validator being created twice and therefore slashable conditions.
|
validator being created twice and therefore slashable conditions.
|
||||||
|
--builder-boost-factor <UINT64>
|
||||||
|
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.
|
||||||
--builder-proposals <builder-proposals>
|
--builder-proposals <builder-proposals>
|
||||||
When provided, all created validators will attempt to create blocks via builder rather than the local EL.
|
When provided, all created validators will attempt to create blocks via builder rather than the local EL.
|
||||||
[possible values: true, false]
|
[possible values: true, false]
|
||||||
@ -93,13 +96,18 @@ OPTIONS:
|
|||||||
--logfile-max-size <SIZE>
|
--logfile-max-size <SIZE>
|
||||||
The maximum size (in MB) each log file can grow to before rotating. If set to 0, background file logging is
|
The maximum size (in MB) each log file can grow to before rotating. If set to 0, background file logging is
|
||||||
disabled. [default: 200]
|
disabled. [default: 200]
|
||||||
--mnemonic-path <MNEMONIC_PATH> If present, the mnemonic will be read in from this file.
|
--mnemonic-path <MNEMONIC_PATH>
|
||||||
|
If present, the mnemonic will be read in from this file.
|
||||||
|
|
||||||
--network <network>
|
--network <network>
|
||||||
Name of the Eth2 chain Lighthouse will sync and follow. [possible values: mainnet, prater, goerli, gnosis,
|
Name of the Eth2 chain Lighthouse will sync and follow. [possible values: mainnet, prater, goerli, gnosis,
|
||||||
chiado, sepolia, holesky]
|
chiado, sepolia, holesky]
|
||||||
--output-path <DIRECTORY>
|
--output-path <DIRECTORY>
|
||||||
The path to a directory where the validator and (optionally) deposits files will be created. The directory
|
The path to a directory where the validator and (optionally) deposits files will be created. The directory
|
||||||
will be created if it does not exist.
|
will be created if it does not exist.
|
||||||
|
--prefer-builder-proposals <prefer-builder-proposals>
|
||||||
|
If this flag is set, Lighthouse will always prefer blocks constructed by builders, regardless of payload
|
||||||
|
value. [possible values: true, false]
|
||||||
--safe-slots-to-import-optimistically <INTEGER>
|
--safe-slots-to-import-optimistically <INTEGER>
|
||||||
Used to coordinate manual overrides of the SAFE_SLOTS_TO_IMPORT_OPTIMISTICALLY parameter. This flag should
|
Used to coordinate manual overrides of the SAFE_SLOTS_TO_IMPORT_OPTIMISTICALLY parameter. This flag should
|
||||||
only be used if the user has a clear understanding that the broad Ethereum community has elected to override
|
only be used if the user has a clear understanding that the broad Ethereum community has elected to override
|
||||||
|
@ -26,10 +26,13 @@ FLAGS:
|
|||||||
-V, --version Prints version information
|
-V, --version Prints version information
|
||||||
|
|
||||||
OPTIONS:
|
OPTIONS:
|
||||||
|
--builder-boost-factor <UINT64>
|
||||||
|
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.
|
||||||
--builder-proposals <builder-proposals>
|
--builder-proposals <builder-proposals>
|
||||||
When provided, all created validators will attempt to create blocks via builder rather than the local EL.
|
When provided, all created validators will attempt to create blocks via builder rather than the local EL.
|
||||||
[possible values: true, false]
|
[possible values: true, false]
|
||||||
--count <VALIDATOR_COUNT> The number of validators to move.
|
--count <VALIDATOR_COUNT> The number of validators to move.
|
||||||
-d, --datadir <DIR>
|
-d, --datadir <DIR>
|
||||||
Used to specify a custom root data directory for lighthouse keys and databases. Defaults to
|
Used to specify a custom root data directory for lighthouse keys and databases. Defaults to
|
||||||
$HOME/.lighthouse/{network} where network is the value of the `network` flag Note: Users should specify
|
$HOME/.lighthouse/{network} where network is the value of the `network` flag Note: Users should specify
|
||||||
@ -75,6 +78,9 @@ OPTIONS:
|
|||||||
--network <network>
|
--network <network>
|
||||||
Name of the Eth2 chain Lighthouse will sync and follow. [possible values: mainnet, prater, goerli, gnosis,
|
Name of the Eth2 chain Lighthouse will sync and follow. [possible values: mainnet, prater, goerli, gnosis,
|
||||||
chiado, sepolia, holesky]
|
chiado, sepolia, holesky]
|
||||||
|
--prefer-builder-proposals <prefer-builder-proposals>
|
||||||
|
If this flag is set, Lighthouse will always prefer blocks constructed by builders, regardless of payload
|
||||||
|
value. [possible values: true, false]
|
||||||
--safe-slots-to-import-optimistically <INTEGER>
|
--safe-slots-to-import-optimistically <INTEGER>
|
||||||
Used to coordinate manual overrides of the SAFE_SLOTS_TO_IMPORT_OPTIMISTICALLY parameter. This flag should
|
Used to coordinate manual overrides of the SAFE_SLOTS_TO_IMPORT_OPTIMISTICALLY parameter. This flag should
|
||||||
only be used if the user has a clear understanding that the broad Ethereum community has elected to override
|
only be used if the user has a clear understanding that the broad Ethereum community has elected to override
|
||||||
|
@ -157,6 +157,12 @@ pub struct ValidatorDefinition {
|
|||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub builder_proposals: Option<bool>,
|
pub builder_proposals: Option<bool>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub builder_boost_factor: Option<u64>,
|
||||||
|
#[serde(default)]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub prefer_builder_proposals: Option<bool>,
|
||||||
|
#[serde(default)]
|
||||||
pub description: String,
|
pub description: String,
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
pub signing_definition: SigningDefinition,
|
pub signing_definition: SigningDefinition,
|
||||||
@ -169,6 +175,7 @@ impl ValidatorDefinition {
|
|||||||
/// ## Notes
|
/// ## Notes
|
||||||
///
|
///
|
||||||
/// This function does not check the password against the keystore.
|
/// This function does not check the password against the keystore.
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn new_keystore_with_password<P: AsRef<Path>>(
|
pub fn new_keystore_with_password<P: AsRef<Path>>(
|
||||||
voting_keystore_path: P,
|
voting_keystore_path: P,
|
||||||
voting_keystore_password_storage: PasswordStorage,
|
voting_keystore_password_storage: PasswordStorage,
|
||||||
@ -176,6 +183,8 @@ impl ValidatorDefinition {
|
|||||||
suggested_fee_recipient: Option<Address>,
|
suggested_fee_recipient: Option<Address>,
|
||||||
gas_limit: Option<u64>,
|
gas_limit: Option<u64>,
|
||||||
builder_proposals: Option<bool>,
|
builder_proposals: Option<bool>,
|
||||||
|
builder_boost_factor: Option<u64>,
|
||||||
|
prefer_builder_proposals: Option<bool>,
|
||||||
) -> Result<Self, Error> {
|
) -> Result<Self, Error> {
|
||||||
let voting_keystore_path = voting_keystore_path.as_ref().into();
|
let voting_keystore_path = voting_keystore_path.as_ref().into();
|
||||||
let keystore =
|
let keystore =
|
||||||
@ -196,6 +205,8 @@ impl ValidatorDefinition {
|
|||||||
suggested_fee_recipient,
|
suggested_fee_recipient,
|
||||||
gas_limit,
|
gas_limit,
|
||||||
builder_proposals,
|
builder_proposals,
|
||||||
|
builder_boost_factor,
|
||||||
|
prefer_builder_proposals,
|
||||||
signing_definition: SigningDefinition::LocalKeystore {
|
signing_definition: SigningDefinition::LocalKeystore {
|
||||||
voting_keystore_path,
|
voting_keystore_path,
|
||||||
voting_keystore_password_path,
|
voting_keystore_password_path,
|
||||||
@ -344,6 +355,8 @@ impl ValidatorDefinitions {
|
|||||||
suggested_fee_recipient: None,
|
suggested_fee_recipient: None,
|
||||||
gas_limit: None,
|
gas_limit: None,
|
||||||
builder_proposals: None,
|
builder_proposals: None,
|
||||||
|
builder_boost_factor: None,
|
||||||
|
prefer_builder_proposals: None,
|
||||||
signing_definition: SigningDefinition::LocalKeystore {
|
signing_definition: SigningDefinition::LocalKeystore {
|
||||||
voting_keystore_path,
|
voting_keystore_path,
|
||||||
voting_keystore_password_path,
|
voting_keystore_password_path,
|
||||||
|
@ -483,12 +483,15 @@ impl ValidatorClientHttpClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// `PATCH lighthouse/validators/{validator_pubkey}`
|
/// `PATCH lighthouse/validators/{validator_pubkey}`
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub async fn patch_lighthouse_validators(
|
pub async fn patch_lighthouse_validators(
|
||||||
&self,
|
&self,
|
||||||
voting_pubkey: &PublicKeyBytes,
|
voting_pubkey: &PublicKeyBytes,
|
||||||
enabled: Option<bool>,
|
enabled: Option<bool>,
|
||||||
gas_limit: Option<u64>,
|
gas_limit: Option<u64>,
|
||||||
builder_proposals: Option<bool>,
|
builder_proposals: Option<bool>,
|
||||||
|
builder_boost_factor: Option<u64>,
|
||||||
|
prefer_builder_proposals: Option<bool>,
|
||||||
graffiti: Option<GraffitiString>,
|
graffiti: Option<GraffitiString>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let mut path = self.server.full.clone();
|
let mut path = self.server.full.clone();
|
||||||
@ -505,6 +508,8 @@ impl ValidatorClientHttpClient {
|
|||||||
enabled,
|
enabled,
|
||||||
gas_limit,
|
gas_limit,
|
||||||
builder_proposals,
|
builder_proposals,
|
||||||
|
builder_boost_factor,
|
||||||
|
prefer_builder_proposals,
|
||||||
graffiti,
|
graffiti,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
@ -32,6 +32,12 @@ pub struct ValidatorRequest {
|
|||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub builder_proposals: Option<bool>,
|
pub builder_proposals: Option<bool>,
|
||||||
|
#[serde(default)]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub builder_boost_factor: Option<u64>,
|
||||||
|
#[serde(default)]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub prefer_builder_proposals: Option<bool>,
|
||||||
#[serde(with = "serde_utils::quoted_u64")]
|
#[serde(with = "serde_utils::quoted_u64")]
|
||||||
pub deposit_gwei: u64,
|
pub deposit_gwei: u64,
|
||||||
}
|
}
|
||||||
@ -86,6 +92,12 @@ pub struct ValidatorPatchRequest {
|
|||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub graffiti: Option<GraffitiString>,
|
pub graffiti: Option<GraffitiString>,
|
||||||
|
#[serde(default)]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub builder_boost_factor: Option<u64>,
|
||||||
|
#[serde(default)]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub prefer_builder_proposals: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, PartialEq, Serialize, Deserialize)]
|
||||||
@ -105,6 +117,12 @@ pub struct KeystoreValidatorsPostRequest {
|
|||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub builder_proposals: Option<bool>,
|
pub builder_proposals: Option<bool>,
|
||||||
|
#[serde(default)]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub builder_boost_factor: Option<u64>,
|
||||||
|
#[serde(default)]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub prefer_builder_proposals: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
@ -135,6 +153,12 @@ pub struct Web3SignerValidatorRequest {
|
|||||||
pub client_identity_path: Option<PathBuf>,
|
pub client_identity_path: Option<PathBuf>,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub client_identity_password: Option<String>,
|
pub client_identity_password: Option<String>,
|
||||||
|
#[serde(default)]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub builder_boost_factor: Option<u64>,
|
||||||
|
#[serde(default)]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub prefer_builder_proposals: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
|
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
|
||||||
|
@ -492,6 +492,8 @@ fn validator_import_launchpad() {
|
|||||||
suggested_fee_recipient: None,
|
suggested_fee_recipient: None,
|
||||||
gas_limit: None,
|
gas_limit: None,
|
||||||
builder_proposals: None,
|
builder_proposals: None,
|
||||||
|
builder_boost_factor: None,
|
||||||
|
prefer_builder_proposals: None,
|
||||||
voting_public_key: keystore.public_key().unwrap(),
|
voting_public_key: keystore.public_key().unwrap(),
|
||||||
signing_definition: SigningDefinition::LocalKeystore {
|
signing_definition: SigningDefinition::LocalKeystore {
|
||||||
voting_keystore_path,
|
voting_keystore_path,
|
||||||
@ -614,6 +616,8 @@ fn validator_import_launchpad_no_password_then_add_password() {
|
|||||||
suggested_fee_recipient: None,
|
suggested_fee_recipient: None,
|
||||||
gas_limit: None,
|
gas_limit: None,
|
||||||
builder_proposals: None,
|
builder_proposals: None,
|
||||||
|
builder_boost_factor: None,
|
||||||
|
prefer_builder_proposals: None,
|
||||||
voting_public_key: keystore.public_key().unwrap(),
|
voting_public_key: keystore.public_key().unwrap(),
|
||||||
signing_definition: SigningDefinition::LocalKeystore {
|
signing_definition: SigningDefinition::LocalKeystore {
|
||||||
voting_keystore_path,
|
voting_keystore_path,
|
||||||
@ -640,6 +644,8 @@ fn validator_import_launchpad_no_password_then_add_password() {
|
|||||||
suggested_fee_recipient: None,
|
suggested_fee_recipient: None,
|
||||||
gas_limit: None,
|
gas_limit: None,
|
||||||
builder_proposals: None,
|
builder_proposals: None,
|
||||||
|
builder_boost_factor: None,
|
||||||
|
prefer_builder_proposals: None,
|
||||||
voting_public_key: keystore.public_key().unwrap(),
|
voting_public_key: keystore.public_key().unwrap(),
|
||||||
signing_definition: SigningDefinition::LocalKeystore {
|
signing_definition: SigningDefinition::LocalKeystore {
|
||||||
voting_keystore_path: dst_keystore_dir.join(KEYSTORE_NAME),
|
voting_keystore_path: dst_keystore_dir.join(KEYSTORE_NAME),
|
||||||
@ -742,6 +748,8 @@ fn validator_import_launchpad_password_file() {
|
|||||||
suggested_fee_recipient: None,
|
suggested_fee_recipient: None,
|
||||||
gas_limit: None,
|
gas_limit: None,
|
||||||
builder_proposals: None,
|
builder_proposals: None,
|
||||||
|
builder_boost_factor: None,
|
||||||
|
prefer_builder_proposals: None,
|
||||||
signing_definition: SigningDefinition::LocalKeystore {
|
signing_definition: SigningDefinition::LocalKeystore {
|
||||||
voting_keystore_path,
|
voting_keystore_path,
|
||||||
voting_keystore_password_path: None,
|
voting_keystore_password_path: None,
|
||||||
|
@ -464,6 +464,32 @@ fn builder_proposals_flag() {
|
|||||||
.with_config(|config| assert!(config.builder_proposals));
|
.with_config(|config| assert!(config.builder_proposals));
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
|
fn builder_boost_factor_flag() {
|
||||||
|
CommandLineTest::new()
|
||||||
|
.flag("builder-boost-factor", Some("150"))
|
||||||
|
.run()
|
||||||
|
.with_config(|config| assert_eq!(config.builder_boost_factor, Some(150)));
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn no_builder_boost_factor_flag() {
|
||||||
|
CommandLineTest::new()
|
||||||
|
.run()
|
||||||
|
.with_config(|config| assert_eq!(config.builder_boost_factor, None));
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn prefer_builder_proposals_flag() {
|
||||||
|
CommandLineTest::new()
|
||||||
|
.flag("prefer-builder-proposals", None)
|
||||||
|
.run()
|
||||||
|
.with_config(|config| assert!(config.prefer_builder_proposals));
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn no_prefer_builder_proposals_flag() {
|
||||||
|
CommandLineTest::new()
|
||||||
|
.run()
|
||||||
|
.with_config(|config| assert!(!config.prefer_builder_proposals));
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
fn no_builder_registration_timestamp_override_flag() {
|
fn no_builder_registration_timestamp_override_flag() {
|
||||||
CommandLineTest::new()
|
CommandLineTest::new()
|
||||||
.run()
|
.run()
|
||||||
|
@ -122,6 +122,8 @@ pub fn validator_create_defaults() {
|
|||||||
specify_voting_keystore_password: false,
|
specify_voting_keystore_password: false,
|
||||||
eth1_withdrawal_address: None,
|
eth1_withdrawal_address: None,
|
||||||
builder_proposals: None,
|
builder_proposals: None,
|
||||||
|
builder_boost_factor: None,
|
||||||
|
prefer_builder_proposals: None,
|
||||||
fee_recipient: None,
|
fee_recipient: None,
|
||||||
gas_limit: None,
|
gas_limit: None,
|
||||||
bn_url: None,
|
bn_url: None,
|
||||||
@ -143,6 +145,8 @@ pub fn validator_create_misc_flags() {
|
|||||||
.flag("--specify-voting-keystore-password", None)
|
.flag("--specify-voting-keystore-password", None)
|
||||||
.flag("--eth1-withdrawal-address", Some(EXAMPLE_ETH1_ADDRESS))
|
.flag("--eth1-withdrawal-address", Some(EXAMPLE_ETH1_ADDRESS))
|
||||||
.flag("--builder-proposals", Some("true"))
|
.flag("--builder-proposals", Some("true"))
|
||||||
|
.flag("--prefer-builder-proposals", Some("true"))
|
||||||
|
.flag("--builder-boost-factor", Some("150"))
|
||||||
.flag("--suggested-fee-recipient", Some(EXAMPLE_ETH1_ADDRESS))
|
.flag("--suggested-fee-recipient", Some(EXAMPLE_ETH1_ADDRESS))
|
||||||
.flag("--gas-limit", Some("1337"))
|
.flag("--gas-limit", Some("1337"))
|
||||||
.flag("--beacon-node", Some("http://localhost:1001"))
|
.flag("--beacon-node", Some("http://localhost:1001"))
|
||||||
@ -159,6 +163,8 @@ pub fn validator_create_misc_flags() {
|
|||||||
specify_voting_keystore_password: true,
|
specify_voting_keystore_password: true,
|
||||||
eth1_withdrawal_address: Some(Address::from_str(EXAMPLE_ETH1_ADDRESS).unwrap()),
|
eth1_withdrawal_address: Some(Address::from_str(EXAMPLE_ETH1_ADDRESS).unwrap()),
|
||||||
builder_proposals: Some(true),
|
builder_proposals: Some(true),
|
||||||
|
builder_boost_factor: Some(150),
|
||||||
|
prefer_builder_proposals: Some(true),
|
||||||
fee_recipient: Some(Address::from_str(EXAMPLE_ETH1_ADDRESS).unwrap()),
|
fee_recipient: Some(Address::from_str(EXAMPLE_ETH1_ADDRESS).unwrap()),
|
||||||
gas_limit: Some(1337),
|
gas_limit: Some(1337),
|
||||||
bn_url: Some(SensitiveUrl::parse("http://localhost:1001").unwrap()),
|
bn_url: Some(SensitiveUrl::parse("http://localhost:1001").unwrap()),
|
||||||
@ -244,6 +250,8 @@ pub fn validator_move_defaults() {
|
|||||||
dest_vc_token_path: PathBuf::from("./2.json"),
|
dest_vc_token_path: PathBuf::from("./2.json"),
|
||||||
validators: Validators::All,
|
validators: Validators::All,
|
||||||
builder_proposals: None,
|
builder_proposals: None,
|
||||||
|
builder_boost_factor: None,
|
||||||
|
prefer_builder_proposals: None,
|
||||||
fee_recipient: None,
|
fee_recipient: None,
|
||||||
gas_limit: None,
|
gas_limit: None,
|
||||||
password_source: PasswordSource::Interactive {
|
password_source: PasswordSource::Interactive {
|
||||||
@ -280,6 +288,8 @@ pub fn validator_move_misc_flags_0() {
|
|||||||
PublicKeyBytes::from_str(EXAMPLE_PUBKEY_1).unwrap(),
|
PublicKeyBytes::from_str(EXAMPLE_PUBKEY_1).unwrap(),
|
||||||
]),
|
]),
|
||||||
builder_proposals: Some(true),
|
builder_proposals: Some(true),
|
||||||
|
builder_boost_factor: None,
|
||||||
|
prefer_builder_proposals: None,
|
||||||
fee_recipient: Some(Address::from_str(EXAMPLE_ETH1_ADDRESS).unwrap()),
|
fee_recipient: Some(Address::from_str(EXAMPLE_ETH1_ADDRESS).unwrap()),
|
||||||
gas_limit: Some(1337),
|
gas_limit: Some(1337),
|
||||||
password_source: PasswordSource::Interactive { stdin_inputs: true },
|
password_source: PasswordSource::Interactive { stdin_inputs: true },
|
||||||
@ -297,6 +307,7 @@ pub fn validator_move_misc_flags_1() {
|
|||||||
.flag("--dest-vc-token", Some("./2.json"))
|
.flag("--dest-vc-token", Some("./2.json"))
|
||||||
.flag("--validators", Some(&format!("{}", EXAMPLE_PUBKEY_0)))
|
.flag("--validators", Some(&format!("{}", EXAMPLE_PUBKEY_0)))
|
||||||
.flag("--builder-proposals", Some("false"))
|
.flag("--builder-proposals", Some("false"))
|
||||||
|
.flag("--prefer-builder-proposals", Some("false"))
|
||||||
.assert_success(|config| {
|
.assert_success(|config| {
|
||||||
let expected = MoveConfig {
|
let expected = MoveConfig {
|
||||||
src_vc_url: SensitiveUrl::parse("http://localhost:1").unwrap(),
|
src_vc_url: SensitiveUrl::parse("http://localhost:1").unwrap(),
|
||||||
@ -307,6 +318,40 @@ pub fn validator_move_misc_flags_1() {
|
|||||||
PublicKeyBytes::from_str(EXAMPLE_PUBKEY_0).unwrap()
|
PublicKeyBytes::from_str(EXAMPLE_PUBKEY_0).unwrap()
|
||||||
]),
|
]),
|
||||||
builder_proposals: Some(false),
|
builder_proposals: Some(false),
|
||||||
|
builder_boost_factor: None,
|
||||||
|
prefer_builder_proposals: Some(false),
|
||||||
|
fee_recipient: None,
|
||||||
|
gas_limit: None,
|
||||||
|
password_source: PasswordSource::Interactive {
|
||||||
|
stdin_inputs: cfg!(windows) || false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
assert_eq!(expected, config);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn validator_move_misc_flags_2() {
|
||||||
|
CommandLineTest::validators_move()
|
||||||
|
.flag("--src-vc-url", Some("http://localhost:1"))
|
||||||
|
.flag("--src-vc-token", Some("./1.json"))
|
||||||
|
.flag("--dest-vc-url", Some("http://localhost:2"))
|
||||||
|
.flag("--dest-vc-token", Some("./2.json"))
|
||||||
|
.flag("--validators", Some(&format!("{}", EXAMPLE_PUBKEY_0)))
|
||||||
|
.flag("--builder-proposals", Some("false"))
|
||||||
|
.flag("--builder-boost-factor", Some("100"))
|
||||||
|
.assert_success(|config| {
|
||||||
|
let expected = MoveConfig {
|
||||||
|
src_vc_url: SensitiveUrl::parse("http://localhost:1").unwrap(),
|
||||||
|
src_vc_token_path: PathBuf::from("./1.json"),
|
||||||
|
dest_vc_url: SensitiveUrl::parse("http://localhost:2").unwrap(),
|
||||||
|
dest_vc_token_path: PathBuf::from("./2.json"),
|
||||||
|
validators: Validators::Specific(vec![
|
||||||
|
PublicKeyBytes::from_str(EXAMPLE_PUBKEY_0).unwrap()
|
||||||
|
]),
|
||||||
|
builder_proposals: Some(false),
|
||||||
|
builder_boost_factor: Some(100),
|
||||||
|
prefer_builder_proposals: None,
|
||||||
fee_recipient: None,
|
fee_recipient: None,
|
||||||
gas_limit: None,
|
gas_limit: None,
|
||||||
password_source: PasswordSource::Interactive {
|
password_source: PasswordSource::Interactive {
|
||||||
@ -333,6 +378,8 @@ pub fn validator_move_count() {
|
|||||||
dest_vc_token_path: PathBuf::from("./2.json"),
|
dest_vc_token_path: PathBuf::from("./2.json"),
|
||||||
validators: Validators::Count(42),
|
validators: Validators::Count(42),
|
||||||
builder_proposals: None,
|
builder_proposals: None,
|
||||||
|
builder_boost_factor: None,
|
||||||
|
prefer_builder_proposals: None,
|
||||||
fee_recipient: None,
|
fee_recipient: None,
|
||||||
gas_limit: None,
|
gas_limit: None,
|
||||||
password_source: PasswordSource::Interactive {
|
password_source: PasswordSource::Interactive {
|
||||||
|
@ -391,6 +391,8 @@ mod tests {
|
|||||||
suggested_fee_recipient: None,
|
suggested_fee_recipient: None,
|
||||||
gas_limit: None,
|
gas_limit: None,
|
||||||
builder_proposals: None,
|
builder_proposals: None,
|
||||||
|
builder_boost_factor: None,
|
||||||
|
prefer_builder_proposals: None,
|
||||||
description: String::default(),
|
description: String::default(),
|
||||||
signing_definition: SigningDefinition::LocalKeystore {
|
signing_definition: SigningDefinition::LocalKeystore {
|
||||||
voting_keystore_path: signer_rig.keystore_path.clone(),
|
voting_keystore_path: signer_rig.keystore_path.clone(),
|
||||||
@ -409,6 +411,8 @@ mod tests {
|
|||||||
suggested_fee_recipient: None,
|
suggested_fee_recipient: None,
|
||||||
gas_limit: None,
|
gas_limit: None,
|
||||||
builder_proposals: None,
|
builder_proposals: None,
|
||||||
|
builder_boost_factor: None,
|
||||||
|
prefer_builder_proposals: None,
|
||||||
description: String::default(),
|
description: String::default(),
|
||||||
signing_definition: SigningDefinition::Web3Signer(Web3SignerDefinition {
|
signing_definition: SigningDefinition::Web3Signer(Web3SignerDefinition {
|
||||||
url: signer_rig.url.to_string(),
|
url: signer_rig.url.to_string(),
|
||||||
|
@ -325,14 +325,7 @@ impl<T: SlotClock + 'static, E: EthSpec> BlockService<T, E> {
|
|||||||
|
|
||||||
if self.validator_store.produce_block_v3() {
|
if self.validator_store.produce_block_v3() {
|
||||||
for validator_pubkey in proposers {
|
for validator_pubkey in proposers {
|
||||||
let builder_proposals = self
|
let builder_boost_factor = self.get_builder_boost_factor(&validator_pubkey);
|
||||||
.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 service = self.clone();
|
let service = self.clone();
|
||||||
let log = log.clone();
|
let log = log.clone();
|
||||||
self.inner.context.executor.spawn(
|
self.inner.context.executor.spawn(
|
||||||
@ -853,6 +846,36 @@ impl<T: SlotClock + 'static, E: EthSpec> BlockService<T, E> {
|
|||||||
|
|
||||||
Ok::<_, BlockError>(unsigned_block)
|
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> {
|
pub enum UnsignedBlock<E: EthSpec> {
|
||||||
|
@ -349,4 +349,22 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> {
|
|||||||
.default_value("500")
|
.default_value("500")
|
||||||
.takes_value(true),
|
.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,
|
pub validator_registration_batch_size: usize,
|
||||||
/// Enables block production via the block v3 endpoint. This configuration option can be removed post deneb.
|
/// Enables block production via the block v3 endpoint. This configuration option can be removed post deneb.
|
||||||
pub produce_block_v3: bool,
|
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 {
|
impl Default for Config {
|
||||||
@ -118,6 +122,8 @@ impl Default for Config {
|
|||||||
enable_latency_measurement_service: true,
|
enable_latency_measurement_service: true,
|
||||||
validator_registration_batch_size: 500,
|
validator_registration_batch_size: 500,
|
||||||
produce_block_v3: false,
|
produce_block_v3: false,
|
||||||
|
builder_boost_factor: None,
|
||||||
|
prefer_builder_proposals: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -346,6 +352,10 @@ impl Config {
|
|||||||
config.produce_block_v3 = true;
|
config.produce_block_v3 = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if cli_args.is_present("prefer-builder-proposals") {
|
||||||
|
config.prefer_builder_proposals = true;
|
||||||
|
}
|
||||||
|
|
||||||
config.gas_limit = cli_args
|
config.gas_limit = cli_args
|
||||||
.value_of("gas-limit")
|
.value_of("gas-limit")
|
||||||
.map(|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 =
|
config.enable_latency_measurement_service =
|
||||||
parse_optional(cli_args, "latency-measurement-service")?.unwrap_or(true);
|
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.suggested_fee_recipient,
|
||||||
request.gas_limit,
|
request.gas_limit,
|
||||||
request.builder_proposals,
|
request.builder_proposals,
|
||||||
|
request.builder_boost_factor,
|
||||||
|
request.prefer_builder_proposals,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
|
@ -224,6 +224,8 @@ fn import_single_keystore<T: SlotClock + 'static, E: EthSpec>(
|
|||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
))
|
))
|
||||||
.map_err(|e| format!("failed to initialize validator: {:?}", e))?;
|
.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 suggested_fee_recipient = body.suggested_fee_recipient;
|
||||||
let gas_limit = body.gas_limit;
|
let gas_limit = body.gas_limit;
|
||||||
let builder_proposals = body.builder_proposals;
|
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 = {
|
let validator_def = {
|
||||||
if let Some(handle) = task_executor.handle() {
|
if let Some(handle) = task_executor.handle() {
|
||||||
@ -577,6 +579,8 @@ pub fn serve<T: 'static + SlotClock + Clone, E: EthSpec>(
|
|||||||
suggested_fee_recipient,
|
suggested_fee_recipient,
|
||||||
gas_limit,
|
gas_limit,
|
||||||
builder_proposals,
|
builder_proposals,
|
||||||
|
builder_boost_factor,
|
||||||
|
prefer_builder_proposals,
|
||||||
))
|
))
|
||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
warp_utils::reject::custom_server_error(format!(
|
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,
|
suggested_fee_recipient: web3signer.suggested_fee_recipient,
|
||||||
gas_limit: web3signer.gas_limit,
|
gas_limit: web3signer.gas_limit,
|
||||||
builder_proposals: web3signer.builder_proposals,
|
builder_proposals: web3signer.builder_proposals,
|
||||||
|
builder_boost_factor: web3signer.builder_boost_factor,
|
||||||
|
prefer_builder_proposals: web3signer.prefer_builder_proposals,
|
||||||
description: web3signer.description,
|
description: web3signer.description,
|
||||||
signing_definition: SigningDefinition::Web3Signer(
|
signing_definition: SigningDefinition::Web3Signer(
|
||||||
Web3SignerDefinition {
|
Web3SignerDefinition {
|
||||||
@ -691,8 +697,12 @@ pub fn serve<T: 'static + SlotClock + Clone, E: EthSpec>(
|
|||||||
(Some(is_enabled), Some(initialized_validator))
|
(Some(is_enabled), Some(initialized_validator))
|
||||||
if Some(is_enabled) == body.enabled
|
if Some(is_enabled) == body.enabled
|
||||||
&& initialized_validator.get_gas_limit() == body.gas_limit
|
&& initialized_validator.get_gas_limit() == body.gas_limit
|
||||||
|
&& initialized_validator.get_builder_boost_factor()
|
||||||
|
== body.builder_boost_factor
|
||||||
&& initialized_validator.get_builder_proposals()
|
&& initialized_validator.get_builder_proposals()
|
||||||
== body.builder_proposals
|
== body.builder_proposals
|
||||||
|
&& initialized_validator.get_prefer_builder_proposals()
|
||||||
|
== body.prefer_builder_proposals
|
||||||
&& initialized_validator.get_graffiti() == maybe_graffiti =>
|
&& initialized_validator.get_graffiti() == maybe_graffiti =>
|
||||||
{
|
{
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -706,6 +716,8 @@ pub fn serve<T: 'static + SlotClock + Clone, E: EthSpec>(
|
|||||||
body.enabled,
|
body.enabled,
|
||||||
body.gas_limit,
|
body.gas_limit,
|
||||||
body.builder_proposals,
|
body.builder_proposals,
|
||||||
|
body.builder_boost_factor,
|
||||||
|
body.prefer_builder_proposals,
|
||||||
body.graffiti,
|
body.graffiti,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
@ -125,6 +125,8 @@ fn import_single_remotekey<T: SlotClock + 'static, E: EthSpec>(
|
|||||||
suggested_fee_recipient: None,
|
suggested_fee_recipient: None,
|
||||||
gas_limit: None,
|
gas_limit: None,
|
||||||
builder_proposals: None,
|
builder_proposals: None,
|
||||||
|
builder_boost_factor: None,
|
||||||
|
prefer_builder_proposals: None,
|
||||||
description: String::from("Added by remotekey API"),
|
description: String::from("Added by remotekey API"),
|
||||||
signing_definition: SigningDefinition::Web3Signer(Web3SignerDefinition {
|
signing_definition: SigningDefinition::Web3Signer(Web3SignerDefinition {
|
||||||
url,
|
url,
|
||||||
|
@ -315,6 +315,8 @@ impl ApiTester {
|
|||||||
suggested_fee_recipient: None,
|
suggested_fee_recipient: None,
|
||||||
gas_limit: None,
|
gas_limit: None,
|
||||||
builder_proposals: None,
|
builder_proposals: None,
|
||||||
|
builder_boost_factor: None,
|
||||||
|
prefer_builder_proposals: None,
|
||||||
deposit_gwei: E::default_spec().max_effective_balance,
|
deposit_gwei: E::default_spec().max_effective_balance,
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
@ -447,6 +449,8 @@ impl ApiTester {
|
|||||||
suggested_fee_recipient: None,
|
suggested_fee_recipient: None,
|
||||||
gas_limit: None,
|
gas_limit: None,
|
||||||
builder_proposals: None,
|
builder_proposals: None,
|
||||||
|
builder_boost_factor: None,
|
||||||
|
prefer_builder_proposals: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
self.client
|
self.client
|
||||||
@ -467,6 +471,8 @@ impl ApiTester {
|
|||||||
suggested_fee_recipient: None,
|
suggested_fee_recipient: None,
|
||||||
gas_limit: None,
|
gas_limit: None,
|
||||||
builder_proposals: None,
|
builder_proposals: None,
|
||||||
|
builder_boost_factor: None,
|
||||||
|
prefer_builder_proposals: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let response = self
|
let response = self
|
||||||
@ -511,6 +517,8 @@ impl ApiTester {
|
|||||||
request_timeout_ms: None,
|
request_timeout_ms: None,
|
||||||
client_identity_path: None,
|
client_identity_path: None,
|
||||||
client_identity_password: None,
|
client_identity_password: None,
|
||||||
|
builder_boost_factor: None,
|
||||||
|
prefer_builder_proposals: None,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
@ -534,7 +542,15 @@ impl ApiTester {
|
|||||||
let validator = &self.client.get_lighthouse_validators().await.unwrap().data[index];
|
let validator = &self.client.get_lighthouse_validators().await.unwrap().data[index];
|
||||||
|
|
||||||
self.client
|
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
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
@ -582,6 +598,8 @@ impl ApiTester {
|
|||||||
Some(gas_limit),
|
Some(gas_limit),
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@ -610,6 +628,8 @@ impl ApiTester {
|
|||||||
None,
|
None,
|
||||||
Some(builder_proposals),
|
Some(builder_proposals),
|
||||||
None,
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -52,6 +52,12 @@ struct ApiTester {
|
|||||||
|
|
||||||
impl ApiTester {
|
impl ApiTester {
|
||||||
pub async fn new() -> Self {
|
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 log = test_logger();
|
||||||
|
|
||||||
let validator_dir = tempdir().unwrap();
|
let validator_dir = tempdir().unwrap();
|
||||||
@ -70,10 +76,8 @@ impl ApiTester {
|
|||||||
let api_secret = ApiSecret::create_or_open(validator_dir.path()).unwrap();
|
let api_secret = ApiSecret::create_or_open(validator_dir.path()).unwrap();
|
||||||
let api_pubkey = api_secret.api_token();
|
let api_pubkey = api_secret.api_token();
|
||||||
|
|
||||||
let mut config = Config::default();
|
|
||||||
config.validator_dir = validator_dir.path().into();
|
config.validator_dir = validator_dir.path().into();
|
||||||
config.secrets_dir = secrets_dir.path().into();
|
config.secrets_dir = secrets_dir.path().into();
|
||||||
config.fee_recipient = Some(TEST_DEFAULT_FEE_RECIPIENT);
|
|
||||||
|
|
||||||
let spec = E::default_spec();
|
let spec = E::default_spec();
|
||||||
|
|
||||||
@ -271,6 +275,8 @@ impl ApiTester {
|
|||||||
suggested_fee_recipient: None,
|
suggested_fee_recipient: None,
|
||||||
gas_limit: None,
|
gas_limit: None,
|
||||||
builder_proposals: None,
|
builder_proposals: None,
|
||||||
|
builder_boost_factor: None,
|
||||||
|
prefer_builder_proposals: None,
|
||||||
deposit_gwei: E::default_spec().max_effective_balance,
|
deposit_gwei: E::default_spec().max_effective_balance,
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
@ -404,6 +410,8 @@ impl ApiTester {
|
|||||||
suggested_fee_recipient: None,
|
suggested_fee_recipient: None,
|
||||||
gas_limit: None,
|
gas_limit: None,
|
||||||
builder_proposals: None,
|
builder_proposals: None,
|
||||||
|
builder_boost_factor: None,
|
||||||
|
prefer_builder_proposals: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
self.client
|
self.client
|
||||||
@ -424,6 +432,8 @@ impl ApiTester {
|
|||||||
suggested_fee_recipient: None,
|
suggested_fee_recipient: None,
|
||||||
gas_limit: None,
|
gas_limit: None,
|
||||||
builder_proposals: None,
|
builder_proposals: None,
|
||||||
|
builder_boost_factor: None,
|
||||||
|
prefer_builder_proposals: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let response = self
|
let response = self
|
||||||
@ -462,6 +472,8 @@ impl ApiTester {
|
|||||||
suggested_fee_recipient: None,
|
suggested_fee_recipient: None,
|
||||||
gas_limit: None,
|
gas_limit: None,
|
||||||
builder_proposals: None,
|
builder_proposals: None,
|
||||||
|
builder_boost_factor: None,
|
||||||
|
prefer_builder_proposals: None,
|
||||||
voting_public_key: kp.pk,
|
voting_public_key: kp.pk,
|
||||||
url: format!("http://signer_{}.com/", i),
|
url: format!("http://signer_{}.com/", i),
|
||||||
root_certificate_path: None,
|
root_certificate_path: None,
|
||||||
@ -518,7 +530,15 @@ impl ApiTester {
|
|||||||
let validator = &self.client.get_lighthouse_validators().await.unwrap().data[index];
|
let validator = &self.client.get_lighthouse_validators().await.unwrap().data[index];
|
||||||
|
|
||||||
self.client
|
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
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
@ -566,6 +586,8 @@ impl ApiTester {
|
|||||||
Some(gas_limit),
|
Some(gas_limit),
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@ -594,6 +616,50 @@ impl ApiTester {
|
|||||||
None,
|
None,
|
||||||
Some(builder_proposals),
|
Some(builder_proposals),
|
||||||
None,
|
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
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@ -613,6 +679,64 @@ impl ApiTester {
|
|||||||
self
|
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 {
|
pub async fn set_graffiti(self, index: usize, graffiti: &str) -> Self {
|
||||||
let validator = &self.client.get_lighthouse_validators().await.unwrap().data[index];
|
let validator = &self.client.get_lighthouse_validators().await.unwrap().data[index];
|
||||||
let graffiti_str = GraffitiString::from_str(graffiti).unwrap();
|
let graffiti_str = GraffitiString::from_str(graffiti).unwrap();
|
||||||
@ -622,6 +746,8 @@ impl ApiTester {
|
|||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
Some(graffiti_str),
|
Some(graffiti_str),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
@ -741,6 +867,8 @@ async fn routes_with_invalid_auth() {
|
|||||||
gas_limit: <_>::default(),
|
gas_limit: <_>::default(),
|
||||||
builder_proposals: <_>::default(),
|
builder_proposals: <_>::default(),
|
||||||
deposit_gwei: <_>::default(),
|
deposit_gwei: <_>::default(),
|
||||||
|
builder_boost_factor: <_>::default(),
|
||||||
|
prefer_builder_proposals: <_>::default(),
|
||||||
}])
|
}])
|
||||||
.await
|
.await
|
||||||
})
|
})
|
||||||
@ -771,6 +899,8 @@ async fn routes_with_invalid_auth() {
|
|||||||
suggested_fee_recipient: <_>::default(),
|
suggested_fee_recipient: <_>::default(),
|
||||||
gas_limit: <_>::default(),
|
gas_limit: <_>::default(),
|
||||||
builder_proposals: <_>::default(),
|
builder_proposals: <_>::default(),
|
||||||
|
builder_boost_factor: <_>::default(),
|
||||||
|
prefer_builder_proposals: <_>::default(),
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
})
|
})
|
||||||
@ -783,6 +913,8 @@ async fn routes_with_invalid_auth() {
|
|||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
})
|
})
|
||||||
@ -980,6 +1112,100 @@ async fn validator_builder_proposals() {
|
|||||||
.await;
|
.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]
|
#[tokio::test]
|
||||||
async fn validator_graffiti() {
|
async fn validator_graffiti() {
|
||||||
ApiTester::new()
|
ApiTester::new()
|
||||||
|
@ -43,6 +43,8 @@ fn web3signer_validator_with_pubkey(pubkey: PublicKey) -> Web3SignerValidatorReq
|
|||||||
suggested_fee_recipient: None,
|
suggested_fee_recipient: None,
|
||||||
gas_limit: None,
|
gas_limit: None,
|
||||||
builder_proposals: None,
|
builder_proposals: None,
|
||||||
|
builder_boost_factor: None,
|
||||||
|
prefer_builder_proposals: None,
|
||||||
voting_public_key: pubkey,
|
voting_public_key: pubkey,
|
||||||
url: web3_signer_url(),
|
url: web3_signer_url(),
|
||||||
root_certificate_path: None,
|
root_certificate_path: None,
|
||||||
@ -468,7 +470,7 @@ async fn import_and_delete_conflicting_web3_signer_keystores() {
|
|||||||
for pubkey in &pubkeys {
|
for pubkey in &pubkeys {
|
||||||
tester
|
tester
|
||||||
.client
|
.client
|
||||||
.patch_lighthouse_validators(pubkey, Some(false), None, None, None)
|
.patch_lighthouse_validators(pubkey, Some(false), None, None, None, None, None)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
@ -131,6 +131,8 @@ pub struct InitializedValidator {
|
|||||||
suggested_fee_recipient: Option<Address>,
|
suggested_fee_recipient: Option<Address>,
|
||||||
gas_limit: Option<u64>,
|
gas_limit: Option<u64>,
|
||||||
builder_proposals: Option<bool>,
|
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.
|
/// The validators index in `state.validators`, to be updated by an external service.
|
||||||
index: Option<u64>,
|
index: Option<u64>,
|
||||||
}
|
}
|
||||||
@ -159,6 +161,14 @@ impl InitializedValidator {
|
|||||||
self.gas_limit
|
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> {
|
pub fn get_builder_proposals(&self) -> Option<bool> {
|
||||||
self.builder_proposals
|
self.builder_proposals
|
||||||
}
|
}
|
||||||
@ -335,6 +345,8 @@ impl InitializedValidator {
|
|||||||
suggested_fee_recipient: def.suggested_fee_recipient,
|
suggested_fee_recipient: def.suggested_fee_recipient,
|
||||||
gas_limit: def.gas_limit,
|
gas_limit: def.gas_limit,
|
||||||
builder_proposals: def.builder_proposals,
|
builder_proposals: def.builder_proposals,
|
||||||
|
builder_boost_factor: def.builder_boost_factor,
|
||||||
|
prefer_builder_proposals: def.prefer_builder_proposals,
|
||||||
index: None,
|
index: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -815,6 +827,22 @@ impl InitializedValidators {
|
|||||||
.and_then(|v| v.builder_proposals)
|
.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
|
/// Returns an `Option` of a reference to an `InitializedValidator` for a given public key specified in the
|
||||||
/// `ValidatorDefinitions`.
|
/// `ValidatorDefinitions`.
|
||||||
pub fn validator(&self, public_key: &PublicKeyBytes) -> Option<&InitializedValidator> {
|
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`.
|
/// or `InitializedValidator`. The same logic applies to `builder_proposals` and `graffiti`.
|
||||||
///
|
///
|
||||||
/// Saves the `ValidatorDefinitions` to file, even if no definitions were changed.
|
/// Saves the `ValidatorDefinitions` to file, even if no definitions were changed.
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub async fn set_validator_definition_fields(
|
pub async fn set_validator_definition_fields(
|
||||||
&mut self,
|
&mut self,
|
||||||
voting_public_key: &PublicKey,
|
voting_public_key: &PublicKey,
|
||||||
enabled: Option<bool>,
|
enabled: Option<bool>,
|
||||||
gas_limit: Option<u64>,
|
gas_limit: Option<u64>,
|
||||||
builder_proposals: Option<bool>,
|
builder_proposals: Option<bool>,
|
||||||
|
builder_boost_factor: Option<u64>,
|
||||||
|
prefer_builder_proposals: Option<bool>,
|
||||||
graffiti: Option<GraffitiString>,
|
graffiti: Option<GraffitiString>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
if let Some(def) = self
|
if let Some(def) = self
|
||||||
@ -862,6 +893,12 @@ impl InitializedValidators {
|
|||||||
if let Some(graffiti) = graffiti.clone() {
|
if let Some(graffiti) = graffiti.clone() {
|
||||||
def.graffiti = Some(graffiti);
|
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?;
|
self.update_validators().await?;
|
||||||
@ -880,6 +917,12 @@ impl InitializedValidators {
|
|||||||
if let Some(graffiti) = graffiti {
|
if let Some(graffiti) = graffiti {
|
||||||
val.graffiti = Some(graffiti.into());
|
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
|
self.definitions
|
||||||
|
@ -98,6 +98,8 @@ pub struct ValidatorStore<T, E: EthSpec> {
|
|||||||
gas_limit: Option<u64>,
|
gas_limit: Option<u64>,
|
||||||
builder_proposals: bool,
|
builder_proposals: bool,
|
||||||
produce_block_v3: bool,
|
produce_block_v3: bool,
|
||||||
|
prefer_builder_proposals: bool,
|
||||||
|
builder_boost_factor: Option<u64>,
|
||||||
task_executor: TaskExecutor,
|
task_executor: TaskExecutor,
|
||||||
_phantom: PhantomData<E>,
|
_phantom: PhantomData<E>,
|
||||||
}
|
}
|
||||||
@ -130,6 +132,8 @@ impl<T: SlotClock + 'static, E: EthSpec> ValidatorStore<T, E> {
|
|||||||
gas_limit: config.gas_limit,
|
gas_limit: config.gas_limit,
|
||||||
builder_proposals: config.builder_proposals,
|
builder_proposals: config.builder_proposals,
|
||||||
produce_block_v3: config.produce_block_v3,
|
produce_block_v3: config.produce_block_v3,
|
||||||
|
prefer_builder_proposals: config.prefer_builder_proposals,
|
||||||
|
builder_boost_factor: config.builder_boost_factor,
|
||||||
task_executor,
|
task_executor,
|
||||||
_phantom: PhantomData,
|
_phantom: PhantomData,
|
||||||
}
|
}
|
||||||
@ -178,6 +182,8 @@ impl<T: SlotClock + 'static, E: EthSpec> ValidatorStore<T, E> {
|
|||||||
suggested_fee_recipient: Option<Address>,
|
suggested_fee_recipient: Option<Address>,
|
||||||
gas_limit: Option<u64>,
|
gas_limit: Option<u64>,
|
||||||
builder_proposals: Option<bool>,
|
builder_proposals: Option<bool>,
|
||||||
|
builder_boost_factor: Option<u64>,
|
||||||
|
prefer_builder_proposals: Option<bool>,
|
||||||
) -> Result<ValidatorDefinition, String> {
|
) -> Result<ValidatorDefinition, String> {
|
||||||
let mut validator_def = ValidatorDefinition::new_keystore_with_password(
|
let mut validator_def = ValidatorDefinition::new_keystore_with_password(
|
||||||
voting_keystore_path,
|
voting_keystore_path,
|
||||||
@ -186,6 +192,8 @@ impl<T: SlotClock + 'static, E: EthSpec> ValidatorStore<T, E> {
|
|||||||
suggested_fee_recipient,
|
suggested_fee_recipient,
|
||||||
gas_limit,
|
gas_limit,
|
||||||
builder_proposals,
|
builder_proposals,
|
||||||
|
builder_boost_factor,
|
||||||
|
prefer_builder_proposals,
|
||||||
)
|
)
|
||||||
.map_err(|e| format!("failed to create validator definitions: {:?}", e))?;
|
.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)
|
.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:
|
/// builder API. The priority order for fetching this value is:
|
||||||
///
|
///
|
||||||
/// 1. validator_definitions.yml
|
/// 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 {
|
fn get_builder_proposals_defaulting(&self, builder_proposals: Option<bool>) -> bool {
|
||||||
builder_proposals
|
builder_proposals
|
||||||
// If there's nothing in the file, try the process-level default value.
|
// If there's nothing in the file, try the process-level default value.
|
||||||
.unwrap_or(self.builder_proposals)
|
.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>>(
|
pub async fn sign_block<Payload: AbstractExecPayload<E>>(
|
||||||
&self,
|
&self,
|
||||||
validator_pubkey: PublicKeyBytes,
|
validator_pubkey: PublicKeyBytes,
|
||||||
|
@ -46,6 +46,8 @@ pub struct ValidatorSpecification {
|
|||||||
pub fee_recipient: Option<Address>,
|
pub fee_recipient: Option<Address>,
|
||||||
pub gas_limit: Option<u64>,
|
pub gas_limit: Option<u64>,
|
||||||
pub builder_proposals: Option<bool>,
|
pub builder_proposals: Option<bool>,
|
||||||
|
pub builder_boost_factor: Option<u64>,
|
||||||
|
pub prefer_builder_proposals: Option<bool>,
|
||||||
pub enabled: Option<bool>,
|
pub enabled: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,6 +66,8 @@ impl ValidatorSpecification {
|
|||||||
gas_limit,
|
gas_limit,
|
||||||
builder_proposals,
|
builder_proposals,
|
||||||
enabled,
|
enabled,
|
||||||
|
builder_boost_factor,
|
||||||
|
prefer_builder_proposals,
|
||||||
} = self;
|
} = self;
|
||||||
|
|
||||||
let voting_public_key = voting_keystore
|
let voting_public_key = voting_keystore
|
||||||
@ -136,6 +140,8 @@ impl ValidatorSpecification {
|
|||||||
enabled,
|
enabled,
|
||||||
gas_limit,
|
gas_limit,
|
||||||
builder_proposals,
|
builder_proposals,
|
||||||
|
builder_boost_factor,
|
||||||
|
prefer_builder_proposals,
|
||||||
None, // Grafitti field is not maintained between validator moves.
|
None, // Grafitti field is not maintained between validator moves.
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
|
@ -25,6 +25,8 @@ pub const ETH1_WITHDRAWAL_ADDRESS_FLAG: &str = "eth1-withdrawal-address";
|
|||||||
pub const GAS_LIMIT_FLAG: &str = "gas-limit";
|
pub const GAS_LIMIT_FLAG: &str = "gas-limit";
|
||||||
pub const FEE_RECIPIENT_FLAG: &str = "suggested-fee-recipient";
|
pub const FEE_RECIPIENT_FLAG: &str = "suggested-fee-recipient";
|
||||||
pub const BUILDER_PROPOSALS_FLAG: &str = "builder-proposals";
|
pub const BUILDER_PROPOSALS_FLAG: &str = "builder-proposals";
|
||||||
|
pub const BUILDER_BOOST_FACTOR_FLAG: &str = "builder-boost-factor";
|
||||||
|
pub const PREFER_BUILDER_PROPOSALS_FLAG: &str = "prefer-builder-proposals";
|
||||||
pub const BEACON_NODE_FLAG: &str = "beacon-node";
|
pub const BEACON_NODE_FLAG: &str = "beacon-node";
|
||||||
pub const FORCE_BLS_WITHDRAWAL_CREDENTIALS: &str = "force-bls-withdrawal-credentials";
|
pub const FORCE_BLS_WITHDRAWAL_CREDENTIALS: &str = "force-bls-withdrawal-credentials";
|
||||||
|
|
||||||
@ -183,6 +185,30 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> {
|
|||||||
address. This is not recommended.",
|
address. This is not recommended.",
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name(BUILDER_BOOST_FACTOR_FLAG)
|
||||||
|
.long(BUILDER_BOOST_FACTOR_FLAG)
|
||||||
|
.takes_value(true)
|
||||||
|
.value_name("UINT64")
|
||||||
|
.required(false)
|
||||||
|
.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.",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name(PREFER_BUILDER_PROPOSALS_FLAG)
|
||||||
|
.long(PREFER_BUILDER_PROPOSALS_FLAG)
|
||||||
|
.help(
|
||||||
|
"If this flag is set, Lighthouse will always prefer blocks \
|
||||||
|
constructed by builders, regardless of payload value.",
|
||||||
|
)
|
||||||
|
.required(false)
|
||||||
|
.possible_values(&["true", "false"])
|
||||||
|
.takes_value(true),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The CLI arguments are parsed into this struct before running the application. This step of
|
/// The CLI arguments are parsed into this struct before running the application. This step of
|
||||||
@ -199,6 +225,8 @@ pub struct CreateConfig {
|
|||||||
pub specify_voting_keystore_password: bool,
|
pub specify_voting_keystore_password: bool,
|
||||||
pub eth1_withdrawal_address: Option<Address>,
|
pub eth1_withdrawal_address: Option<Address>,
|
||||||
pub builder_proposals: Option<bool>,
|
pub builder_proposals: Option<bool>,
|
||||||
|
pub builder_boost_factor: Option<u64>,
|
||||||
|
pub prefer_builder_proposals: Option<bool>,
|
||||||
pub fee_recipient: Option<Address>,
|
pub fee_recipient: Option<Address>,
|
||||||
pub gas_limit: Option<u64>,
|
pub gas_limit: Option<u64>,
|
||||||
pub bn_url: Option<SensitiveUrl>,
|
pub bn_url: Option<SensitiveUrl>,
|
||||||
@ -223,6 +251,11 @@ impl CreateConfig {
|
|||||||
ETH1_WITHDRAWAL_ADDRESS_FLAG,
|
ETH1_WITHDRAWAL_ADDRESS_FLAG,
|
||||||
)?,
|
)?,
|
||||||
builder_proposals: clap_utils::parse_optional(matches, BUILDER_PROPOSALS_FLAG)?,
|
builder_proposals: clap_utils::parse_optional(matches, BUILDER_PROPOSALS_FLAG)?,
|
||||||
|
builder_boost_factor: clap_utils::parse_optional(matches, BUILDER_BOOST_FACTOR_FLAG)?,
|
||||||
|
prefer_builder_proposals: clap_utils::parse_optional(
|
||||||
|
matches,
|
||||||
|
PREFER_BUILDER_PROPOSALS_FLAG,
|
||||||
|
)?,
|
||||||
fee_recipient: clap_utils::parse_optional(matches, FEE_RECIPIENT_FLAG)?,
|
fee_recipient: clap_utils::parse_optional(matches, FEE_RECIPIENT_FLAG)?,
|
||||||
gas_limit: clap_utils::parse_optional(matches, GAS_LIMIT_FLAG)?,
|
gas_limit: clap_utils::parse_optional(matches, GAS_LIMIT_FLAG)?,
|
||||||
bn_url: clap_utils::parse_optional(matches, BEACON_NODE_FLAG)?,
|
bn_url: clap_utils::parse_optional(matches, BEACON_NODE_FLAG)?,
|
||||||
@ -254,6 +287,8 @@ impl ValidatorsAndDeposits {
|
|||||||
gas_limit,
|
gas_limit,
|
||||||
bn_url,
|
bn_url,
|
||||||
force_bls_withdrawal_credentials,
|
force_bls_withdrawal_credentials,
|
||||||
|
builder_boost_factor,
|
||||||
|
prefer_builder_proposals,
|
||||||
} = config;
|
} = config;
|
||||||
|
|
||||||
// Since Capella, it really doesn't make much sense to use BLS
|
// Since Capella, it really doesn't make much sense to use BLS
|
||||||
@ -456,6 +491,8 @@ impl ValidatorsAndDeposits {
|
|||||||
fee_recipient,
|
fee_recipient,
|
||||||
gas_limit,
|
gas_limit,
|
||||||
builder_proposals,
|
builder_proposals,
|
||||||
|
builder_boost_factor,
|
||||||
|
prefer_builder_proposals,
|
||||||
// Allow the VC to choose a default "enabled" state. Since "enabled" is not part of
|
// Allow the VC to choose a default "enabled" state. Since "enabled" is not part of
|
||||||
// the standard API, leaving this as `None` means we are not forced to use the
|
// the standard API, leaving this as `None` means we are not forced to use the
|
||||||
// non-standard API.
|
// non-standard API.
|
||||||
@ -585,6 +622,8 @@ pub mod tests {
|
|||||||
specify_voting_keystore_password: false,
|
specify_voting_keystore_password: false,
|
||||||
eth1_withdrawal_address: junk_execution_address(),
|
eth1_withdrawal_address: junk_execution_address(),
|
||||||
builder_proposals: None,
|
builder_proposals: None,
|
||||||
|
builder_boost_factor: None,
|
||||||
|
prefer_builder_proposals: None,
|
||||||
fee_recipient: None,
|
fee_recipient: None,
|
||||||
gas_limit: None,
|
gas_limit: None,
|
||||||
bn_url: None,
|
bn_url: None,
|
||||||
|
@ -32,6 +32,8 @@ pub const VALIDATORS_FLAG: &str = "validators";
|
|||||||
pub const GAS_LIMIT_FLAG: &str = "gas-limit";
|
pub const GAS_LIMIT_FLAG: &str = "gas-limit";
|
||||||
pub const FEE_RECIPIENT_FLAG: &str = "suggested-fee-recipient";
|
pub const FEE_RECIPIENT_FLAG: &str = "suggested-fee-recipient";
|
||||||
pub const BUILDER_PROPOSALS_FLAG: &str = "builder-proposals";
|
pub const BUILDER_PROPOSALS_FLAG: &str = "builder-proposals";
|
||||||
|
pub const BUILDER_BOOST_FACTOR_FLAG: &str = "builder-boost-factor";
|
||||||
|
pub const PREFER_BUILDER_PROPOSALS_FLAG: &str = "prefer-builder-proposals";
|
||||||
|
|
||||||
const NO_VALIDATORS_MSG: &str = "No validators present on source validator client";
|
const NO_VALIDATORS_MSG: &str = "No validators present on source validator client";
|
||||||
|
|
||||||
@ -170,6 +172,30 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> {
|
|||||||
.long(STDIN_INPUTS_FLAG)
|
.long(STDIN_INPUTS_FLAG)
|
||||||
.help("If present, read all user inputs from stdin instead of tty."),
|
.help("If present, read all user inputs from stdin instead of tty."),
|
||||||
)
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name(BUILDER_BOOST_FACTOR_FLAG)
|
||||||
|
.long(BUILDER_BOOST_FACTOR_FLAG)
|
||||||
|
.takes_value(true)
|
||||||
|
.value_name("UINT64")
|
||||||
|
.required(false)
|
||||||
|
.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.",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name(PREFER_BUILDER_PROPOSALS_FLAG)
|
||||||
|
.long(PREFER_BUILDER_PROPOSALS_FLAG)
|
||||||
|
.help(
|
||||||
|
"If this flag is set, Lighthouse will always prefer blocks \
|
||||||
|
constructed by builders, regardless of payload value.",
|
||||||
|
)
|
||||||
|
.required(false)
|
||||||
|
.possible_values(&["true", "false"])
|
||||||
|
.takes_value(true),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
|
#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
|
||||||
@ -187,6 +213,8 @@ pub struct MoveConfig {
|
|||||||
pub dest_vc_token_path: PathBuf,
|
pub dest_vc_token_path: PathBuf,
|
||||||
pub validators: Validators,
|
pub validators: Validators,
|
||||||
pub builder_proposals: Option<bool>,
|
pub builder_proposals: Option<bool>,
|
||||||
|
pub builder_boost_factor: Option<u64>,
|
||||||
|
pub prefer_builder_proposals: Option<bool>,
|
||||||
pub fee_recipient: Option<Address>,
|
pub fee_recipient: Option<Address>,
|
||||||
pub gas_limit: Option<u64>,
|
pub gas_limit: Option<u64>,
|
||||||
pub password_source: PasswordSource,
|
pub password_source: PasswordSource,
|
||||||
@ -221,6 +249,11 @@ impl MoveConfig {
|
|||||||
dest_vc_token_path: clap_utils::parse_required(matches, DEST_VC_TOKEN_FLAG)?,
|
dest_vc_token_path: clap_utils::parse_required(matches, DEST_VC_TOKEN_FLAG)?,
|
||||||
validators,
|
validators,
|
||||||
builder_proposals: clap_utils::parse_optional(matches, BUILDER_PROPOSALS_FLAG)?,
|
builder_proposals: clap_utils::parse_optional(matches, BUILDER_PROPOSALS_FLAG)?,
|
||||||
|
builder_boost_factor: clap_utils::parse_optional(matches, BUILDER_BOOST_FACTOR_FLAG)?,
|
||||||
|
prefer_builder_proposals: clap_utils::parse_optional(
|
||||||
|
matches,
|
||||||
|
PREFER_BUILDER_PROPOSALS_FLAG,
|
||||||
|
)?,
|
||||||
fee_recipient: clap_utils::parse_optional(matches, FEE_RECIPIENT_FLAG)?,
|
fee_recipient: clap_utils::parse_optional(matches, FEE_RECIPIENT_FLAG)?,
|
||||||
gas_limit: clap_utils::parse_optional(matches, GAS_LIMIT_FLAG)?,
|
gas_limit: clap_utils::parse_optional(matches, GAS_LIMIT_FLAG)?,
|
||||||
password_source: PasswordSource::Interactive {
|
password_source: PasswordSource::Interactive {
|
||||||
@ -253,6 +286,8 @@ async fn run<'a>(config: MoveConfig) -> Result<(), String> {
|
|||||||
fee_recipient,
|
fee_recipient,
|
||||||
gas_limit,
|
gas_limit,
|
||||||
mut password_source,
|
mut password_source,
|
||||||
|
builder_boost_factor,
|
||||||
|
prefer_builder_proposals,
|
||||||
} = config;
|
} = config;
|
||||||
|
|
||||||
// Moving validators between the same VC is unlikely to be useful and probably indicates a user
|
// Moving validators between the same VC is unlikely to be useful and probably indicates a user
|
||||||
@ -488,13 +523,15 @@ async fn run<'a>(config: MoveConfig) -> Result<(), String> {
|
|||||||
|
|
||||||
let keystore_derivation_path = voting_keystore.0.path();
|
let keystore_derivation_path = voting_keystore.0.path();
|
||||||
|
|
||||||
let validator_specification = ValidatorSpecification {
|
let validator_specification: ValidatorSpecification = ValidatorSpecification {
|
||||||
voting_keystore,
|
voting_keystore,
|
||||||
voting_keystore_password,
|
voting_keystore_password,
|
||||||
slashing_protection: Some(InterchangeJsonStr(slashing_protection)),
|
slashing_protection: Some(InterchangeJsonStr(slashing_protection)),
|
||||||
fee_recipient,
|
fee_recipient,
|
||||||
gas_limit,
|
gas_limit,
|
||||||
builder_proposals,
|
builder_proposals,
|
||||||
|
builder_boost_factor,
|
||||||
|
prefer_builder_proposals,
|
||||||
// Allow the VC to choose a default "enabled" state. Since "enabled" is not part of
|
// Allow the VC to choose a default "enabled" state. Since "enabled" is not part of
|
||||||
// the standard API, leaving this as `None` means we are not forced to use the
|
// the standard API, leaving this as `None` means we are not forced to use the
|
||||||
// non-standard API.
|
// non-standard API.
|
||||||
@ -758,6 +795,8 @@ mod test {
|
|||||||
dest_vc_token_path: dest_vc_token_path.clone(),
|
dest_vc_token_path: dest_vc_token_path.clone(),
|
||||||
validators: validators.clone(),
|
validators: validators.clone(),
|
||||||
builder_proposals: None,
|
builder_proposals: None,
|
||||||
|
builder_boost_factor: None,
|
||||||
|
prefer_builder_proposals: None,
|
||||||
fee_recipient: None,
|
fee_recipient: None,
|
||||||
gas_limit: None,
|
gas_limit: None,
|
||||||
password_source: PasswordSource::Testing(self.passwords.clone()),
|
password_source: PasswordSource::Testing(self.passwords.clone()),
|
||||||
|
Loading…
Reference in New Issue
Block a user