Add getBlobsV1 and getBlobsV2 support to mock EL server (#8870)

Co-Authored-By: Jimmy Chen <jchen.tc@gmail.com>
This commit is contained in:
Jimmy Chen
2026-02-25 23:17:49 +11:00
committed by GitHub
parent d6bf53834f
commit a1ef265c9e
2 changed files with 66 additions and 1 deletions

View File

@@ -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;
@@ -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;
@@ -456,6 +458,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 {

View File

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