feat: add EIP-4788 parent_beacon_block_root to Header (#4299)

This commit is contained in:
Dan Cline
2023-08-29 10:55:13 -07:00
committed by GitHub
parent 4a2c1691fc
commit 0c7a93717a
16 changed files with 189 additions and 94 deletions

View File

@ -277,6 +277,7 @@ impl StorageInner {
blob_gas_used: None,
excess_blob_gas: None,
extra_data: Default::default(),
parent_beacon_block_root: None,
};
header.transactions_root = if transactions.is_empty() {

View File

@ -5,6 +5,7 @@ use crate::{
BeaconForkChoiceUpdateError, BeaconOnNewPayloadError,
};
use futures::TryFutureExt;
use reth_primitives::H256;
use reth_rpc_types::engine::{
ExecutionPayload, ForkchoiceState, ForkchoiceUpdated, PayloadAttributes, PayloadStatus,
};
@ -34,9 +35,14 @@ impl BeaconConsensusEngineHandle {
pub async fn new_payload(
&self,
payload: ExecutionPayload,
parent_beacon_block_root: Option<H256>,
) -> Result<PayloadStatus, BeaconOnNewPayloadError> {
let (tx, rx) = oneshot::channel();
let _ = self.to_engine.send(BeaconEngineMessage::NewPayload { payload, tx });
let _ = self.to_engine.send(BeaconEngineMessage::NewPayload {
payload,
parent_beacon_block_root,
tx,
});
rx.await.map_err(|_| BeaconOnNewPayloadError::EngineUnavailable)?
}

View File

@ -5,6 +5,7 @@ use crate::{
use futures::{future::Either, FutureExt};
use reth_interfaces::consensus::ForkchoiceState;
use reth_payload_builder::error::PayloadBuilderError;
use reth_primitives::H256;
use reth_rpc_types::engine::{
ExecutionPayload, ForkChoiceUpdateResult, ForkchoiceUpdateError, ForkchoiceUpdated,
PayloadAttributes, PayloadId, PayloadStatus, PayloadStatusEnum,
@ -146,6 +147,8 @@ pub enum BeaconEngineMessage {
NewPayload {
/// The execution payload received by Engine API.
payload: ExecutionPayload,
/// The parent beacon block root, if any.
parent_beacon_block_root: Option<H256>,
/// The sender for returning payload status result.
tx: oneshot::Sender<Result<PayloadStatus, BeaconOnNewPayloadError>>,
},

View File

@ -1049,12 +1049,13 @@ where
///
/// This returns a [`PayloadStatus`] that represents the outcome of a processed new payload and
/// returns an error if an internal error occurred.
#[instrument(level = "trace", skip(self, payload), fields(block_hash= ?payload.block_hash, block_number = %payload.block_number.as_u64(), is_pipeline_idle = %self.sync.is_pipeline_idle()), target = "consensus::engine")]
#[instrument(level = "trace", skip(self, payload, parent_beacon_block_root), fields(block_hash= ?payload.block_hash, block_number = %payload.block_number.as_u64(), is_pipeline_idle = %self.sync.is_pipeline_idle()), target = "consensus::engine")]
fn on_new_payload(
&mut self,
payload: ExecutionPayload,
parent_beacon_block_root: Option<H256>,
) -> Result<PayloadStatus, BeaconOnNewPayloadError> {
let block = match self.ensure_well_formed_payload(payload) {
let block = match self.ensure_well_formed_payload(payload, parent_beacon_block_root) {
Ok(block) => block,
Err(status) => return Ok(status),
};
@ -1118,9 +1119,10 @@ where
fn ensure_well_formed_payload(
&self,
payload: ExecutionPayload,
parent_beacon_block_root: Option<H256>,
) -> Result<SealedBlock, PayloadStatus> {
let parent_hash = payload.parent_hash;
let block = match SealedBlock::try_from(payload) {
let block = match payload.try_into_sealed_block(parent_beacon_block_root) {
Ok(block) => block,
Err(error) => {
error!(target: "consensus::engine", ?error, "Invalid payload");
@ -1725,9 +1727,9 @@ where
}
}
}
BeaconEngineMessage::NewPayload { payload, tx } => {
BeaconEngineMessage::NewPayload { payload, parent_beacon_block_root, tx } => {
this.metrics.new_payload_messages.increment(1);
let res = this.on_new_payload(payload);
let res = this.on_new_payload(payload, parent_beacon_block_root);
let _ = tx.send(res);
}
BeaconEngineMessage::TransitionConfigurationExchanged => {
@ -1865,7 +1867,7 @@ mod tests {
assert_matches!(rx.try_recv(), Err(TryRecvError::Empty));
// consensus engine is still idle because no FCUs were received
let _ = env.send_new_payload(SealedBlock::default().into()).await;
let _ = env.send_new_payload(SealedBlock::default().into(), None).await;
assert_matches!(rx.try_recv(), Err(TryRecvError::Empty));
// consensus engine is still idle because pruning is running
@ -2279,14 +2281,16 @@ mod tests {
let mut engine_rx = spawn_consensus_engine(consensus_engine);
// Send new payload
let res =
env.send_new_payload(random_block(&mut rng, 0, None, None, Some(0)).into()).await;
let res = env
.send_new_payload(random_block(&mut rng, 0, None, None, Some(0)).into(), None)
.await;
// Invalid, because this is a genesis block
assert_matches!(res, Ok(result) => assert_matches!(result.status, PayloadStatusEnum::Invalid { .. }));
// Send new payload
let res =
env.send_new_payload(random_block(&mut rng, 1, None, None, Some(0)).into()).await;
let res = env
.send_new_payload(random_block(&mut rng, 1, None, None, Some(0)).into(), None)
.await;
let expected_result = PayloadStatus::from_status(PayloadStatusEnum::Syncing);
assert_matches!(res, Ok(result) => assert_eq!(result, expected_result));
@ -2336,7 +2340,7 @@ mod tests {
// Send new payload
let result =
env.send_new_payload_retry_on_syncing(block2.clone().into()).await.unwrap();
env.send_new_payload_retry_on_syncing(block2.clone().into(), None).await.unwrap();
let expected_result = PayloadStatus::from_status(PayloadStatusEnum::Valid)
.with_latest_valid_hash(block2.hash);
assert_eq!(result, expected_result);
@ -2434,7 +2438,7 @@ mod tests {
// Send new payload
let block = random_block(&mut rng, 2, Some(H256::random()), None, Some(0));
let res = env.send_new_payload(block.into()).await;
let res = env.send_new_payload(block.into(), None).await;
let expected_result = PayloadStatus::from_status(PayloadStatusEnum::Syncing);
assert_matches!(res, Ok(result) => assert_eq!(result, expected_result));
@ -2497,7 +2501,7 @@ mod tests {
// Send new payload
let result =
env.send_new_payload_retry_on_syncing(block2.clone().into()).await.unwrap();
env.send_new_payload_retry_on_syncing(block2.clone().into(), None).await.unwrap();
let expected_result = PayloadStatus::from_status(PayloadStatusEnum::Invalid {
validation_error: BlockValidationError::BlockPreMerge { hash: block2.hash }

View File

@ -69,8 +69,9 @@ impl<DB> TestEnv<DB> {
pub async fn send_new_payload(
&self,
payload: ExecutionPayload,
parent_beacon_block_root: Option<H256>,
) -> Result<PayloadStatus, BeaconOnNewPayloadError> {
self.engine_handle.new_payload(payload).await
self.engine_handle.new_payload(payload, parent_beacon_block_root).await
}
/// Sends the `ExecutionPayload` message to the consensus engine and retries if the engine
@ -78,9 +79,10 @@ impl<DB> TestEnv<DB> {
pub async fn send_new_payload_retry_on_syncing(
&self,
payload: ExecutionPayload,
parent_beacon_block_root: Option<H256>,
) -> Result<PayloadStatus, BeaconOnNewPayloadError> {
loop {
let result = self.send_new_payload(payload.clone()).await?;
let result = self.send_new_payload(payload.clone(), parent_beacon_block_root).await?;
if !result.is_syncing() {
return Ok(result)
}

View File

@ -50,6 +50,8 @@ pub fn validate_header_standalone(
return Err(ConsensusError::BlobGasUsedUnexpected)
} else if header.excess_blob_gas.is_some() {
return Err(ConsensusError::ExcessBlobGasUnexpected)
} else if header.parent_beacon_block_root.is_some() {
return Err(ConsensusError::ParentBeaconBlockRootUnexpected)
}
Ok(())
@ -451,6 +453,7 @@ pub fn validate_4844_header_with_parent(
///
/// * `blob_gas_used` exists as a header field
/// * `excess_blob_gas` exists as a header field
/// * `parent_beacon_block_root` exists as a header field
/// * `blob_gas_used` is less than or equal to `MAX_DATA_GAS_PER_BLOCK`
/// * `blob_gas_used` is a multiple of `DATA_GAS_PER_BLOB`
pub fn validate_4844_header_standalone(header: &SealedHeader) -> Result<(), ConsensusError> {
@ -460,6 +463,10 @@ pub fn validate_4844_header_standalone(header: &SealedHeader) -> Result<(), Cons
return Err(ConsensusError::ExcessBlobGasMissing)
}
if header.parent_beacon_block_root.is_none() {
return Err(ConsensusError::ParentBeaconBlockRootMissing)
}
if blob_gas_used > MAX_DATA_GAS_PER_BLOCK {
return Err(ConsensusError::BlobGasUsedExceedsMaxBlobGasPerBlock {
blob_gas_used,
@ -633,6 +640,7 @@ mod tests {
withdrawals_root: None,
blob_gas_used: None,
excess_blob_gas: None,
parent_beacon_block_root: None,
};
// size: 0x9b5