mirror of
https://github.com/sigp/lighthouse.git
synced 2026-03-06 10:11:44 +00:00
Retrospective invalidation of exec. payloads for opt. sync (#2837)
## Issue Addressed
NA
## Proposed Changes
Adds the functionality to allow blocks to be validated/invalidated after their import as per the [optimistic sync spec](https://github.com/ethereum/consensus-specs/blob/dev/sync/optimistic.md#how-to-optimistically-import-blocks). This means:
- Updating `ProtoArray` to allow flipping the `execution_status` of ancestors/descendants based on payload validity updates.
- Creating separation between `execution_layer` and the `beacon_chain` by creating a `PayloadStatus` struct.
- Refactoring how the `execution_layer` selects a `PayloadStatus` from the multiple statuses returned from multiple EEs.
- Adding testing framework for optimistic imports.
- Add `ExecutionBlockHash(Hash256)` new-type struct to avoid confusion between *beacon block roots* and *execution payload hashes*.
- Add `merge` to [`FORKS`](c3a793fd73/Makefile (L17)) in the `Makefile` to ensure we test the beacon chain with merge settings.
- Fix some tests here that were failing due to a missing execution layer.
## TODO
- [ ] Balance tests
Co-authored-by: Mark Mackey <mark@sigmaprime.io>
This commit is contained in:
@@ -1,10 +1,10 @@
|
||||
use crate::execution_engine::{ExecutionEngine, GenericExecutionEngine};
|
||||
use execution_layer::{ExecutionLayer, PayloadAttributes, PayloadStatusV1Status};
|
||||
use execution_layer::{ExecutionLayer, PayloadAttributes, PayloadStatus};
|
||||
use std::sync::Arc;
|
||||
use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
|
||||
use task_executor::TaskExecutor;
|
||||
use tokio::time::sleep;
|
||||
use types::{Address, ChainSpec, EthSpec, Hash256, MainnetEthSpec, Uint256};
|
||||
use types::{Address, ChainSpec, EthSpec, ExecutionBlockHash, Hash256, MainnetEthSpec, Uint256};
|
||||
|
||||
const EXECUTION_ENGINE_START_TIMEOUT: Duration = Duration::from_secs(10);
|
||||
|
||||
@@ -139,7 +139,7 @@ impl<E: GenericExecutionEngine> TestRig<E> {
|
||||
let parent_hash = terminal_pow_block_hash;
|
||||
let timestamp = timestamp_now();
|
||||
let random = Hash256::zero();
|
||||
let finalized_block_hash = Hash256::zero();
|
||||
let finalized_block_hash = ExecutionBlockHash::zero();
|
||||
let proposer_index = 0;
|
||||
let valid_payload = self
|
||||
.ee_a
|
||||
@@ -161,15 +161,15 @@ impl<E: GenericExecutionEngine> TestRig<E> {
|
||||
* `notify_new_payload`.
|
||||
*/
|
||||
let head_block_hash = valid_payload.block_hash;
|
||||
let finalized_block_hash = Hash256::zero();
|
||||
let finalized_block_hash = ExecutionBlockHash::zero();
|
||||
let payload_attributes = None;
|
||||
let (status, _) = self
|
||||
let status = self
|
||||
.ee_a
|
||||
.execution_layer
|
||||
.notify_forkchoice_updated(head_block_hash, finalized_block_hash, payload_attributes)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(status, PayloadStatusV1Status::Syncing);
|
||||
assert_eq!(status, PayloadStatus::Syncing);
|
||||
|
||||
/*
|
||||
* Execution Engine A:
|
||||
@@ -177,13 +177,13 @@ impl<E: GenericExecutionEngine> TestRig<E> {
|
||||
* Provide the valid payload back to the EE again.
|
||||
*/
|
||||
|
||||
let (status, _) = self
|
||||
let status = self
|
||||
.ee_a
|
||||
.execution_layer
|
||||
.notify_new_payload(&valid_payload)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(status, PayloadStatusV1Status::Valid);
|
||||
assert_eq!(status, PayloadStatus::Valid);
|
||||
|
||||
/*
|
||||
* Execution Engine A:
|
||||
@@ -193,15 +193,15 @@ impl<E: GenericExecutionEngine> TestRig<E> {
|
||||
* Do not provide payload attributes (we'll test that later).
|
||||
*/
|
||||
let head_block_hash = valid_payload.block_hash;
|
||||
let finalized_block_hash = Hash256::zero();
|
||||
let finalized_block_hash = ExecutionBlockHash::zero();
|
||||
let payload_attributes = None;
|
||||
let (status, _) = self
|
||||
let status = self
|
||||
.ee_a
|
||||
.execution_layer
|
||||
.notify_forkchoice_updated(head_block_hash, finalized_block_hash, payload_attributes)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(status, PayloadStatusV1Status::Valid);
|
||||
assert_eq!(status, PayloadStatus::Valid);
|
||||
|
||||
/*
|
||||
* Execution Engine A:
|
||||
@@ -211,16 +211,13 @@ impl<E: GenericExecutionEngine> TestRig<E> {
|
||||
|
||||
let mut invalid_payload = valid_payload.clone();
|
||||
invalid_payload.random = Hash256::from_low_u64_be(42);
|
||||
let (status, _) = self
|
||||
let status = self
|
||||
.ee_a
|
||||
.execution_layer
|
||||
.notify_new_payload(&invalid_payload)
|
||||
.await
|
||||
.unwrap();
|
||||
assert!(matches!(
|
||||
status,
|
||||
PayloadStatusV1Status::Invalid | PayloadStatusV1Status::InvalidBlockHash
|
||||
));
|
||||
assert!(matches!(status, PayloadStatus::InvalidBlockHash { .. }));
|
||||
|
||||
/*
|
||||
* Execution Engine A:
|
||||
@@ -231,7 +228,7 @@ impl<E: GenericExecutionEngine> TestRig<E> {
|
||||
let parent_hash = valid_payload.block_hash;
|
||||
let timestamp = valid_payload.timestamp + 1;
|
||||
let random = Hash256::zero();
|
||||
let finalized_block_hash = Hash256::zero();
|
||||
let finalized_block_hash = ExecutionBlockHash::zero();
|
||||
let proposer_index = 0;
|
||||
let second_payload = self
|
||||
.ee_a
|
||||
@@ -252,13 +249,13 @@ impl<E: GenericExecutionEngine> TestRig<E> {
|
||||
* Provide the second payload back to the EE again.
|
||||
*/
|
||||
|
||||
let (status, _) = self
|
||||
let status = self
|
||||
.ee_a
|
||||
.execution_layer
|
||||
.notify_new_payload(&second_payload)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(status, PayloadStatusV1Status::Valid);
|
||||
assert_eq!(status, PayloadStatus::Valid);
|
||||
|
||||
/*
|
||||
* Execution Engine A:
|
||||
@@ -266,32 +263,32 @@ impl<E: GenericExecutionEngine> TestRig<E> {
|
||||
* Indicate that the payload is the head of the chain, providing payload attributes.
|
||||
*/
|
||||
let head_block_hash = valid_payload.block_hash;
|
||||
let finalized_block_hash = Hash256::zero();
|
||||
let finalized_block_hash = ExecutionBlockHash::zero();
|
||||
let payload_attributes = Some(PayloadAttributes {
|
||||
timestamp: second_payload.timestamp + 1,
|
||||
random: Hash256::zero(),
|
||||
suggested_fee_recipient: Address::zero(),
|
||||
});
|
||||
let (status, _) = self
|
||||
let status = self
|
||||
.ee_a
|
||||
.execution_layer
|
||||
.notify_forkchoice_updated(head_block_hash, finalized_block_hash, payload_attributes)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(status, PayloadStatusV1Status::Valid);
|
||||
assert_eq!(status, PayloadStatus::Valid);
|
||||
|
||||
/*
|
||||
* Execution Engine B:
|
||||
*
|
||||
* Provide the second payload, without providing the first.
|
||||
*/
|
||||
let (status, _) = self
|
||||
let status = self
|
||||
.ee_b
|
||||
.execution_layer
|
||||
.notify_new_payload(&second_payload)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(status, PayloadStatusV1Status::Syncing);
|
||||
assert_eq!(status, PayloadStatus::Accepted);
|
||||
|
||||
/*
|
||||
* Execution Engine B:
|
||||
@@ -299,15 +296,15 @@ impl<E: GenericExecutionEngine> TestRig<E> {
|
||||
* Set the second payload as the head, without providing payload attributes.
|
||||
*/
|
||||
let head_block_hash = second_payload.block_hash;
|
||||
let finalized_block_hash = Hash256::zero();
|
||||
let finalized_block_hash = ExecutionBlockHash::zero();
|
||||
let payload_attributes = None;
|
||||
let (status, _) = self
|
||||
let status = self
|
||||
.ee_b
|
||||
.execution_layer
|
||||
.notify_forkchoice_updated(head_block_hash, finalized_block_hash, payload_attributes)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(status, PayloadStatusV1Status::Syncing);
|
||||
assert_eq!(status, PayloadStatus::Syncing);
|
||||
|
||||
/*
|
||||
* Execution Engine B:
|
||||
@@ -315,26 +312,26 @@ impl<E: GenericExecutionEngine> TestRig<E> {
|
||||
* Provide the first payload to the EE.
|
||||
*/
|
||||
|
||||
let (status, _) = self
|
||||
let status = self
|
||||
.ee_b
|
||||
.execution_layer
|
||||
.notify_new_payload(&valid_payload)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(status, PayloadStatusV1Status::Valid);
|
||||
assert_eq!(status, PayloadStatus::Valid);
|
||||
|
||||
/*
|
||||
* Execution Engine B:
|
||||
*
|
||||
* Provide the second payload, now the first has been provided.
|
||||
*/
|
||||
let (status, _) = self
|
||||
let status = self
|
||||
.ee_b
|
||||
.execution_layer
|
||||
.notify_new_payload(&second_payload)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(status, PayloadStatusV1Status::Valid);
|
||||
assert_eq!(status, PayloadStatus::Valid);
|
||||
|
||||
/*
|
||||
* Execution Engine B:
|
||||
@@ -342,15 +339,15 @@ impl<E: GenericExecutionEngine> TestRig<E> {
|
||||
* Set the second payload as the head, without providing payload attributes.
|
||||
*/
|
||||
let head_block_hash = second_payload.block_hash;
|
||||
let finalized_block_hash = Hash256::zero();
|
||||
let finalized_block_hash = ExecutionBlockHash::zero();
|
||||
let payload_attributes = None;
|
||||
let (status, _) = self
|
||||
let status = self
|
||||
.ee_b
|
||||
.execution_layer
|
||||
.notify_forkchoice_updated(head_block_hash, finalized_block_hash, payload_attributes)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(status, PayloadStatusV1Status::Valid);
|
||||
assert_eq!(status, PayloadStatus::Valid);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user