Skip to content
Open
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
eda918d
Batch verify builder deposit signatures
pawanjay176 May 15, 2026
ed15ac6
Refactor `onboard_builders_from_pending_deposits` based on new spec
pawanjay176 May 15, 2026
369eecd
Add a builder onboarding cache
pawanjay176 May 15, 2026
112b093
Working wiring with pre-gloas cache
pawanjay176 May 16, 2026
0aa7d7a
More threading
pawanjay176 May 16, 2026
5e46d38
Clean up threading with a GloasVerificationContext
pawanjay176 May 17, 2026
18bcc24
Add a hashmap for keeping track of added builders
pawanjay176 May 17, 2026
826a521
Update onboarding cache size
pawanjay176 May 17, 2026
49410fa
Add better docs
pawanjay176 May 17, 2026
e2e8406
fmt
pawanjay176 May 17, 2026
9738905
lint
pawanjay176 May 17, 2026
fd43fdc
Cleanup
pawanjay176 May 18, 2026
44dcf5d
Fix lint
pawanjay176 May 19, 2026
bc1a156
Call initialize_ptc in all cases and rename variant
pawanjay176 May 19, 2026
50cd378
Use spawn_blocking_with_rayon for batch signature verification tasks
pawanjay176 May 19, 2026
16f615e
Review comments
pawanjay176 May 19, 2026
33bccd0
Add unit tests
pawanjay176 May 19, 2026
f89c099
Remove SkipBuilderOnboarding variant and thread the onboard builder c…
pawanjay176 May 19, 2026
de89987
Add more tests
pawanjay176 May 19, 2026
70b8594
Optimise by not iterating through the state.builders list for every i…
pawanjay176 May 21, 2026
ecbb7e7
Only onboard state deposits before gloas
pawanjay176 May 22, 2026
656e70a
Fix consensus bugs and add test
pawanjay176 May 22, 2026
31b6f3d
Merge branch 'unstable' into builder-deposits-optimisation
pawanjay176 May 23, 2026
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 Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

25 changes: 23 additions & 2 deletions beacon_node/beacon_chain/src/beacon_chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,9 @@ use slasher::Slasher;
use slot_clock::SlotClock;
use ssz::Encode;
use state_processing::{
BlockSignatureStrategy, ConsensusContext, SigVerifiedOp, VerifyBlockRoot, VerifyOperation,
BlockSignatureStrategy, ConsensusContext, GloasVerificationContext, SigVerifiedOp,
VerifyBlockRoot, VerifyOperation,
builder_deposits_cache::OnboardBuildersCache,
common::get_attesting_indices_from_state,
epoch_cache::initialize_epoch_cache,
per_block_processing,
Expand Down Expand Up @@ -510,6 +512,9 @@ pub struct BeaconChain<T: BeaconChainTypes> {
pub pending_payload_cache: Arc<PendingPayloadCache<T>>,
/// The KZG trusted setup used by this chain.
pub kzg: Arc<Kzg>,
/// Pre-validates builder deposit signatures.
/// Only required when gloas is enabled.
pub builder_onboarding_cache: Option<Arc<OnboardBuildersCache>>,
/// RNG instance used by the chain. Currently used for shuffling column sidecars in block publishing.
pub rng: Arc<Mutex<Box<dyn RngCore + Send>>>,
}
Expand Down Expand Up @@ -1513,7 +1518,12 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
while state.slot() < slot {
// Note: supplying some `state_root` when it is known would be a cheap and easy
// optimization.
match per_slot_processing(&mut state, skip_state_root, &self.spec) {
match per_slot_processing(
&mut state,
skip_state_root,
GloasVerificationContext::from_cache(self.builder_onboarding_cache.clone()),
&self.spec,
) {
Ok(_) => (),
Err(e) => {
warn!(
Expand Down Expand Up @@ -4536,6 +4546,15 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
current_slot,
);

if let Some(builder_onboarding_cache) = &self.builder_onboarding_cache {
let cache = builder_onboarding_cache.clone();
let spec = self.spec.clone();
self.task_executor.spawn_blocking(
move || cache.add_new_pending_deposits::<T::EthSpec>(&state, &spec),
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Is this pretty much a no-op after the fork?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

yeah it is. Hadn't considered it. can potentially only do this for pre-gloas states and then delete it post gloas

"pre_verify_deposits",
);
}

Ok(block_root)
}

Expand Down Expand Up @@ -5188,6 +5207,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
apply_parent_execution_payload(
&mut advanced_state,
&envelope.message.execution_requests,
self.builder_onboarding_cache.as_deref(),
&self.spec,
)
.map_err(Error::PrepareProposerFailed)?;
Expand Down Expand Up @@ -6191,6 +6211,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
signature_strategy,
VerifyBlockRoot::True,
&mut ctxt,
self.builder_onboarding_cache.as_deref(),
&self.spec,
)?;
drop(process_timer);
Expand Down
2 changes: 2 additions & 0 deletions beacon_node/beacon_chain/src/block_production/gloas.rs
Original file line number Diff line number Diff line change
Expand Up @@ -619,6 +619,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
signature_strategy,
VerifyBlockRoot::True,
&mut ctxt,
self.builder_onboarding_cache.as_deref(),
&self.spec,
)?;
drop(process_timer);
Expand Down Expand Up @@ -965,6 +966,7 @@ fn get_execution_payload_gloas<T: BeaconChainTypes>(
apply_parent_execution_payload(
&mut withdrawals_state,
&envelope.message.execution_requests,
chain.builder_onboarding_cache.as_deref(),
spec,
)?;
Withdrawals::<T::EthSpec>::from(get_expected_withdrawals(&withdrawals_state, spec)?)
Expand Down
12 changes: 9 additions & 3 deletions beacon_node/beacon_chain/src/block_verification.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,8 @@ use ssz::Encode;
use ssz_derive::{Decode, Encode};
use state_processing::per_block_processing::errors::IntoWithIndex;
use state_processing::{
AllCaches, BlockProcessingError, BlockSignatureStrategy, ConsensusContext, SlotProcessingError,
VerifyBlockRoot,
AllCaches, BlockProcessingError, BlockSignatureStrategy, ConsensusContext,
GloasVerificationContext, SlotProcessingError, VerifyBlockRoot,
block_signature_verifier::{BlockSignatureVerifier, Error as BlockSignatureVerifierError},
per_block_processing, per_slot_processing,
state_advance::partial_state_advance,
Expand Down Expand Up @@ -1542,7 +1542,12 @@ impl<T: BeaconChainTypes> ExecutionPendingBlock<T> {
state_root
};

if let Some(summary) = per_slot_processing(&mut state, Some(state_root), &chain.spec)? {
if let Some(summary) = per_slot_processing(
&mut state,
Some(state_root),
GloasVerificationContext::from_cache(chain.builder_onboarding_cache.clone()),
&chain.spec,
)? {
// Expose Prometheus metrics.
if let Err(e) = summary.observe_metrics() {
error!(
Expand Down Expand Up @@ -1611,6 +1616,7 @@ impl<T: BeaconChainTypes> ExecutionPendingBlock<T> {
BlockSignatureStrategy::NoVerification,
VerifyBlockRoot::True,
&mut consensus_context,
chain.builder_onboarding_cache.as_deref(),
&chain.spec,
) {
match err {
Expand Down
23 changes: 20 additions & 3 deletions beacon_node/beacon_chain/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,9 @@ use rayon::prelude::*;
use slasher::Slasher;
use slot_clock::{SlotClock, TestingSlotClock};
use state_processing::AllCaches;
use state_processing::builder_deposits_cache::OnboardBuildersCache;
use state_processing::genesis::genesis_block;
use state_processing::per_slot_processing;
use state_processing::{GloasVerificationContext, per_slot_processing};
use std::marker::PhantomData;
use std::sync::Arc;
use std::time::Duration;
Expand Down Expand Up @@ -445,8 +446,13 @@ where
"Advancing checkpoint state to boundary"
);
while weak_subj_state.slot() % slots_per_epoch != 0 {
per_slot_processing(&mut weak_subj_state, None, &self.spec)
.map_err(|e| format!("Error advancing state: {e:?}"))?;
per_slot_processing(
&mut weak_subj_state,
None,
GloasVerificationContext::FullVerification,
&self.spec,
)
.map_err(|e| format!("Error advancing state: {e:?}"))?;
}
}

Expand Down Expand Up @@ -1084,6 +1090,7 @@ where
rng: Arc::new(Mutex::new(rng)),
gossip_verified_payload_bid_cache: <_>::default(),
gossip_verified_proposer_preferences_cache: <_>::default(),
builder_onboarding_cache: OnboardBuildersCache::new(&self.spec).map(Arc::new),
};

let head = beacon_chain.head_snapshot();
Expand Down Expand Up @@ -1155,6 +1162,16 @@ where
.process_prune_blobs(data_availability_boundary);
}

// Seed the builder onboarding cache in the background from the current head state.
if let Some(onboarding_cache) = &beacon_chain.builder_onboarding_cache {
let cache = onboarding_cache.clone();
let spec = self.spec.clone();
beacon_chain.task_executor.spawn_blocking(
move || cache.seed_from_state(&head.beacon_state, &spec),
"initialize_builder_onboarding_cache",
);
}

Ok(beacon_chain)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,21 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
);
}

// Pre-verify builder deposit signatures while awaiting EL verification.
if let Some(ref cache) = self.builder_onboarding_cache {
let cache = cache.clone();
let deposits = unverified_envelope
.signed_envelope
.message
.execution_requests
.deposits
.clone();
let spec = self.spec.clone();
self.task_executor.spawn_blocking(
move || cache.cache_deposit_requests(&deposits, &spec),
"pre_verify_builder_deposits",
);
}
// TODO(gloas) insert the pre-executed envelope into some type of cache?

let _full_timer = metrics::start_timer(&metrics::ENVELOPE_PROCESSING_TIMES);
Expand Down
12 changes: 8 additions & 4 deletions beacon_node/beacon_chain/src/state_advance_timer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use crate::{
BeaconChain, BeaconChainError, BeaconChainTypes, chain_config::FORK_CHOICE_LOOKAHEAD_FACTOR,
};
use slot_clock::SlotClock;
use state_processing::per_slot_processing;
use state_processing::{GloasVerificationContext, per_slot_processing};
use std::sync::{
Arc,
atomic::{AtomicBool, Ordering},
Expand Down Expand Up @@ -286,9 +286,13 @@ fn advance_head<T: BeaconChainTypes>(beacon_chain: &Arc<BeaconChain<T>>) -> Resu
let initial_epoch = state.current_epoch();

// Advance the state a single slot.
if let Some(summary) =
per_slot_processing(&mut state, Some(head_state_root), &beacon_chain.spec)
.map_err(BeaconChainError::from)?
if let Some(summary) = per_slot_processing(
&mut state,
Some(head_state_root),
GloasVerificationContext::from_cache(beacon_chain.builder_onboarding_cache.clone()),
&beacon_chain.spec,
)
.map_err(BeaconChainError::from)?
{
// Expose Prometheus metrics.
if let Err(e) = summary.observe_metrics() {
Expand Down
1 change: 1 addition & 0 deletions beacon_node/beacon_chain/src/test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1425,6 +1425,7 @@ where
BlockSignatureStrategy::NoVerification,
VerifyBlockRoot::False,
&mut ctxt,
None,
&self.spec,
)
.unwrap_or_else(|e| panic!("per_block_processing failed at slot {}: {e:?}", slot));
Expand Down
26 changes: 22 additions & 4 deletions beacon_node/beacon_chain/tests/attestation_verification.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use fixed_bytes::FixedBytesExtended;
use genesis::{DEFAULT_ETH1_BLOCK_HASH, interop_genesis_state};
use int_to_bytes::int_to_bytes32;
use slasher::{Config as SlasherConfig, Slasher};
use state_processing::per_slot_processing;
use state_processing::{GloasVerificationContext, per_slot_processing};
use std::sync::{Arc, LazyLock};
use tempfile::tempdir;
use tree_hash::TreeHash;
Expand Down Expand Up @@ -1217,7 +1217,13 @@ async fn attestation_that_skips_epochs() {
.expect("should find state");

while state.slot() < current_slot {
per_slot_processing(&mut state, None, &harness.spec).expect("should process slot");
per_slot_processing(
&mut state,
None,
GloasVerificationContext::FullVerification,
&harness.spec,
)
.expect("should process slot");
}

let state_root = state.update_tree_hash_cache().unwrap();
Expand Down Expand Up @@ -1328,7 +1334,13 @@ async fn attestation_validator_receive_proposer_reward_and_withdrawals() {
.expect("should find state");

while state.slot() < current_slot {
per_slot_processing(&mut state, None, &harness.spec).expect("should process slot");
per_slot_processing(
&mut state,
None,
GloasVerificationContext::FullVerification,
&harness.spec,
)
.expect("should process slot");
}

let state_root = state.update_tree_hash_cache().unwrap();
Expand Down Expand Up @@ -1405,7 +1417,13 @@ async fn attestation_to_finalized_block() {
.expect("should find state");

while state.slot() < current_slot {
per_slot_processing(&mut state, None, &harness.spec).expect("should process slot");
per_slot_processing(
&mut state,
None,
GloasVerificationContext::FullVerification,
&harness.spec,
)
.expect("should process slot");
}

let state_root = state.update_tree_hash_cache().unwrap();
Expand Down
21 changes: 18 additions & 3 deletions beacon_node/beacon_chain/tests/block_verification.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ use fixed_bytes::FixedBytesExtended;
use logging::create_test_tracing_subscriber;
use slasher::{Config as SlasherConfig, Slasher};
use state_processing::{
BlockProcessingError, BlockSignatureStrategy, ConsensusContext, VerifyBlockRoot,
BlockProcessingError, BlockSignatureStrategy, ConsensusContext, GloasVerificationContext,
VerifyBlockRoot,
common::{attesting_indices_base, attesting_indices_electra},
per_block_processing, per_slot_processing,
};
Expand Down Expand Up @@ -1696,14 +1697,21 @@ async fn add_base_block_to_altair_chain() {
{
let mut state = state;
let mut ctxt = ConsensusContext::new(base_block.slot());
per_slot_processing(&mut state, None, &harness.chain.spec).unwrap();
per_slot_processing(
&mut state,
None,
GloasVerificationContext::FullVerification,
&harness.chain.spec,
)
.unwrap();
assert!(matches!(
per_block_processing(
&mut state,
&base_block,
BlockSignatureStrategy::NoVerification,
VerifyBlockRoot::True,
&mut ctxt,
None,
&harness.chain.spec,
),
Err(BlockProcessingError::InconsistentBlockFork(
Expand Down Expand Up @@ -1847,14 +1855,21 @@ async fn add_altair_block_to_base_chain() {
{
let mut state = state;
let mut ctxt = ConsensusContext::new(altair_block.slot());
per_slot_processing(&mut state, None, &harness.chain.spec).unwrap();
per_slot_processing(
&mut state,
None,
GloasVerificationContext::FullVerification,
&harness.chain.spec,
)
.unwrap();
assert!(matches!(
per_block_processing(
&mut state,
&altair_block,
BlockSignatureStrategy::NoVerification,
VerifyBlockRoot::True,
&mut ctxt,
None,
&harness.chain.spec,
),
Err(BlockProcessingError::InconsistentBlockFork(
Expand Down
2 changes: 2 additions & 0 deletions beacon_node/beacon_chain/tests/prepare_payload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,7 @@ async fn prepare_payload_generic(
apply_parent_execution_payload(
&mut unadvanced_full_state,
&envelope.message.execution_requests,
None,
&spec,
)
.unwrap();
Expand All @@ -245,6 +246,7 @@ async fn prepare_payload_generic(
apply_parent_execution_payload(
&mut advanced_full_state,
&envelope.message.execution_requests,
None,
&spec,
)
.unwrap();
Expand Down
12 changes: 10 additions & 2 deletions beacon_node/beacon_chain/tests/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@ use beacon_chain::{
use bls::Keypair;
use operation_pool::PersistedOperationPool;
use state_processing::EpochProcessingError;
use state_processing::{per_slot_processing, per_slot_processing::Error as SlotProcessingError};
use state_processing::{
GloasVerificationContext, per_slot_processing,
per_slot_processing::Error as SlotProcessingError,
};
use std::sync::LazyLock;
use types::{
BeaconState, BeaconStateError, BlockImportSource, ChainSpec, Checkpoint,
Expand Down Expand Up @@ -107,7 +110,12 @@ fn massive_skips() {

// Run per_slot_processing until it returns an error.
let error = loop {
match per_slot_processing(&mut state, None, spec) {
match per_slot_processing(
&mut state,
None,
GloasVerificationContext::FullVerification,
spec,
) {
Ok(_) => continue,
Err(e) => break e,
}
Expand Down
Loading
Loading