mirror of
https://github.com/sigp/lighthouse.git
synced 2026-05-30 04:37:13 +00:00
Merge branch 'unstable' of https://github.com/sigp/lighthouse into gloas-parent-envelope-unknown-lookup
This commit is contained in:
@@ -1351,7 +1351,7 @@ where
|
||||
let ptc_indices: Vec<usize> = attestation
|
||||
.attesting_indices
|
||||
.iter()
|
||||
.filter_map(|vi| ptc.iter().position(|&p| p == *vi as usize))
|
||||
.filter_map(|validator_index| ptc.iter().position(|&p| p == *validator_index as usize))
|
||||
.collect();
|
||||
|
||||
// Check that all the attesters are in the PTC
|
||||
|
||||
@@ -8,6 +8,7 @@ use crate::per_block_processing::builder::{
|
||||
convert_validator_index_to_builder_index, is_builder_index,
|
||||
};
|
||||
use crate::per_block_processing::errors::{BlockProcessingError, ExitInvalid, IntoWithIndex};
|
||||
use crate::per_block_processing::signature_sets::{exit_signature_set, get_pubkey_from_state};
|
||||
use crate::per_block_processing::verify_payload_attestation::verify_payload_attestation;
|
||||
use bls::{PublicKeyBytes, SignatureBytes};
|
||||
use ssz_types::FixedVector;
|
||||
@@ -547,7 +548,8 @@ fn process_builder_voluntary_exit<E: EthSpec>(
|
||||
let builder_index =
|
||||
convert_validator_index_to_builder_index(signed_exit.message.validator_index);
|
||||
|
||||
let builder = state
|
||||
// Verify builder is known
|
||||
state
|
||||
.builders()?
|
||||
.get(builder_index as usize)
|
||||
.cloned()
|
||||
@@ -570,22 +572,17 @@ fn process_builder_voluntary_exit<E: EthSpec>(
|
||||
));
|
||||
}
|
||||
|
||||
// Verify signature (using EIP-7044 domain: capella_fork_version for Deneb+)
|
||||
if verify_signatures.is_true() {
|
||||
let pubkey = builder.pubkey;
|
||||
let domain = spec.compute_domain(
|
||||
Domain::VoluntaryExit,
|
||||
spec.capella_fork_version,
|
||||
state.genesis_validators_root(),
|
||||
verify!(
|
||||
exit_signature_set(
|
||||
state,
|
||||
|i| get_pubkey_from_state(state, i),
|
||||
signed_exit,
|
||||
spec
|
||||
)?
|
||||
.verify(),
|
||||
ExitInvalid::BadSignature
|
||||
);
|
||||
let message = signed_exit.message.signing_root(domain);
|
||||
// TODO(gloas): use builder pubkey cache once available
|
||||
let bls_pubkey = pubkey
|
||||
.decompress()
|
||||
.map_err(|_| BlockOperationError::invalid(ExitInvalid::BadSignature))?;
|
||||
if !signed_exit.signature.verify(&bls_pubkey, message) {
|
||||
return Err(BlockOperationError::invalid(ExitInvalid::BadSignature));
|
||||
}
|
||||
}
|
||||
|
||||
// Initiate builder exit
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
//! validated individually, or alongside in others in a potentially cheaper bulk operation.
|
||||
//!
|
||||
//! This module exposes one function to extract each type of `SignatureSet` from a `BeaconBlock`.
|
||||
use super::builder::{convert_validator_index_to_builder_index, is_builder_index};
|
||||
use bls::{AggregateSignature, PublicKey, PublicKeyBytes, Signature, SignatureSet};
|
||||
use ssz::DecodeError;
|
||||
use std::borrow::Cow;
|
||||
@@ -503,7 +504,7 @@ pub fn deposit_pubkey_signature_message(
|
||||
}
|
||||
|
||||
/// Returns a signature set that is valid if the `SignedVoluntaryExit` was signed by the indicated
|
||||
/// validator.
|
||||
/// validator (or builder, in the case of a builder exit).
|
||||
pub fn exit_signature_set<'a, E, F>(
|
||||
state: &'a BeaconState<E>,
|
||||
get_pubkey: F,
|
||||
@@ -515,7 +516,18 @@ where
|
||||
F: Fn(usize) -> Option<Cow<'a, PublicKey>>,
|
||||
{
|
||||
let exit = &signed_exit.message;
|
||||
let proposer_index = exit.validator_index as usize;
|
||||
let validator_index = exit.validator_index;
|
||||
|
||||
let is_builder_exit =
|
||||
state.fork_name_unchecked().gloas_enabled() && is_builder_index(validator_index);
|
||||
|
||||
let pubkey = if is_builder_exit {
|
||||
let builder_index = convert_validator_index_to_builder_index(validator_index);
|
||||
get_builder_pubkey_from_state(state, builder_index)
|
||||
.ok_or(Error::ValidatorUnknown(validator_index))?
|
||||
} else {
|
||||
get_pubkey(validator_index as usize).ok_or(Error::ValidatorUnknown(validator_index))?
|
||||
};
|
||||
|
||||
let domain = if state.fork_name_unchecked().deneb_enabled() {
|
||||
// EIP-7044
|
||||
@@ -537,7 +549,7 @@ where
|
||||
|
||||
Ok(SignatureSet::single_pubkey(
|
||||
&signed_exit.signature,
|
||||
get_pubkey(proposer_index).ok_or(Error::ValidatorUnknown(proposer_index as u64))?,
|
||||
pubkey,
|
||||
message,
|
||||
))
|
||||
}
|
||||
|
||||
@@ -102,6 +102,7 @@ impl<E: EthSpec> Hash for Attestation<E> {
|
||||
|
||||
impl<E: EthSpec> Attestation<E> {
|
||||
/// Produces an attestation with empty signature.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn empty_for_signing(
|
||||
committee_index: u64,
|
||||
committee_length: usize,
|
||||
@@ -109,6 +110,7 @@ impl<E: EthSpec> Attestation<E> {
|
||||
beacon_block_root: Hash256,
|
||||
source: Checkpoint,
|
||||
target: Checkpoint,
|
||||
payload_present: bool,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<Self, Error> {
|
||||
if spec.fork_name_at_slot::<E>(slot).electra_enabled() {
|
||||
@@ -116,12 +118,19 @@ impl<E: EthSpec> Attestation<E> {
|
||||
committee_bits
|
||||
.set(committee_index as usize, true)
|
||||
.map_err(|_| Error::InvalidCommitteeIndex)?;
|
||||
// Gloas attestation data index now indicates payload presence.
|
||||
// Pre-gloas index is always 0.
|
||||
let index = if spec.fork_name_at_slot::<E>(slot).gloas_enabled() && payload_present {
|
||||
1u64
|
||||
} else {
|
||||
0u64
|
||||
};
|
||||
Ok(Attestation::Electra(AttestationElectra {
|
||||
aggregation_bits: BitList::with_capacity(committee_length)
|
||||
.map_err(|_| Error::InvalidCommitteeLength)?,
|
||||
data: AttestationData {
|
||||
slot,
|
||||
index: 0u64,
|
||||
index,
|
||||
beacon_block_root,
|
||||
source,
|
||||
target,
|
||||
|
||||
@@ -5,7 +5,10 @@ use rand::RngCore;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ssz::{Decode, DecodeError, Encode};
|
||||
|
||||
use crate::{core::Hash256, test_utils::TestRandom};
|
||||
use crate::{
|
||||
core::{Hash256, Hash256Ext},
|
||||
test_utils::TestRandom,
|
||||
};
|
||||
|
||||
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
|
||||
#[derive(Default, Clone, Copy, Serialize, Deserialize, Eq, PartialEq, Hash)]
|
||||
@@ -20,13 +23,7 @@ impl fmt::Debug for ExecutionBlockHash {
|
||||
|
||||
impl fmt::Display for ExecutionBlockHash {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let hash = format!("{}", self.0);
|
||||
write!(
|
||||
f,
|
||||
"{}…{}",
|
||||
&hash[..6],
|
||||
&hash[hash.len().saturating_sub(4)..]
|
||||
)
|
||||
self.0.short().fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -49,3 +49,29 @@ pub type Hash64 = alloy_primitives::B64;
|
||||
pub type Address = alloy_primitives::Address;
|
||||
pub type VersionedHash = Hash256;
|
||||
pub type MerkleProof = Vec<Hash256>;
|
||||
|
||||
/// Extension trait for `Hash256` to allow us to implement additional methods on it.
|
||||
pub trait Hash256Ext {
|
||||
fn short(&self) -> ShortenedHash<'_>;
|
||||
}
|
||||
|
||||
impl Hash256Ext for Hash256 {
|
||||
fn short(&self) -> ShortenedHash<'_> {
|
||||
ShortenedHash(self)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ShortenedHash<'a>(&'a Hash256);
|
||||
|
||||
impl<'a> std::fmt::Display for ShortenedHash<'a> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
let hash: &[u8; 32] = self.0.as_ref();
|
||||
write!(
|
||||
f,
|
||||
// Format as hex, padded to 2 digits per byte.
|
||||
// This outputs a consistent "0x1234...abcd" format.
|
||||
"0x{:02x}{:02x}…{:02x}{:02x}",
|
||||
hash[0], hash[1], hash[30], hash[31]
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3198,6 +3198,27 @@ impl<E: EthSpec> BeaconState<E> {
|
||||
Ok(hash(&preimage))
|
||||
}
|
||||
|
||||
/// Find the first slot in the given epoch where the validator is assigned to the PTC.
|
||||
///
|
||||
/// Returns `Ok(Some(slot))` if the validator is in the PTC for any slot in the epoch,
|
||||
/// `Ok(None)` if the validator is not in the PTC for this epoch.
|
||||
///
|
||||
/// This iterates through all slots in the epoch, so it's O(slots_per_epoch) per validator.
|
||||
pub fn get_ptc_assignment(
|
||||
&self,
|
||||
validator_index: usize,
|
||||
epoch: Epoch,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<Option<Slot>, BeaconStateError> {
|
||||
for slot in epoch.slot_iter(E::slots_per_epoch()) {
|
||||
let ptc = self.get_ptc(slot, spec)?;
|
||||
if ptc.0.contains(&validator_index) {
|
||||
return Ok(Some(slot));
|
||||
}
|
||||
}
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
/// Return size indices sampled by effective balance, using indices as candidates.
|
||||
///
|
||||
/// If shuffle_indices is True, candidate indices are themselves sampled from indices
|
||||
|
||||
Reference in New Issue
Block a user