Skip to content
Merged
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
3 changes: 2 additions & 1 deletion crates/beacon_api/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use silver_common::{
MAX_BLOB_COMMITMENTS_PER_BLOCK, MAX_COMMITTEES_PER_SLOT, MAX_PAYLOAD_SIZE,
MAX_REQUEST_BLOCKS_DENEB, MAX_VALIDATORS_PER_COMMITTEE, NUMBER_OF_COLUMNS,
},
ticker::MAXIMUM_GOSSIP_CLOCK_DISPARITY,
};

use crate::json::Json;
Expand Down Expand Up @@ -192,7 +193,7 @@ const NETWORK_CONFIG: &[(&str, u64)] = &[
("EPOCHS_PER_SUBNET_SUBSCRIPTION", EPOCHS_PER_SUBNET_SUBSCRIPTION),
("MIN_EPOCHS_FOR_BLOCK_REQUESTS", 33_024),
("ATTESTATION_PROPAGATION_SLOT_RANGE", 32),
("MAXIMUM_GOSSIP_CLOCK_DISPARITY", 500),
("MAXIMUM_GOSSIP_CLOCK_DISPARITY", MAXIMUM_GOSSIP_CLOCK_DISPARITY.as_millis() as u64),
("SUBNETS_PER_NODE", SUBNETS_PER_NODE as u64),
("ATTESTATION_SUBNET_COUNT", 64),
("ATTESTATION_SUBNET_EXTRA_BITS", 0),
Expand Down
10 changes: 10 additions & 0 deletions crates/beacon_state/data/src/beacon_block_body.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,16 @@ impl<'a> BodyOffsets<'a> {
)
.unwrap_or(&[])
}

#[inline]
pub fn blob_commitments_fulu(&self) -> &'a [u8] {
self.slice(
BeaconBlockBodyFuluView::blob_kzg_commitments_offset(self.body),
BeaconBlockBodyFuluView::execution_requests_offset(self.body),
)
.unwrap_or(&[])
}

#[inline]
pub fn execution_requests(&self) -> &'a [u8] {
self.slice(
Expand Down
17 changes: 10 additions & 7 deletions crates/beacon_state/data/src/column/roots.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,16 @@ impl RootsView<'_, BlockRoots> {
self.get(slot as usize % SLOTS_PER_HISTORICAL_ROOT)
}

/// Whether the ring holds `root` at or below `from_slot`. Fork choice is
/// what writes a root here, so membership means "seen and validated".
/// Walks most-recent-first: a queried parent is virtually always a slot or
/// two back, while a miss costs the whole ring either way.
pub fn contains(&self, root: &B256, from_slot: Slot) -> bool {
(0..SLOTS_PER_HISTORICAL_ROOT as u64)
.any(|back| self.at_slot(from_slot.saturating_sub(back)) == *root)
/// Slot of the block with `root`, if the ring holds it at or below
/// `from_slot`. Fork choice is what writes a root here, so a hit means
/// "seen and validated".
pub fn slot_of(&self, root: &B256, from_slot: Slot) -> Option<Slot> {
let oldest = from_slot.saturating_sub(SLOTS_PER_HISTORICAL_ROOT as u64 - 1);
let mut slot = (oldest..=from_slot).rev().find(|&s| self.at_slot(s) == *root)?;
while slot > oldest && self.at_slot(slot - 1) == *root {
slot -= 1;
}
Some(slot)
}
}

Expand Down
23 changes: 15 additions & 8 deletions crates/beacon_state/data/src/column/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -433,22 +433,29 @@ fn block_roots_ring_wraps_and_hashes_as_a_vector() {
assert_eq!(wv.hash_root(), hash_b256_vector(&expected));
}

/// `contains` walks back from `from_slot`, so it sees every written bucket but
/// nothing written above the slot it is asked about.
/// `slot_of` walks back from `from_slot`, so it sees every written bucket but
/// nothing written above the slot it is asked about. A block at slot 100
/// followed by two empty slots occupies buckets 100..=102, and the slot
/// reported is the block's own.
#[test]
fn block_roots_contains_scans_back_from_the_given_slot() {
fn block_roots_slot_of_scans_back_from_the_given_slot() {
let mut g = BlockRootsGroup::zeroed_vector();
let id = {
let mut wv = g.roll_fresh();
wv.set(100, [0xAA; 32]);
wv.set(101, [0xBB; 32]);
wv.set(99, [0x99; 32]);
for slot in 100..=102 {
wv.set(slot, [0xAA; 32]);
}
wv.set(103, [0xBB; 32]);
wv.commit()
};
let reader = g.view(id);

assert!(reader.contains(&[0xAA; 32], 101));
assert!(reader.contains(&[0xBB; 32], 101));
assert!(!reader.contains(&[0xCC; 32], 101));
assert_eq!(reader.slot_of(&[0xAA; 32], 103), Some(100));
assert_eq!(reader.slot_of(&[0xAA; 32], 101), Some(100));
assert_eq!(reader.slot_of(&[0xBB; 32], 103), Some(103));
assert_eq!(reader.slot_of(&[0xBB; 32], 102), None, "written above the asked slot");
assert_eq!(reader.slot_of(&[0xCC; 32], 103), None);
}

/// A block's reveal accumulates into the current epoch's bucket; the boundary
Expand Down
32 changes: 23 additions & 9 deletions crates/beacon_state/tile/src/error.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use silver_beacon_state_data::{B256, BLSPubkey, BlockBodyError, Epoch, Slot};
use silver_beacon_state_data::{B256, BLSPubkey, BlockBodyError, Slot};
use thiserror::Error;

use crate::tile::Feedback;
Expand All @@ -19,16 +19,16 @@ pub enum PrecheckError {
b256_hex(block_root)
)]
ParentInvalid { parent_root: B256, block_root: B256 },
#[error("past block: block_epoch={block_epoch} finalized_epoch={finalized_epoch}")]
PreFinalized { block_epoch: Epoch, finalized_epoch: Epoch },
#[error("past block: block_slot={block_slot} finalized_slot={finalized_slot}")]
PreFinalized { block_slot: Slot, finalized_slot: Slot },
#[error("block body is not canonical SSZ: block_slot={block_slot} body_len={body_len}")]
NonCanonicalBody { block_slot: Slot, body_len: usize },
#[error("block past-slot precheck failed: block_slot={block_slot} parent_slot={parent_slot}")]
PastSlot { block_slot: Slot, parent_slot: Slot },
#[error("block already imported: block_root=0x{}", b256_hex(block_root))]
AlreadyKnown { block_root: B256 },
#[error(
"block ticker slot precheck failed: block_slot={block_slot} ticker={wall_slot_plus_one}"
)]
FutureSlot { block_slot: Slot, wall_slot_plus_one: Slot },
#[error("block ticker slot precheck failed: block_slot={block_slot} wall_slot={wall_slot}")]
FutureSlot { block_slot: Slot, wall_slot: Slot },
#[error(
"block proposer lookahead precheck failed: expected={expected} got={got} \
block_root=0x{}",
Expand All @@ -47,14 +47,26 @@ pub enum PrecheckError {
b256_hex(block_root)
)]
UnverifiedParentPayload { parent_root: B256, block_root: B256 },
#[error(
"block execution payload timestamp precheck failed: expected={expected} got={got} \
block_root=0x{}",
b256_hex(block_root)
)]
PayloadTimestamp { expected: u64, got: u64, block_root: B256 },
#[error(
"block blob commitment count precheck failed: got={got} max={max} \
block_root=0x{}",
b256_hex(block_root)
)]
TooManyCommitments { got: usize, max: usize, block_root: B256 },
#[error("invalid block signature: block_root=0x{}", b256_hex(block_root))]
InvalidSignature { block_root: B256 },
}

impl PrecheckError {
pub fn feedback(self) -> Feedback {
match self {
Self::SizeMismatch { .. } => Feedback::Reject(None),
Self::SizeMismatch { .. } | Self::NonCanonicalBody { .. } => Feedback::Reject(None),
Self::ParentMissing { parent_root, block_root, .. } => {
Feedback::RequestParent { parent_root, block_root }
}
Expand All @@ -67,7 +79,9 @@ impl PrecheckError {
}
Self::ParentInvalid { block_root, .. } |
Self::ProposerLookaheadMismatch { block_root, .. } |
Self::ProposerIndexTooBig { block_root, .. } => Feedback::Reject(Some(block_root)),
Self::ProposerIndexTooBig { block_root, .. } |
Self::PayloadTimestamp { block_root, .. } |
Self::TooManyCommitments { block_root, .. } => Feedback::Reject(Some(block_root)),
Self::InvalidSignature { block_root } => Feedback::Reject(Some(block_root)),
}
}
Expand Down
8 changes: 3 additions & 5 deletions crates/beacon_state/tile/src/tile.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::{fmt::Debug, sync::Arc, time::Duration};
use std::{fmt::Debug, sync::Arc};

use flux::{
spine::{FluxSpine, SpineAdapter, SpineProducers},
Expand All @@ -14,7 +14,7 @@ use silver_common::{
NewGossipMsg, Origin, ReplayBlock, RequestId, RpcInbound, RpcResponse, RpcResponseInbound,
SilverSpine, SyncUpdate, TRandomAccess, TRead, hex32,
ssz_view::{MAX_ATTESTATIONS_ELECTRA, MAX_ATTESTING_INDICES, STATUS_V2_SIZE},
ticker::{SlotTicker, TickEvent},
ticker::{MAXIMUM_GOSSIP_CLOCK_DISPARITY, SlotTicker, TickEvent},
};
use silver_config::{PendingBounds, SyncingConfig};

Expand Down Expand Up @@ -45,9 +45,6 @@ mod seen_validators;
mod shuffling_cache;
mod sync_contribution_pool;

/// Consensus-spec clock-skew allowance for slot-scoped gossip validation.
const MAXIMUM_GOSSIP_CLOCK_DISPARITY: Duration = Duration::from_millis(500);

#[derive(Clone, Copy, PartialEq, Eq)]
pub enum Feedback {
Accept(Option<B256>),
Expand Down Expand Up @@ -111,6 +108,7 @@ struct ParsedBlock {
parent_state_id: StateId,
is_gloas: bool,
parent_payload_status: PayloadStatus,
relay_eligible: bool,
}

pub struct BeaconStateTile {
Expand Down
Loading
Loading