mirror of
https://github.com/sigp/lighthouse.git
synced 2026-05-30 20:57:10 +00:00
Gloas payload cache (#9209)
In Gloas, beacon blocks are imported into fork choice immediately - the payload envelope and data columns arrive separately. KZG commitments moved from the column sidecar into the execution payload bid, so the existing `DataAvailabilityChecker` (which assumes block and data are coupled) can't be used for Gloas. * Introduced `PendingPayloadCache` to keep track of payload and data columns per block root. * Added gossip column verification * Added support for Gloas data column reconstruction * Payload envelope verification simplified: removed `MaybeAvailableEnvelope`, `ExecutedEnvelope`, `EnvelopeImportData` Not yet implemented (tracked with TODOs): - Proper lookup sync for Gloas columns arriving before blocks - Partial column merging for Gloas - Moving `load_gloas_payload_bid` disk reads off the async runtime - Backfill/range sync for Gloas Based on @eserilev's PR and work in progress. See also #9202 for verification. Co-Authored-By: Eitan Seri-Levi <eserilev@ucsc.edu> Co-Authored-By: Eitan Seri- Levi <eserilev@gmail.com> Co-Authored-By: Daniel Knopik <daniel@dknopik.de> Co-Authored-By: Daniel Knopik <107140945+dknopik@users.noreply.github.com> Co-Authored-By: dapplion <35266934+dapplion@users.noreply.github.com> Co-Authored-By: Jimmy Chen <jchen.tc@gmail.com>
This commit is contained in:
@@ -2851,11 +2851,42 @@ where
|
||||
.await
|
||||
.expect("newPayload should succeed");
|
||||
|
||||
// Store the envelope.
|
||||
// Store the envelope and the data columns derived from the block.
|
||||
//
|
||||
// Production stores columns inside `import_available_execution_payload_envelope` after
|
||||
// the cache is satisfied. The harness sidesteps that flow but must still persist columns
|
||||
// or the `DataColumnMissing` invariant fires for any block with `num_expected_blobs > 0`.
|
||||
let block = self
|
||||
.chain
|
||||
.store
|
||||
.get_blinded_block(&block_root)
|
||||
.expect("should read block from store")
|
||||
.expect("block should exist in store");
|
||||
let mut ops = vec![];
|
||||
let block_with_full_payload = self
|
||||
.chain
|
||||
.store
|
||||
.make_full_block(&block_root, block.clone())
|
||||
.expect("should reconstruct full block");
|
||||
let columns =
|
||||
generate_data_column_sidecars_from_block(&block_with_full_payload, &self.spec);
|
||||
if !columns.is_empty()
|
||||
&& let Some(store_op) = self.chain.get_blobs_or_columns_store_op(
|
||||
block_root,
|
||||
block.slot(),
|
||||
AvailableBlockData::DataColumns(columns),
|
||||
)
|
||||
{
|
||||
ops.push(store_op);
|
||||
}
|
||||
ops.push(store::StoreOp::PutPayloadEnvelope(
|
||||
block_root,
|
||||
std::sync::Arc::new(signed_envelope),
|
||||
));
|
||||
self.chain
|
||||
.store
|
||||
.put_payload_envelope(&block_root, &signed_envelope)
|
||||
.expect("should store envelope");
|
||||
.do_atomically_with_block_and_blobs_cache(ops)
|
||||
.expect("should persist envelope and columns");
|
||||
|
||||
// Update fork choice so it knows the payload was received.
|
||||
self.chain
|
||||
@@ -2876,11 +2907,10 @@ where
|
||||
block: Arc<SignedBeaconBlock<E>>,
|
||||
) -> RangeSyncBlock<E> {
|
||||
let block_root = block_root.unwrap_or_else(|| get_block_root(&block));
|
||||
let has_blobs = block
|
||||
.message()
|
||||
.body()
|
||||
.blob_kzg_commitments()
|
||||
.is_ok_and(|c| !c.is_empty());
|
||||
// For Gloas, kzg commitments live in the bid (`signed_execution_payload_bid`), so the
|
||||
// body's `blob_kzg_commitments()` accessor returns Err. `num_expected_blobs` already
|
||||
// handles both shapes.
|
||||
let has_blobs = block.num_expected_blobs() > 0;
|
||||
if !has_blobs {
|
||||
return RangeSyncBlock::new(
|
||||
block,
|
||||
@@ -3782,7 +3812,26 @@ pub fn generate_rand_block_and_blobs<E: EthSpec>(
|
||||
SignedBeaconBlock::Fulu(SignedBeaconBlockFulu {
|
||||
ref mut message, ..
|
||||
}) => add_blob_transactions!(message, FullPayloadFulu<E>, num_blobs, u, fork_name),
|
||||
// TODO(EIP-7732) Add `SignedBeaconBlock::Gloas` variant
|
||||
SignedBeaconBlock::Gloas(SignedBeaconBlockGloas {
|
||||
ref mut message, ..
|
||||
}) => {
|
||||
// For Gloas, commitments are in the bid, not directly in the body.
|
||||
// BlobSidecars cannot be created for Gloas because there's no merkle proof
|
||||
// from the block body to the commitments. Return early with empty blob_sidecars.
|
||||
let num_blobs = match num_blobs {
|
||||
NumBlobs::Random => u.int_in_range(DEFAULT_MIN_BLOBS..=DEFAULT_MAX_BLOBS)?,
|
||||
NumBlobs::Number(n) => n,
|
||||
NumBlobs::None => 0,
|
||||
};
|
||||
let (bundle, _transactions) =
|
||||
execution_layer::test_utils::generate_blobs::<E>(num_blobs, fork_name).unwrap();
|
||||
message
|
||||
.body
|
||||
.signed_execution_payload_bid
|
||||
.message
|
||||
.blob_kzg_commitments = bundle.commitments.clone();
|
||||
return Ok((block, blob_sidecars));
|
||||
}
|
||||
_ => return Ok((block, blob_sidecars)),
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user