mirror of
https://github.com/sigp/lighthouse.git
synced 2026-05-29 20:27:14 +00:00
payload verification with commitments
This commit is contained in:
@@ -11,7 +11,6 @@ use kzg::Kzg;
|
||||
use slog::{debug, error};
|
||||
use slot_clock::SlotClock;
|
||||
use ssz_types::{Error, FixedVector, VariableList};
|
||||
use state_processing::per_block_processing::deneb::deneb::verify_kzg_commitments_against_transactions;
|
||||
use std::collections::HashSet;
|
||||
use std::sync::Arc;
|
||||
use strum::IntoStaticStr;
|
||||
@@ -21,7 +20,7 @@ use types::blob_sidecar::{BlobIdentifier, BlobSidecar, FixedBlobSidecarList};
|
||||
use types::consts::deneb::MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS;
|
||||
use types::ssz_tagged_signed_beacon_block;
|
||||
use types::{
|
||||
BeaconBlockRef, BlobSidecarList, ChainSpec, Epoch, EthSpec, ExecPayload, FullPayload, Hash256,
|
||||
BeaconBlockRef, BlobSidecarList, ChainSpec, Epoch, EthSpec, FullPayload, Hash256,
|
||||
SignedBeaconBlock, SignedBeaconBlockHeader, Slot,
|
||||
};
|
||||
|
||||
@@ -291,35 +290,20 @@ impl<T: BeaconChainTypes> DataAvailabilityChecker<T> {
|
||||
&self,
|
||||
block: &Arc<SignedBeaconBlock<T::EthSpec, FullPayload<T::EthSpec>>>,
|
||||
) -> Result<BlobRequirements, AvailabilityCheckError> {
|
||||
let verified_blobs = if let (Ok(block_kzg_commitments), Ok(payload)) = (
|
||||
block.message().body().blob_kzg_commitments(),
|
||||
block.message().body().execution_payload(),
|
||||
) {
|
||||
if let Some(transactions) = payload.transactions() {
|
||||
let verified = verify_kzg_commitments_against_transactions::<T::EthSpec>(
|
||||
transactions,
|
||||
block_kzg_commitments,
|
||||
)
|
||||
.map_err(|e| AvailabilityCheckError::TxKzgCommitmentMismatch(format!("{e:?}")))?;
|
||||
if !verified {
|
||||
return Err(AvailabilityCheckError::TxKzgCommitmentMismatch(
|
||||
"a commitment and version didn't match".to_string(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
if self.da_check_required(block.epoch()) {
|
||||
if block_kzg_commitments.is_empty() {
|
||||
BlobRequirements::EmptyBlobs
|
||||
let verified_blobs =
|
||||
if let Ok(block_kzg_commitments) = block.message().body().blob_kzg_commitments() {
|
||||
if self.da_check_required(block.epoch()) {
|
||||
if block_kzg_commitments.is_empty() {
|
||||
BlobRequirements::EmptyBlobs
|
||||
} else {
|
||||
BlobRequirements::Required
|
||||
}
|
||||
} else {
|
||||
BlobRequirements::Required
|
||||
BlobRequirements::NotRequired
|
||||
}
|
||||
} else {
|
||||
BlobRequirements::NotRequired
|
||||
}
|
||||
} else {
|
||||
BlobRequirements::PreDeneb
|
||||
};
|
||||
BlobRequirements::PreDeneb
|
||||
};
|
||||
Ok(verified_blobs)
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ use proto_array::{Block as ProtoBlock, ExecutionStatus};
|
||||
use slog::{debug, warn};
|
||||
use slot_clock::SlotClock;
|
||||
use state_processing::per_block_processing::{
|
||||
compute_timestamp_at_slot, get_expected_withdrawals, is_execution_enabled,
|
||||
self, compute_timestamp_at_slot, get_expected_withdrawals, is_execution_enabled,
|
||||
is_merge_transition_complete, partially_verify_execution_payload,
|
||||
};
|
||||
use std::sync::Arc;
|
||||
@@ -68,15 +68,16 @@ impl<T: BeaconChainTypes> PayloadNotifier<T> {
|
||||
// the block as optimistically imported. This is particularly relevant in the case
|
||||
// where we do not send the block to the EL at all.
|
||||
let block_message = block.message();
|
||||
let payload = block_message.execution_payload()?;
|
||||
partially_verify_execution_payload::<_, FullPayload<_>>(
|
||||
state,
|
||||
block.slot(),
|
||||
payload,
|
||||
block_message.body(),
|
||||
&chain.spec,
|
||||
)
|
||||
.map_err(BlockError::PerBlockProcessingError)?;
|
||||
|
||||
let payload = block_message.execution_payload()?;
|
||||
|
||||
match notify_execution_layer {
|
||||
NotifyExecutionLayer::No if chain.config.optimistic_finalized_sync => {
|
||||
// Verify the block hash here in Lighthouse and immediately mark the block as
|
||||
@@ -139,6 +140,14 @@ async fn notify_new_payload<'a, T: BeaconChainTypes>(
|
||||
block: BeaconBlockRef<'a, T::EthSpec>,
|
||||
) -> Result<PayloadVerificationStatus, BlockError<T::EthSpec>> {
|
||||
let execution_payload = block.execution_payload()?;
|
||||
let versioned_hashes = block.body().blob_kzg_commitments().ok().map(|commitments| {
|
||||
commitments
|
||||
.into_iter()
|
||||
.map(|commitment| {
|
||||
per_block_processing::deneb::deneb::kzg_commitment_to_versioned_hash(commitment)
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
});
|
||||
|
||||
let execution_layer = chain
|
||||
.execution_layer
|
||||
@@ -146,7 +155,7 @@ async fn notify_new_payload<'a, T: BeaconChainTypes>(
|
||||
.ok_or(ExecutionPayloadError::NoExecutionConnection)?;
|
||||
|
||||
let new_payload_response = execution_layer
|
||||
.notify_new_payload(&execution_payload.into())
|
||||
.notify_new_payload(&execution_payload.into(), versioned_hashes)
|
||||
.await;
|
||||
|
||||
match new_payload_response {
|
||||
|
||||
@@ -11,7 +11,7 @@ use std::collections::HashSet;
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
use std::time::{Duration, Instant};
|
||||
use types::EthSpec;
|
||||
use types::{EthSpec, VersionedHash};
|
||||
|
||||
pub use deposit_log::{DepositLog, Log};
|
||||
pub use reqwest::Client;
|
||||
@@ -808,8 +808,12 @@ impl HttpJsonRpc {
|
||||
pub async fn new_payload_v3<T: EthSpec>(
|
||||
&self,
|
||||
execution_payload: ExecutionPayload<T>,
|
||||
versioned_hashes: Vec<VersionedHash>,
|
||||
) -> Result<PayloadStatusV1, Error> {
|
||||
let params = json!([JsonExecutionPayload::from(execution_payload)]);
|
||||
let params = json!([
|
||||
JsonExecutionPayload::from(execution_payload),
|
||||
versioned_hashes
|
||||
]);
|
||||
|
||||
let response: JsonPayloadStatusV1 = self
|
||||
.rpc_request(
|
||||
@@ -1099,10 +1103,15 @@ impl HttpJsonRpc {
|
||||
pub async fn new_payload<T: EthSpec>(
|
||||
&self,
|
||||
execution_payload: ExecutionPayload<T>,
|
||||
versioned_hashes_opt: Option<Vec<VersionedHash>>,
|
||||
) -> Result<PayloadStatusV1, Error> {
|
||||
let engine_capabilities = self.get_engine_capabilities(None).await?;
|
||||
if engine_capabilities.new_payload_v3 {
|
||||
self.new_payload_v3(execution_payload).await
|
||||
let Some(versioned_hashes) = versioned_hashes_opt else {
|
||||
return Err(Error::IncorrectStateVariant);
|
||||
};
|
||||
self.new_payload_v3(execution_payload, versioned_hashes)
|
||||
.await
|
||||
} else if engine_capabilities.new_payload_v2 {
|
||||
self.new_payload_v2(execution_payload).await
|
||||
} else if engine_capabilities.new_payload_v1 {
|
||||
|
||||
@@ -1210,6 +1210,7 @@ impl<T: EthSpec> ExecutionLayer<T> {
|
||||
pub async fn notify_new_payload(
|
||||
&self,
|
||||
execution_payload: &ExecutionPayload<T>,
|
||||
versioned_hashes: Option<Vec<VersionedHash>>,
|
||||
) -> Result<PayloadStatus, Error> {
|
||||
let _timer = metrics::start_timer_vec(
|
||||
&metrics::EXECUTION_LAYER_REQUEST_TIMES,
|
||||
@@ -1226,7 +1227,11 @@ impl<T: EthSpec> ExecutionLayer<T> {
|
||||
|
||||
let result = self
|
||||
.engine()
|
||||
.request(|engine| engine.api.new_payload(execution_payload.clone()))
|
||||
.request(|engine| {
|
||||
engine
|
||||
.api
|
||||
.new_payload(execution_payload.clone(), versioned_hashes)
|
||||
})
|
||||
.await;
|
||||
|
||||
if let Ok(status) = &result {
|
||||
@@ -1237,6 +1242,8 @@ impl<T: EthSpec> ExecutionLayer<T> {
|
||||
}
|
||||
*self.inner.last_new_payload_errored.write().await = result.is_err();
|
||||
|
||||
//TODO(sean) process notify commitments updatE?
|
||||
|
||||
process_payload_status(execution_payload.block_hash(), result, self.log())
|
||||
.map_err(Box::new)
|
||||
.map_err(Error::EngineError)
|
||||
|
||||
@@ -204,7 +204,7 @@ impl<T: EthSpec> MockExecutionLayer<T> {
|
||||
Some(payload.clone())
|
||||
);
|
||||
|
||||
let status = self.el.notify_new_payload(&payload).await.unwrap();
|
||||
let status = self.el.notify_new_payload(&payload, None).await.unwrap();
|
||||
assert_eq!(status, PayloadStatus::Valid);
|
||||
|
||||
// Use junk values for slot/head-root to ensure there is no payload supplied.
|
||||
|
||||
Reference in New Issue
Block a user