Don't use the builder network if the head is optimistic (#3412)

## Issue Addressed

Resolves https://github.com/sigp/lighthouse/issues/3394

Adds a check in `is_healthy` about whether the head is optimistic when choosing whether to use the builder network. 



Co-authored-by: realbigsean <sean@sigmaprime.io>
This commit is contained in:
realbigsean 2022-08-09 06:05:16 +00:00
parent 5bb4aada92
commit 6f13727fbe
3 changed files with 74 additions and 2 deletions

View File

@ -3333,7 +3333,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
pubkey, pubkey,
slot: state.slot(), slot: state.slot(),
chain_health: self chain_health: self
.is_healthy() .is_healthy(&parent_root)
.map_err(BlockProductionError::BeaconChain)?, .map_err(BlockProductionError::BeaconChain)?,
}; };
@ -4562,7 +4562,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
/// ///
/// Since we are likely calling this during the slot we are going to propose in, don't take into /// Since we are likely calling this during the slot we are going to propose in, don't take into
/// account the current slot when accounting for skips. /// account the current slot when accounting for skips.
pub fn is_healthy(&self) -> Result<ChainHealth, Error> { pub fn is_healthy(&self, parent_root: &Hash256) -> Result<ChainHealth, Error> {
// Check if the merge has been finalized. // Check if the merge has been finalized.
if let Some(finalized_hash) = self if let Some(finalized_hash) = self
.canonical_head .canonical_head
@ -4577,6 +4577,17 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
return Ok(ChainHealth::PreMerge); return Ok(ChainHealth::PreMerge);
}; };
// Check that the parent is NOT optimistic.
if let Some(execution_status) = self
.canonical_head
.fork_choice_read_lock()
.get_block_execution_status(parent_root)
{
if execution_status.is_strictly_optimistic() {
return Ok(ChainHealth::Optimistic);
}
}
if self.config.builder_fallback_disable_checks { if self.config.builder_fallback_disable_checks {
return Ok(ChainHealth::Healthy); return Ok(ChainHealth::Healthy);
} }

View File

@ -114,6 +114,7 @@ pub struct BuilderParams {
pub enum ChainHealth { pub enum ChainHealth {
Healthy, Healthy,
Unhealthy(FailedCondition), Unhealthy(FailedCondition),
Optimistic,
PreMerge, PreMerge,
} }
@ -695,6 +696,9 @@ impl<T: EthSpec> ExecutionLayer<T> {
} }
// Intentional no-op, so we never attempt builder API proposals pre-merge. // Intentional no-op, so we never attempt builder API proposals pre-merge.
ChainHealth::PreMerge => (), ChainHealth::PreMerge => (),
ChainHealth::Optimistic => info!(self.log(), "The local execution engine is syncing \
so the builder network cannot safely be used. Attempting \
to build a block with the local execution engine"),
} }
} }
self.get_full_payload_caching( self.get_full_payload_caching(

View File

@ -3044,6 +3044,55 @@ impl ApiTester {
self self
} }
pub async fn test_builder_chain_health_optimistic_head(self) -> Self {
// Make sure the next payload verification will return optimistic before advancing the chain.
self.harness.mock_execution_layer.as_ref().map(|el| {
el.server.all_payloads_syncing(true);
el
});
self.harness
.extend_chain(
1,
BlockStrategy::OnCanonicalHead,
AttestationStrategy::AllValidators,
)
.await;
self.harness.advance_slot();
let slot = self.chain.slot().unwrap();
let epoch = self.chain.epoch().unwrap();
let (proposer_index, randao_reveal) = self.get_test_randao(slot, epoch).await;
let payload = self
.client
.get_validator_blinded_blocks::<E, BlindedPayload<E>>(slot, &randao_reveal, None)
.await
.unwrap()
.data
.body()
.execution_payload()
.unwrap()
.clone();
let expected_fee_recipient = Address::from_low_u64_be(proposer_index as u64);
assert_eq!(
payload.execution_payload_header.fee_recipient,
expected_fee_recipient
);
// If this cache is populated, it indicates fallback to the local EE was correctly used.
assert!(self
.chain
.execution_layer
.as_ref()
.unwrap()
.get_payload_by_root(&payload.tree_hash_root())
.is_some());
self
}
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
pub async fn test_get_lighthouse_health(self) -> Self { pub async fn test_get_lighthouse_health(self) -> Self {
self.client.get_lighthouse_health().await.unwrap(); self.client.get_lighthouse_health().await.unwrap();
@ -4000,6 +4049,14 @@ async fn builder_chain_health_epochs_since_finalization() {
.await; .await;
} }
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn builder_chain_health_optimistic_head() {
ApiTester::new_mev_tester()
.await
.test_builder_chain_health_optimistic_head()
.await;
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)] #[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn lighthouse_endpoints() { async fn lighthouse_endpoints() {
ApiTester::new() ApiTester::new()