Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions beacon_node/execution_layer/src/engine_api/json_structures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -824,6 +824,8 @@ impl<E: EthSpec> From<JsonBlobsBundleV1<E>> for BlobsBundle<E> {
)
)]
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(untagged)]
#[serde(bound = "E: EthSpec")]
pub struct BlobAndProof<E: EthSpec> {
#[serde(with = "ssz_types::serde_utils::hex_fixed_vec")]
pub blob: Blob<E>,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use crate::engine_api::{
ExecutionBlock, PayloadAttributes, PayloadId, PayloadStatusV1, PayloadStatusV1Status,
json_structures::{
JsonForkchoiceUpdatedV1Response, JsonPayloadStatusV1, JsonPayloadStatusV1Status,
BlobAndProof, BlobAndProofV1, BlobAndProofV2, JsonForkchoiceUpdatedV1Response,
JsonPayloadStatusV1, JsonPayloadStatusV1Status,
},
};
use crate::engines::ForkchoiceState;
Expand All @@ -15,6 +16,7 @@ use rand::{Rng, SeedableRng, rngs::StdRng};
use serde::{Deserialize, Serialize};
use ssz::Decode;
use ssz_types::VariableList;
use state_processing::per_block_processing::deneb::kzg_commitment_to_versioned_hash;
use std::cmp::max;
use std::collections::HashMap;
use std::sync::Arc;
Expand Down Expand Up @@ -480,6 +482,46 @@ impl<E: EthSpec> ExecutionBlockGenerator<E> {
self.blobs_bundles.get(id).cloned()
}

pub fn get_blob_and_proofs(&self, versioned_hashes: Vec<Hash256>) -> Vec<BlobAndProof<E>> {
self.blobs_bundles
.values()
// Assumes all versioned hashes are present in the same bundle; short-circuit if found.
.find_map(|blobs_bundle| {
let blobs_and_proofs: Vec<_> = blobs_bundle
.commitments
.iter()
.enumerate()
.filter(|(_, commitment)| {
let hash = kzg_commitment_to_versioned_hash(commitment);
versioned_hashes.contains(&hash)
})
.filter_map(|(blob_idx, _)| {
let is_fulu_bundle = blobs_bundle.blobs.len() < blobs_bundle.proofs.len();
let blob = blobs_bundle.blobs.get(blob_idx)?.clone();
if is_fulu_bundle {
let start = blob_idx * E::cells_per_ext_blob();
let end = start + E::cells_per_ext_blob();
let proofs = blobs_bundle
.proofs
.get(start..end)?
.to_vec()
.try_into()
.ok()?;
Some(BlobAndProof::V2(BlobAndProofV2 { blob, proofs }))
} else {
Some(BlobAndProof::V1(BlobAndProofV1 {
blob,
proof: *blobs_bundle.proofs.get(blob_idx)?,
}))
}
})
.collect();

(!blobs_and_proofs.is_empty()).then_some(blobs_and_proofs)
})
.unwrap_or_default()
}

pub fn new_payload(&mut self, payload: ExecutionPayload<E>) -> PayloadStatusV1 {
let Some(parent) = self.blocks.get(&payload.parent_hash()) else {
return PayloadStatusV1 {
Expand Down
33 changes: 33 additions & 0 deletions beacon_node/execution_layer/src/test_utils/handle_rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,39 @@ pub async fn handle_rpc<E: EthSpec>(
_ => unreachable!(),
}
}
ENGINE_GET_BLOBS_V1 | ENGINE_GET_BLOBS_V2 => {
let versioned_hashes =
get_param::<Vec<Hash256>>(params, 0).map_err(|s| (s, BAD_PARAMS_ERROR_CODE))?;
let blobs_and_proofs = ctx
.execution_block_generator
.read()
.get_blob_and_proofs(versioned_hashes);

// Validate method called correctly according to the blob and proof type,
// as the blob bundle generated is based on the fork.
if let Some(blob_and_proof) = blobs_and_proofs.first() {
match blob_and_proof {
BlobAndProof::V1(_) => {
if method == ENGINE_GET_BLOBS_V2 {
return Err((
format!("{} called before Fulu fork!", method),
FORK_REQUEST_MISMATCH_ERROR_CODE,
));
}
}
BlobAndProof::V2(_) => {
if method == ENGINE_GET_BLOBS_V1 {
return Err((
format!("{} called after Fulu fork!", method),
FORK_REQUEST_MISMATCH_ERROR_CODE,
));
}
}
}
}

Ok(serde_json::to_value(blobs_and_proofs).unwrap())
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this return Vec<Option<...>>? To set the missing blobs to null

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch — fixed in the latest push. V1 now returns Vec<Option<BlobAndProofV1>> with nulls at positions of missing hashes, and V2 returns Option<Vec<BlobAndProofV2>> (null if any blob is missing), per the execution-apis spec.

}
ENGINE_FORKCHOICE_UPDATED_V1
| ENGINE_FORKCHOICE_UPDATED_V2
| ENGINE_FORKCHOICE_UPDATED_V3 => {
Expand Down