mirror of
https://github.com/sigp/lighthouse.git
synced 2026-03-06 18:21:45 +00:00
Block v3 builder boost factor (#5035)
* builder boost factor * default boost factor * revert * deprecate always_prefer_builder_payload, builder-profit-threshold, ignore_builder_override_suggestion_threshold and builder_comparison_factor flags * revert * set deprecated flags to no op, revert should_override_builder * fix test, calc boosted relay value correctly, dont calculate if none * Add deprecation warnings and restore CLI docs
This commit is contained in:
@@ -335,10 +335,7 @@ struct Inner<E: EthSpec> {
|
||||
proposers: RwLock<HashMap<ProposerKey, Proposer>>,
|
||||
executor: TaskExecutor,
|
||||
payload_cache: PayloadCache<E>,
|
||||
builder_profit_threshold: Uint256,
|
||||
log: Logger,
|
||||
always_prefer_builder_payload: bool,
|
||||
ignore_builder_override_suggestion_threshold: f32,
|
||||
/// Track whether the last `newPayload` call errored.
|
||||
///
|
||||
/// This is used *only* in the informational sync status endpoint, so that a VC using this
|
||||
@@ -365,11 +362,7 @@ pub struct Config {
|
||||
pub jwt_version: Option<String>,
|
||||
/// Default directory for the jwt secret if not provided through cli.
|
||||
pub default_datadir: PathBuf,
|
||||
/// The minimum value of an external payload for it to be considered in a proposal.
|
||||
pub builder_profit_threshold: u128,
|
||||
pub execution_timeout_multiplier: Option<u32>,
|
||||
pub always_prefer_builder_payload: bool,
|
||||
pub ignore_builder_override_suggestion_threshold: f32,
|
||||
}
|
||||
|
||||
/// Provides access to one execution engine and provides a neat interface for consumption by the
|
||||
@@ -379,40 +372,6 @@ pub struct ExecutionLayer<T: EthSpec> {
|
||||
inner: Arc<Inner<T>>,
|
||||
}
|
||||
|
||||
/// This function will return the percentage difference between 2 U256 values, using `base_value`
|
||||
/// as the denominator. It is accurate to 7 decimal places which is about the precision of
|
||||
/// an f32.
|
||||
///
|
||||
/// If some error is encountered in the calculation, None will be returned.
|
||||
fn percentage_difference_u256(base_value: Uint256, comparison_value: Uint256) -> Option<f32> {
|
||||
if base_value == Uint256::zero() {
|
||||
return None;
|
||||
}
|
||||
// this is the total supply of ETH in WEI
|
||||
let max_value = Uint256::from(12u8) * Uint256::exp10(25);
|
||||
if base_value > max_value || comparison_value > max_value {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Now we should be able to calculate the difference without division by zero or overflow
|
||||
const PRECISION: usize = 7;
|
||||
let precision_factor = Uint256::exp10(PRECISION);
|
||||
let scaled_difference = if base_value <= comparison_value {
|
||||
(comparison_value - base_value) * precision_factor
|
||||
} else {
|
||||
(base_value - comparison_value) * precision_factor
|
||||
};
|
||||
let scaled_proportion = scaled_difference / base_value;
|
||||
// max value of scaled difference is 1.2 * 10^33, well below the max value of a u128 / f64 / f32
|
||||
let percentage =
|
||||
100.0f64 * scaled_proportion.low_u128() as f64 / precision_factor.low_u128() as f64;
|
||||
if base_value <= comparison_value {
|
||||
Some(percentage as f32)
|
||||
} else {
|
||||
Some(-percentage as f32)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: EthSpec> ExecutionLayer<T> {
|
||||
/// Instantiate `Self` with an Execution engine specified in `Config`, using JSON-RPC via HTTP.
|
||||
pub fn from_config(config: Config, executor: TaskExecutor, log: Logger) -> Result<Self, Error> {
|
||||
@@ -425,10 +384,7 @@ impl<T: EthSpec> ExecutionLayer<T> {
|
||||
jwt_id,
|
||||
jwt_version,
|
||||
default_datadir,
|
||||
builder_profit_threshold,
|
||||
execution_timeout_multiplier,
|
||||
always_prefer_builder_payload,
|
||||
ignore_builder_override_suggestion_threshold,
|
||||
} = config;
|
||||
|
||||
if urls.len() > 1 {
|
||||
@@ -489,10 +445,7 @@ impl<T: EthSpec> ExecutionLayer<T> {
|
||||
execution_blocks: Mutex::new(LruCache::new(EXECUTION_BLOCKS_LRU_CACHE_SIZE)),
|
||||
executor,
|
||||
payload_cache: PayloadCache::default(),
|
||||
builder_profit_threshold: Uint256::from(builder_profit_threshold),
|
||||
log,
|
||||
always_prefer_builder_payload,
|
||||
ignore_builder_override_suggestion_threshold,
|
||||
last_new_payload_errored: RwLock::new(false),
|
||||
};
|
||||
|
||||
@@ -530,7 +483,6 @@ impl<T: EthSpec> ExecutionLayer<T> {
|
||||
self.log(),
|
||||
"Using external block builder";
|
||||
"builder_url" => ?builder_url,
|
||||
"builder_profit_threshold" => self.inner.builder_profit_threshold.as_u128(),
|
||||
"local_user_agent" => builder_client.get_user_agent(),
|
||||
);
|
||||
self.inner.builder.swap(Some(Arc::new(builder_client)));
|
||||
@@ -836,6 +788,7 @@ impl<T: EthSpec> ExecutionLayer<T> {
|
||||
builder_params: BuilderParams,
|
||||
current_fork: ForkName,
|
||||
spec: &ChainSpec,
|
||||
builder_boost_factor: Option<u64>,
|
||||
block_production_version: BlockProductionVersion,
|
||||
) -> Result<BlockProposalContentsType<T>, Error> {
|
||||
let payload_result_type = match block_production_version {
|
||||
@@ -846,6 +799,7 @@ impl<T: EthSpec> ExecutionLayer<T> {
|
||||
forkchoice_update_params,
|
||||
builder_params,
|
||||
current_fork,
|
||||
builder_boost_factor,
|
||||
spec,
|
||||
)
|
||||
.await
|
||||
@@ -870,6 +824,7 @@ impl<T: EthSpec> ExecutionLayer<T> {
|
||||
forkchoice_update_params,
|
||||
builder_params,
|
||||
current_fork,
|
||||
None,
|
||||
spec,
|
||||
)
|
||||
.await?
|
||||
@@ -990,6 +945,7 @@ impl<T: EthSpec> ExecutionLayer<T> {
|
||||
(relay_result, local_result)
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
async fn determine_and_fetch_payload(
|
||||
&self,
|
||||
parent_hash: ExecutionBlockHash,
|
||||
@@ -997,6 +953,7 @@ impl<T: EthSpec> ExecutionLayer<T> {
|
||||
forkchoice_update_params: ForkchoiceUpdateParameters,
|
||||
builder_params: BuilderParams,
|
||||
current_fork: ForkName,
|
||||
builder_boost_factor: Option<u64>,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<ProvenancedPayload<BlockProposalContentsType<T>>, Error> {
|
||||
let Some(builder) = self.builder() else {
|
||||
@@ -1148,18 +1105,36 @@ impl<T: EthSpec> ExecutionLayer<T> {
|
||||
)));
|
||||
}
|
||||
|
||||
if self.inner.always_prefer_builder_payload {
|
||||
return ProvenancedPayload::try_from(relay.data.message);
|
||||
}
|
||||
|
||||
let relay_value = *relay.data.message.value();
|
||||
|
||||
let boosted_relay_value = match builder_boost_factor {
|
||||
Some(builder_boost_factor) => {
|
||||
(relay_value / 100).saturating_mul(builder_boost_factor.into())
|
||||
}
|
||||
None => relay_value,
|
||||
};
|
||||
|
||||
let local_value = *local.block_value();
|
||||
|
||||
if local_value >= relay_value {
|
||||
if local_value >= boosted_relay_value {
|
||||
info!(
|
||||
self.log(),
|
||||
"Local block is more profitable than relay block";
|
||||
"local_block_value" => %local_value,
|
||||
"relay_value" => %relay_value,
|
||||
"boosted_relay_value" => %boosted_relay_value,
|
||||
"builder_boost_factor" => ?builder_boost_factor,
|
||||
);
|
||||
return Ok(ProvenancedPayload::Local(BlockProposalContentsType::Full(
|
||||
local.try_into()?,
|
||||
)));
|
||||
}
|
||||
|
||||
if local.should_override_builder().unwrap_or(false) {
|
||||
info!(
|
||||
self.log(),
|
||||
"Using local payload because execution engine suggested we ignore builder payload";
|
||||
"local_block_value" => %local_value,
|
||||
"relay_value" => %relay_value
|
||||
);
|
||||
return Ok(ProvenancedPayload::Local(BlockProposalContentsType::Full(
|
||||
@@ -1167,43 +1142,13 @@ impl<T: EthSpec> ExecutionLayer<T> {
|
||||
)));
|
||||
}
|
||||
|
||||
if relay_value < self.inner.builder_profit_threshold {
|
||||
info!(
|
||||
self.log(),
|
||||
"Builder payload ignored";
|
||||
"info" => "using local payload",
|
||||
"reason" => format!("payload value of {} does not meet user-configured profit-threshold of {}", relay_value, self.inner.builder_profit_threshold),
|
||||
"relay_block_hash" => ?header.block_hash(),
|
||||
"parent_hash" => ?parent_hash,
|
||||
);
|
||||
return Ok(ProvenancedPayload::Local(BlockProposalContentsType::Full(
|
||||
local.try_into()?,
|
||||
)));
|
||||
}
|
||||
|
||||
if local.should_override_builder().unwrap_or(false) {
|
||||
let percentage_difference =
|
||||
percentage_difference_u256(local_value, relay_value);
|
||||
if percentage_difference.map_or(false, |percentage| {
|
||||
percentage < self.inner.ignore_builder_override_suggestion_threshold
|
||||
}) {
|
||||
info!(
|
||||
self.log(),
|
||||
"Using local payload because execution engine suggested we ignore builder payload";
|
||||
"local_block_value" => %local_value,
|
||||
"relay_value" => %relay_value
|
||||
);
|
||||
return Ok(ProvenancedPayload::Local(BlockProposalContentsType::Full(
|
||||
local.try_into()?,
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
info!(
|
||||
self.log(),
|
||||
"Relay block is more profitable than local block";
|
||||
"local_block_value" => %local_value,
|
||||
"relay_value" => %relay_value
|
||||
"relay_value" => %relay_value,
|
||||
"boosted_relay_value" => %boosted_relay_value,
|
||||
"builder_boost_factor" => ?builder_boost_factor
|
||||
);
|
||||
|
||||
Ok(ProvenancedPayload::try_from(relay.data.message)?)
|
||||
@@ -2374,42 +2319,4 @@ mod test {
|
||||
})
|
||||
.await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn percentage_difference_u256_tests() {
|
||||
// ensure function returns `None` when base value is zero
|
||||
assert_eq!(percentage_difference_u256(0.into(), 1.into()), None);
|
||||
// ensure function returns `None` when either value is greater than 120 Million ETH
|
||||
let max_value = Uint256::from(12u8) * Uint256::exp10(25);
|
||||
assert_eq!(
|
||||
percentage_difference_u256(1u8.into(), max_value + Uint256::from(1u8)),
|
||||
None
|
||||
);
|
||||
assert_eq!(
|
||||
percentage_difference_u256(max_value + Uint256::from(1u8), 1u8.into()),
|
||||
None
|
||||
);
|
||||
// it should work up to max value
|
||||
assert_eq!(
|
||||
percentage_difference_u256(max_value, max_value / Uint256::from(2u8)),
|
||||
Some(-50f32)
|
||||
);
|
||||
// should work when base value is greater than comparison value
|
||||
assert_eq!(
|
||||
percentage_difference_u256(4u8.into(), 3u8.into()),
|
||||
Some(-25f32)
|
||||
);
|
||||
// should work when comparison value is greater than base value
|
||||
assert_eq!(
|
||||
percentage_difference_u256(4u8.into(), 5u8.into()),
|
||||
Some(25f32)
|
||||
);
|
||||
// should be accurate to 7 decimal places
|
||||
let result =
|
||||
percentage_difference_u256(Uint256::from(31415926u64), Uint256::from(13371337u64))
|
||||
.expect("should get percentage");
|
||||
// result = -57.4377116
|
||||
assert!(result > -57.43772);
|
||||
assert!(result <= -57.43771);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user