payload verification with commitments

This commit is contained in:
realbigsean
2023-06-07 14:29:39 -04:00
parent 6970f7a19f
commit 5d73a9bdde
12 changed files with 94 additions and 1147 deletions

View File

@@ -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)
}

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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)

View File

@@ -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.