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
2 changes: 2 additions & 0 deletions crates/beacon_state/tile/src/bls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ pub const DOMAIN_VOLUNTARY_EXIT: u32 = 0x0000_0004;
pub const DOMAIN_SELECTION_PROOF: u32 = 0x0000_0005;
pub const DOMAIN_AGGREGATE_AND_PROOF: u32 = 0x0000_0006;
pub const DOMAIN_SYNC_COMMITTEE: u32 = 0x0000_0007;
pub const DOMAIN_SYNC_COMMITTEE_SELECTION_PROOF: u32 = 0x0000_0008;
pub const DOMAIN_CONTRIBUTION_AND_PROOF: u32 = 0x0000_0009;
pub const DOMAIN_BLS_TO_EXECUTION_CHANGE: u32 = 0x0000_000a;
// Gloas
pub const DOMAIN_BEACON_BUILDER: u32 = 0x0000_000b;
Expand Down
14 changes: 9 additions & 5 deletions crates/beacon_state/tile/src/counters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,14 @@ silver_common::declare_counters! {
// aggregates inflate Miss without ever becoming votes.
AttestationRootMemoHit,
AttestationRootMemoMiss,
// gossip-attestation batching: size of the latest flush (gauge) and
// batch-verify failures that fell back to per-attestation verifies
// (non-zero = someone is feeding us invalid signatures).
AttestationBatchSize,
AttestationBatchFallback,
// gossip vote batching (attestations + sync messages + PTC): size of
// the latest flush (gauge) and batch-verify failures that fell back
// to per-message verifies (non-zero = someone is feeding us invalid
// signatures).
VoteBatchSize,
VoteBatchFallback,
// Valid sync messages are still accepted and relayed when this is
// full; only creation of a local contribution is skipped.
SyncContributionPoolFull,
}
}
23 changes: 20 additions & 3 deletions crates/beacon_state/tile/src/fork_choice/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,23 @@ impl PtcVotes {
}
}

#[inline]
pub(super) fn record_mask(&mut self, positions: &[u64; 8], present: bool, da: bool) {
for (word, &positions) in self.voted.iter_mut().zip(positions) {
*word |= positions;
}
if present {
for (word, &positions) in self.present.iter_mut().zip(positions) {
*word |= positions;
}
}
if da {
for (word, &positions) in self.da.iter_mut().zip(positions) {
*word |= positions;
}
}
}

#[inline]
pub(super) fn present_count(&self) -> usize {
popcount(&self.present)
Expand All @@ -116,18 +133,18 @@ impl PtcVotes {
popcount(&self.da)
}

#[cfg(feature = "ef_tests")]
#[cfg(any(test, feature = "ef_tests"))]
pub(super) fn timeliness(&self) -> [Option<bool>; PTC_SIZE] {
self.optional(&self.present)
}

/// Data-availability votes (see `timeliness`).
#[cfg(feature = "ef_tests")]
#[cfg(any(test, feature = "ef_tests"))]
pub(super) fn availability(&self) -> [Option<bool>; PTC_SIZE] {
self.optional(&self.da)
}

#[cfg(feature = "ef_tests")]
#[cfg(any(test, feature = "ef_tests"))]
fn optional(&self, value: &[u64; 8]) -> [Option<bool>; PTC_SIZE] {
let mut out = [None; PTC_SIZE];
for (i, slot) in out.iter_mut().enumerate() {
Expand Down
18 changes: 16 additions & 2 deletions crates/beacon_state/tile/src/fork_choice/payload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,15 +106,29 @@ impl ForkChoice {
self.head_moved = true;
}

#[cfg(feature = "ef_tests")]
pub fn record_ptc_votes(
&mut self,
block_root: &B256,
positions: &[u64; PTC_SIZE / 64],
present: bool,
da: bool,
) {
let Some(idx) = self.find_node_idx(block_root) else {
return;
};
self.nodes[idx].ptc.record_mask(positions, present, da);
self.head_moved = true;
}

#[cfg(any(test, feature = "ef_tests"))]
pub fn ptc_timeliness_votes(&self, block_root: &B256) -> [Option<bool>; PTC_SIZE] {
match self.find_node_idx(block_root) {
Some(idx) => self.nodes[idx].ptc.timeliness(),
None => [None; PTC_SIZE],
}
}

#[cfg(feature = "ef_tests")]
#[cfg(any(test, feature = "ef_tests"))]
pub fn ptc_data_availability_votes(&self, block_root: &B256) -> [Option<bool>; PTC_SIZE] {
match self.find_node_idx(block_root) {
Some(idx) => self.nodes[idx].ptc.availability(),
Expand Down
34 changes: 34 additions & 0 deletions crates/beacon_state/tile/src/ssz_hash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,40 @@ pub fn hash_tree_root_block_header(hdr: &BeaconBlockHeader) -> B256 {
merkleize(&chunks)
}

pub fn hash_tree_root_sync_contribution(
slot: u64,
beacon_block_root: &B256,
subcommittee_index: u64,
aggregation_bits: &[u8; 16],
signature: &[u8; 96],
) -> B256 {
let mut bits_chunk = [0u8; 32];
bits_chunk[..16].copy_from_slice(aggregation_bits);
merkleize(&[
uint64_chunk(slot),
*beacon_block_root,
uint64_chunk(subcommittee_index),
bits_chunk,
hash_fixed_bytes(signature),
])
}

pub fn hash_tree_root_contribution_and_proof(
aggregator_index: u64,
contribution_root: &B256,
selection_proof: &[u8; 96],
) -> B256 {
merkleize(&[
uint64_chunk(aggregator_index),
*contribution_root,
hash_fixed_bytes(selection_proof),
])
}

pub fn hash_tree_root_sync_selection_data(slot: u64, subcommittee_index: u64) -> B256 {
hash_concat(&uint64_chunk(slot), &uint64_chunk(subcommittee_index))
}

pub fn hash_checkpoint(cp: &Checkpoint) -> B256 {
hash_concat(&uint64_chunk(cp.epoch), &cp.root)
}
Expand Down
1 change: 1 addition & 0 deletions crates/beacon_state/tile/src/stf/gloas/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,6 @@ pub use committee::process_ptc_window;
pub(crate) use committee::{fill_epoch_ptc, get_ptc};
pub use envelope::verify_execution_payload_envelope;
pub use parent_payload::process_parent_execution_payload;
pub(crate) use payload_attestation::hash_payload_attestation_data;
pub use payload_attestation::{collect_sigs_payload_attestations, process_payload_attestations};
pub use withdrawals::process_withdrawals as process_withdrawals_gloas;
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ fn collect_sigs_payload_attestation(
Ok(())
}

fn hash_payload_attestation_data(data: &[u8; 42]) -> silver_beacon_state_data::B256 {
pub(crate) fn hash_payload_attestation_data(data: &[u8; 42]) -> silver_beacon_state_data::B256 {
let bool_chunk = |b: u8| {
let mut c = [0u8; 32];
c[0] = b;
Expand Down
2 changes: 1 addition & 1 deletion crates/beacon_state/tile/src/stf/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,14 @@ pub use epoch::{
};
pub use epoch_shuffling::{EpochShuffling, ShufflingRef};
pub use fork_transition::upgrade_to_gloas;
pub(crate) use gloas::get_ptc;
pub use gloas::{
collect_sigs_execution_payload_bid, collect_sigs_payload_attestations,
get_builder_payment_quorum_threshold, process_builder_deposit_request,
process_builder_exit_request, process_builder_pending_payments, process_execution_payload_bid,
process_parent_execution_payload, process_payload_attestations, process_ptc_window,
process_withdrawals_gloas, verify_execution_payload_envelope,
};
pub(crate) use gloas::{get_ptc, hash_payload_attestation_data};
pub(crate) use operations::process_execution_requests;
pub use operations::{
collect_sigs_bls_to_execution_changes, collect_sigs_voluntary_exits,
Expand Down
119 changes: 115 additions & 4 deletions crates/beacon_state/tile/src/test_signing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ use silver_beacon_state_data::{
B256, BLSPubkey, BeaconBlockHeader, Fork, Immutable, SLOTS_PER_EPOCH,
};
use silver_common::ssz_view::{
ATTESTATION_FIXED, AttestationView, IndexedAttestationView, PROPOSER_SLASHING_SIZE,
ProposerSlashingView, SIGNED_AGG_PROOF_MIN, SIGNED_BLS_CHANGE_SIZE, SIGNED_VOLUNTARY_EXIT_SIZE,
SINGLE_ATT_SIZE, SignedAggregateAndProofView, SignedBlsToExecutionChangeView,
SignedVoluntaryExitView, SingleAttestationView,
ATTESTATION_FIXED, AttestationView, IndexedAttestationView, PAYLOAD_ATTESTATION_MESSAGE_SIZE,
PROPOSER_SLASHING_SIZE, ProposerSlashingView, SIGNED_AGG_PROOF_MIN, SIGNED_BLS_CHANGE_SIZE,
SIGNED_VOLUNTARY_EXIT_SIZE, SINGLE_ATT_SIZE, SignedAggregateAndProofView,
SignedBlsToExecutionChangeView, SignedVoluntaryExitView, SingleAttestationView,
};

use crate::{
Expand Down Expand Up @@ -264,6 +264,117 @@ pub fn resign_single_attestation(sk_idx: usize, buf: &mut [u8; SINGLE_ATT_SIZE],
debug_assert_eq!(SingleAttestationView::signature(buf), &sig);
}

pub fn sign_sync_committee_message(
sk_idx: usize,
vi: u64,
slot: u64,
beacon_block_root: B256,
imm: &Immutable,
) -> [u8; 144] {
let mut buf = [0u8; 144];
buf[0..8].copy_from_slice(&slot.to_le_bytes());
buf[8..40].copy_from_slice(&beacon_block_root);
buf[40..48].copy_from_slice(&vi.to_le_bytes());

let fv = test_fork_version(slot / SLOTS_PER_EPOCH);
let domain = bls::compute_domain(bls::DOMAIN_SYNC_COMMITTEE, fv, &imm.genesis_validators_root);
let sig = sign(sk_idx, &bls::compute_signing_root(&beacon_block_root, &domain));
buf[48..144].copy_from_slice(&sig);
buf
}

pub fn sign_payload_attestation_message(
sk_idx: usize,
validator_index: u64,
slot: u64,
beacon_block_root: B256,
payload_present: u8,
blob_data_available: u8,
imm: &Immutable,
) -> [u8; PAYLOAD_ATTESTATION_MESSAGE_SIZE] {
let mut buf = [0u8; PAYLOAD_ATTESTATION_MESSAGE_SIZE];
buf[0..8].copy_from_slice(&validator_index.to_le_bytes());
buf[8..40].copy_from_slice(&beacon_block_root);
buf[40..48].copy_from_slice(&slot.to_le_bytes());
buf[48] = payload_present;
buf[49] = blob_data_available;

let data: &[u8; 42] = (&buf[8..50]).try_into().unwrap();
let fv = test_fork_version(slot / SLOTS_PER_EPOCH);
let domain = bls::compute_domain(bls::DOMAIN_PTC_ATTESTER, fv, &imm.genesis_validators_root);
let signing_root =
bls::compute_signing_root(&crate::stf::hash_payload_attestation_data(data), &domain);
let signature = sign(sk_idx, &signing_root);
buf[50..146].copy_from_slice(&signature);
buf
}

pub fn sync_selection_proof(
sk_idx: usize,
slot: u64,
subcommittee: u64,
imm: &Immutable,
) -> [u8; 96] {
let fv = test_fork_version(slot / SLOTS_PER_EPOCH);
let domain = bls::compute_domain(
bls::DOMAIN_SYNC_COMMITTEE_SELECTION_PROOF,
fv,
&imm.genesis_validators_root,
);
let root = ssz_hash::hash_tree_root_sync_selection_data(slot, subcommittee);
sign(sk_idx, &bls::compute_signing_root(&root, &domain))
}

pub fn sign_contribution_and_proof(
sk_agg: usize,
aggregator_index: u64,
slot: u64,
subcommittee: u64,
participant_pos: usize,
sk_part: usize,
beacon_block_root: B256,
imm: &Immutable,
) -> [u8; 360] {
let fv = test_fork_version(slot / SLOTS_PER_EPOCH);
let domain = |ty| bls::compute_domain(ty, fv, &imm.genesis_validators_root);

let mut bits = [0u8; 16];
bits[participant_pos / 8] |= 1 << (participant_pos % 8);
let contrib_sig = sign(
sk_part,
&bls::compute_signing_root(&beacon_block_root, &domain(bls::DOMAIN_SYNC_COMMITTEE)),
);
let selection_proof = sync_selection_proof(sk_agg, slot, subcommittee, imm);

let contribution_root = ssz_hash::hash_tree_root_sync_contribution(
slot,
&beacon_block_root,
subcommittee,
&bits,
&contrib_sig,
);
let cap_root = ssz_hash::hash_tree_root_contribution_and_proof(
aggregator_index,
&contribution_root,
&selection_proof,
);
let outer = sign(
sk_agg,
&bls::compute_signing_root(&cap_root, &domain(bls::DOMAIN_CONTRIBUTION_AND_PROOF)),
);

let mut buf = [0u8; 360];
buf[0..8].copy_from_slice(&aggregator_index.to_le_bytes());
buf[8..16].copy_from_slice(&slot.to_le_bytes());
buf[16..48].copy_from_slice(&beacon_block_root);
buf[48..56].copy_from_slice(&subcommittee.to_le_bytes());
buf[56..72].copy_from_slice(&bits);
buf[72..168].copy_from_slice(&contrib_sig);
buf[168..264].copy_from_slice(&selection_proof);
buf[264..360].copy_from_slice(&outer);
buf
}

/// Build a single-signer `Attestation`: `committee_index` is the (single)
/// bit in `committee_bits`; the bit at `participant_pos` is the only set bit
/// in `aggregation_bits` — that participant signs the aggregate.
Expand Down
Loading
Loading