Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
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,40 @@ impl<E: EthSpec> ExecutionBlockGenerator<E> {
self.blobs_bundles.get(id).cloned()
}

/// Look up a blob and proof by versioned hash across all stored bundles.
pub fn get_blob_and_proof(&self, versioned_hash: &Hash256) -> Option<BlobAndProof<E>> {
self.blobs_bundles
.iter()
.find_map(|(payload_id, blobs_bundle)| {
let (blob_idx, _) =
blobs_bundle
.commitments
.iter()
.enumerate()
.find(|(_, commitment)| {
&kzg_commitment_to_versioned_hash(commitment) == versioned_hash
})?;
let is_fulu = self.payload_ids.get(payload_id)?.fork_name().fulu_enabled();
let blob = blobs_bundle.blobs.get(blob_idx)?.clone();
if is_fulu {
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)?,
}))
}
})
}

pub fn new_payload(&mut self, payload: ExecutionPayload<E>) -> PayloadStatusV1 {
let Some(parent) = self.blocks.get(&payload.parent_hash()) else {
return PayloadStatusV1 {
Expand Down
29 changes: 29 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,35 @@ pub async fn handle_rpc<E: EthSpec>(
_ => unreachable!(),
}
}
ENGINE_GET_BLOBS_V1 => {
let versioned_hashes =
get_param::<Vec<Hash256>>(params, 0).map_err(|s| (s, BAD_PARAMS_ERROR_CODE))?;
let generator = ctx.execution_block_generator.read();
// V1: per-element nullable array, positionally matching the request.
let response: Vec<Option<BlobAndProofV1<E>>> = versioned_hashes
.iter()
.map(|hash| match generator.get_blob_and_proof(hash) {
Some(BlobAndProof::V1(v1)) => Some(v1),
_ => None,
})
.collect();
Ok(serde_json::to_value(response).unwrap())
}
ENGINE_GET_BLOBS_V2 => {
let versioned_hashes =
get_param::<Vec<Hash256>>(params, 0).map_err(|s| (s, BAD_PARAMS_ERROR_CODE))?;
let generator = ctx.execution_block_generator.read();
// V2: all-or-nothing — null if any blob is missing.
let results: Vec<Option<BlobAndProofV2<E>>> = versioned_hashes
.iter()
.map(|hash| match generator.get_blob_and_proof(hash) {
Some(BlobAndProof::V2(v2)) => Some(v2),
_ => None,
})
.collect();
let response: Option<Vec<BlobAndProofV2<E>>> = results.into_iter().collect();
Ok(serde_json::to_value(response).unwrap())
}
ENGINE_FORKCHOICE_UPDATED_V1
| ENGINE_FORKCHOICE_UPDATED_V2
| ENGINE_FORKCHOICE_UPDATED_V3 => {
Expand Down