Merge branch 'unstable' into dvt

This commit is contained in:
chonghe
2025-03-31 14:59:07 +08:00
committed by GitHub
494 changed files with 14225 additions and 37939 deletions

View File

@@ -8,10 +8,11 @@ edition = { workspace = true }
[dependencies]
ethereum_ssz = { workspace = true }
ethereum_ssz_derive = { workspace = true }
logging = { workspace = true }
metrics = { workspace = true }
proto_array = { workspace = true }
slog = { workspace = true }
state_processing = { workspace = true }
tracing = { workspace = true }
types = { workspace = true }
[dev-dependencies]

View File

@@ -1,10 +1,10 @@
use crate::metrics::{self, scrape_for_metrics};
use crate::{ForkChoiceStore, InvalidationOperation};
use logging::crit;
use proto_array::{
Block as ProtoBlock, DisallowedReOrgOffsets, ExecutionStatus, ProposerHeadError,
ProposerHeadInfo, ProtoArrayForkChoice, ReOrgThreshold,
};
use slog::{crit, debug, warn, Logger};
use ssz_derive::{Decode, Encode};
use state_processing::{
per_block_processing::errors::AttesterSlashingValidationError, per_epoch_processing,
@@ -13,6 +13,7 @@ use std::cmp::Ordering;
use std::collections::BTreeSet;
use std::marker::PhantomData;
use std::time::Duration;
use tracing::{debug, warn};
use types::{
consts::bellatrix::INTERVALS_PER_SLOT, AbstractExecPayload, AttestationShufflingId,
AttesterSlashingRef, BeaconBlockRef, BeaconState, BeaconStateError, ChainSpec, Checkpoint,
@@ -1255,6 +1256,11 @@ where
.is_finalized_checkpoint_or_descendant::<E>(block_root)
}
pub fn is_descendant(&self, ancestor_root: Hash256, descendant_root: Hash256) -> bool {
self.proto_array
.is_descendant(ancestor_root, descendant_root)
}
/// Returns `Ok(true)` if `block_root` has been imported optimistically or deemed invalid.
///
/// Returns `Ok(false)` if `block_root`'s execution payload has been elected as fully VALID, if
@@ -1365,17 +1371,14 @@ where
persisted: &PersistedForkChoice,
reset_payload_statuses: ResetPayloadStatuses,
spec: &ChainSpec,
log: &Logger,
) -> Result<ProtoArrayForkChoice, Error<T::Error>> {
let mut proto_array = ProtoArrayForkChoice::from_bytes(&persisted.proto_array_bytes)
.map_err(Error::InvalidProtoArrayBytes)?;
let contains_invalid_payloads = proto_array.contains_invalid_payloads();
debug!(
log,
"Restoring fork choice from persisted";
"reset_payload_statuses" => ?reset_payload_statuses,
"contains_invalid_payloads" => contains_invalid_payloads,
?reset_payload_statuses,
contains_invalid_payloads, "Restoring fork choice from persisted"
);
// Exit early if there are no "invalid" payloads, if requested.
@@ -1394,18 +1397,14 @@ where
// back to a proto-array which does not have the reset applied. This indicates a
// significant error in Lighthouse and warrants detailed investigation.
crit!(
log,
"Failed to reset payload statuses";
"error" => e,
"info" => "please report this error",
error = ?e,
info = "please report this error",
"Failed to reset payload statuses"
);
ProtoArrayForkChoice::from_bytes(&persisted.proto_array_bytes)
.map_err(Error::InvalidProtoArrayBytes)
} else {
debug!(
log,
"Successfully reset all payload statuses";
);
debug!("Successfully reset all payload statuses");
Ok(proto_array)
}
}
@@ -1417,10 +1416,9 @@ where
reset_payload_statuses: ResetPayloadStatuses,
fc_store: T,
spec: &ChainSpec,
log: &Logger,
) -> Result<Self, Error<T::Error>> {
let proto_array =
Self::proto_array_from_persisted(&persisted, reset_payload_statuses, spec, log)?;
Self::proto_array_from_persisted(&persisted, reset_payload_statuses, spec)?;
let current_slot = fc_store.get_current_slot();
@@ -1444,10 +1442,9 @@ where
// an optimistic status so that we can have a head to start from.
if let Err(e) = fork_choice.get_head(current_slot, spec) {
warn!(
log,
"Could not find head on persisted FC";
"info" => "resetting all payload statuses and retrying",
"error" => ?e
info = "resetting all payload statuses and retrying",
error = ?e,
"Could not find head on persisted FC"
);
// Although we may have already made this call whilst loading `proto_array`, try it
// again since we may have mutated the `proto_array` during `get_head` and therefore may

View File

@@ -25,6 +25,9 @@ pub type E = MainnetEthSpec;
pub const VALIDATOR_COUNT: usize = 64;
// When set to true, cache any states fetched from the db.
pub const CACHE_STATE_IN_TESTS: bool = true;
/// Defines some delay between when an attestation is created and when it is mutated.
pub enum MutationDelay {
/// No delay between creation and mutation.
@@ -373,7 +376,7 @@ impl ForkChoiceTest {
let state = harness
.chain
.store
.get_state(&state_root, None)
.get_state(&state_root, None, CACHE_STATE_IN_TESTS)
.unwrap()
.unwrap();
let balances = state

View File

@@ -34,6 +34,8 @@ pub enum MerkleTree {
pub enum MerkleTreeError {
// Trying to push in a leaf
LeafReached,
// Trying to generate a proof for a non-leaf node
NonLeafProof,
// No more space in the MerkleTree
MerkleTreeFull,
// MerkleTree is invalid
@@ -313,8 +315,17 @@ impl MerkleTree {
current_depth -= 1;
}
debug_assert_eq!(proof.len(), depth);
debug_assert!(current_node.is_leaf());
if proof.len() != depth {
// This should be unreachable regardless of how the method is called, because we push
// one proof element for each layer of `depth`.
return Err(MerkleTreeError::PleaseNotifyTheDevs);
}
// Generating a proof for a non-leaf node is invalid and indicates an error on the part of
// the caller.
if !current_node.is_leaf() {
return Err(MerkleTreeError::NonLeafProof);
}
// Put proof in bottom-up order.
proof.reverse();

View File

@@ -293,7 +293,6 @@ where
)?);
Ok(())
})
.map_err(Error::into)
}
/// Includes all signatures in `self.block.body.voluntary_exits` for verification.

View File

@@ -60,6 +60,7 @@ pub enum BlockProcessingError {
SignatureSetError(SignatureSetError),
SszTypesError(ssz_types::Error),
SszDecodeError(DecodeError),
BitfieldError(ssz::BitfieldError),
MerkleTreeError(MerkleTreeError),
ArithError(ArithError),
InconsistentBlockFork(InconsistentFork),
@@ -153,6 +154,7 @@ impl From<BlockOperationError<HeaderInvalid>> for BlockProcessingError {
BlockOperationError::BeaconStateError(e) => BlockProcessingError::BeaconStateError(e),
BlockOperationError::SignatureSetError(e) => BlockProcessingError::SignatureSetError(e),
BlockOperationError::SszTypesError(e) => BlockProcessingError::SszTypesError(e),
BlockOperationError::BitfieldError(e) => BlockProcessingError::BitfieldError(e),
BlockOperationError::ConsensusContext(e) => BlockProcessingError::ConsensusContext(e),
BlockOperationError::ArithError(e) => BlockProcessingError::ArithError(e),
}
@@ -181,6 +183,7 @@ macro_rules! impl_into_block_processing_error_with_index {
BlockOperationError::BeaconStateError(e) => BlockProcessingError::BeaconStateError(e),
BlockOperationError::SignatureSetError(e) => BlockProcessingError::SignatureSetError(e),
BlockOperationError::SszTypesError(e) => BlockProcessingError::SszTypesError(e),
BlockOperationError::BitfieldError(e) => BlockProcessingError::BitfieldError(e),
BlockOperationError::ConsensusContext(e) => BlockProcessingError::ConsensusContext(e),
BlockOperationError::ArithError(e) => BlockProcessingError::ArithError(e),
}
@@ -215,6 +218,7 @@ pub enum BlockOperationError<T> {
BeaconStateError(BeaconStateError),
SignatureSetError(SignatureSetError),
SszTypesError(ssz_types::Error),
BitfieldError(ssz::BitfieldError),
ConsensusContext(ContextError),
ArithError(ArithError),
}
@@ -242,6 +246,12 @@ impl<T> From<ssz_types::Error> for BlockOperationError<T> {
}
}
impl<T> From<ssz::BitfieldError> for BlockOperationError<T> {
fn from(error: ssz::BitfieldError) -> Self {
BlockOperationError::BitfieldError(error)
}
}
impl<T> From<ArithError> for BlockOperationError<T> {
fn from(e: ArithError) -> Self {
BlockOperationError::ArithError(e)
@@ -367,6 +377,7 @@ impl From<BlockOperationError<IndexedAttestationInvalid>>
BlockOperationError::BeaconStateError(e) => BlockOperationError::BeaconStateError(e),
BlockOperationError::SignatureSetError(e) => BlockOperationError::SignatureSetError(e),
BlockOperationError::SszTypesError(e) => BlockOperationError::SszTypesError(e),
BlockOperationError::BitfieldError(e) => BlockOperationError::BitfieldError(e),
BlockOperationError::ConsensusContext(e) => BlockOperationError::ConsensusContext(e),
BlockOperationError::ArithError(e) => BlockOperationError::ArithError(e),
}

View File

@@ -22,6 +22,9 @@ pub const VALIDATOR_COUNT: usize = 64;
pub const EPOCH_OFFSET: u64 = 4;
pub const NUM_ATTESTATIONS: u64 = 1;
// When set to true, cache any states fetched from the db.
pub const CACHE_STATE_IN_TESTS: bool = true;
/// A cached set of keys.
static KEYPAIRS: LazyLock<Vec<Keypair>> =
LazyLock::new(|| generate_deterministic_keypairs(MAX_VALIDATOR_COUNT));
@@ -1114,9 +1117,10 @@ async fn block_replayer_peeking_state_roots() {
.get_blinded_block(&parent_block_root)
.unwrap()
.unwrap();
// Cache the state to make CI go brr.
let parent_state = harness
.chain
.get_state(&parent_block.state_root(), Some(parent_block.slot()))
.get_state(&parent_block.state_root(), Some(parent_block.slot()), true)
.unwrap()
.unwrap();

View File

@@ -19,9 +19,10 @@ pub enum EpochProcessingError {
BeaconStateError(BeaconStateError),
InclusionError(InclusionError),
SszTypesError(ssz_types::Error),
BitfieldError(ssz::BitfieldError),
ArithError(safe_arith::ArithError),
InconsistentStateFork(InconsistentFork),
InvalidJustificationBit(ssz_types::Error),
InvalidJustificationBit(ssz::BitfieldError),
InvalidFlagIndex(usize),
MilhouseError(milhouse::Error),
EpochCache(EpochCacheError),
@@ -49,6 +50,12 @@ impl From<ssz_types::Error> for EpochProcessingError {
}
}
impl From<ssz::BitfieldError> for EpochProcessingError {
fn from(e: ssz::BitfieldError) -> EpochProcessingError {
EpochProcessingError::BitfieldError(e)
}
}
impl From<safe_arith::ArithError> for EpochProcessingError {
fn from(e: safe_arith::ArithError) -> EpochProcessingError {
EpochProcessingError::ArithError(e)

View File

@@ -175,6 +175,7 @@ pub fn process_epoch_single_pass<E: EthSpec>(
let mut earliest_exit_epoch = state.earliest_exit_epoch().ok();
let mut exit_balance_to_consume = state.exit_balance_to_consume().ok();
let validators_in_consolidations = get_validators_in_consolidations(state);
// Split the state into several disjoint mutable borrows.
let (
@@ -317,17 +318,26 @@ pub fn process_epoch_single_pass<E: EthSpec>(
// `process_effective_balance_updates`
if conf.effective_balance_updates {
process_single_effective_balance_update(
validator_info.index,
*balance,
&mut validator,
validator_info.current_epoch_participation,
&mut next_epoch_cache,
progressive_balances,
effective_balances_ctxt,
state_ctxt,
spec,
)?;
if validators_in_consolidations.contains(&validator_info.index) {
process_single_dummy_effective_balance_update(
validator_info.index,
&validator,
&mut next_epoch_cache,
state_ctxt,
)?;
} else {
process_single_effective_balance_update(
validator_info.index,
*balance,
&mut validator,
validator_info.current_epoch_participation,
&mut next_epoch_cache,
progressive_balances,
effective_balances_ctxt,
state_ctxt,
spec,
)?;
}
}
}
@@ -430,6 +440,7 @@ pub fn process_epoch_single_pass<E: EthSpec>(
if fork_name.electra_enabled() && conf.pending_consolidations {
process_pending_consolidations(
state,
&validators_in_consolidations,
&mut next_epoch_cache,
effective_balances_ctxt,
conf.effective_balance_updates,
@@ -1026,12 +1037,38 @@ fn process_pending_deposits_for_validator(
Ok(())
}
/// Return the set of validators referenced by consolidations, either as source or target.
///
/// This function is blind to whether the consolidations are valid and capable of being processed,
/// it just returns the set of all indices present in consolidations. This is *sufficient* to
/// make consolidations play nicely with effective balance updates. The algorithm used is:
///
/// - In the single pass: apply effective balance updates for all validators *not* referenced by
/// consolidations.
/// - Apply consolidations.
/// - Apply effective balance updates for all validators previously skipped.
///
/// Prior to Electra, the empty set is returned.
fn get_validators_in_consolidations<E: EthSpec>(state: &BeaconState<E>) -> BTreeSet<usize> {
let mut referenced_validators = BTreeSet::new();
if let Ok(pending_consolidations) = state.pending_consolidations() {
for pending_consolidation in pending_consolidations {
referenced_validators.insert(pending_consolidation.source_index as usize);
referenced_validators.insert(pending_consolidation.target_index as usize);
}
}
referenced_validators
}
/// We process pending consolidations after all of single-pass epoch processing, and then patch up
/// the effective balances for affected validators.
///
/// This is safe because processing consolidations does not depend on the `effective_balance`.
fn process_pending_consolidations<E: EthSpec>(
state: &mut BeaconState<E>,
validators_in_consolidations: &BTreeSet<usize>,
next_epoch_cache: &mut PreEpochCache,
effective_balances_ctxt: &EffectiveBalancesContext,
perform_effective_balance_updates: bool,
@@ -1042,8 +1079,6 @@ fn process_pending_consolidations<E: EthSpec>(
let next_epoch = state.next_epoch()?;
let pending_consolidations = state.pending_consolidations()?.clone();
let mut affected_validators = BTreeSet::new();
for pending_consolidation in &pending_consolidations {
let source_index = pending_consolidation.source_index as usize;
let target_index = pending_consolidation.target_index as usize;
@@ -1069,9 +1104,6 @@ fn process_pending_consolidations<E: EthSpec>(
decrease_balance(state, source_index, source_effective_balance)?;
increase_balance(state, target_index, source_effective_balance)?;
affected_validators.insert(source_index);
affected_validators.insert(target_index);
next_pending_consolidation.safe_add_assign(1)?;
}
@@ -1087,7 +1119,7 @@ fn process_pending_consolidations<E: EthSpec>(
// Re-process effective balance updates for validators affected by consolidations.
let (validators, balances, _, current_epoch_participation, _, progressive_balances, _, _) =
state.mutable_validator_fields()?;
for validator_index in affected_validators {
for &validator_index in validators_in_consolidations {
let balance = *balances
.get(validator_index)
.ok_or(BeaconStateError::UnknownValidator(validator_index))?;
@@ -1129,6 +1161,28 @@ impl EffectiveBalancesContext {
}
}
/// This function is called for validators that do not have their effective balance updated as
/// part of the single-pass loop. For these validators we compute their true effective balance
/// update after processing consolidations. However, to maintain the invariants of the
/// `PreEpochCache` we must register _some_ effective balance for them immediately.
fn process_single_dummy_effective_balance_update(
validator_index: usize,
validator: &Cow<Validator>,
next_epoch_cache: &mut PreEpochCache,
state_ctxt: &StateContext,
) -> Result<(), Error> {
// Populate the effective balance cache with the current effective balance. This will be
// overriden when `process_single_effective_balance_update` is called.
let is_active_next_epoch = validator.is_active_at(state_ctxt.next_epoch);
let temporary_effective_balance = validator.effective_balance;
next_epoch_cache.update_effective_balance(
validator_index,
temporary_effective_balance,
is_active_next_epoch,
)?;
Ok(())
}
/// This function abstracts over phase0 and Electra effective balance processing.
#[allow(clippy::too_many_arguments)]
fn process_single_effective_balance_update(

View File

@@ -28,7 +28,6 @@ hex = { workspace = true }
int_to_bytes = { workspace = true }
itertools = { workspace = true }
kzg = { workspace = true }
log = { workspace = true }
maplit = { workspace = true }
merkle_proof = { workspace = true }
metastruct = "0.1.0"
@@ -39,18 +38,18 @@ rand_xorshift = "0.3.0"
rayon = { workspace = true }
regex = { workspace = true }
rpds = { workspace = true }
rusqlite = { workspace = true }
rusqlite = { workspace = true, optional = true }
safe_arith = { workspace = true }
serde = { workspace = true, features = ["rc"] }
serde_json = { workspace = true }
serde_yaml = { workspace = true }
slog = { workspace = true }
smallvec = { workspace = true }
ssz_types = { workspace = true, features = ["arbitrary"] }
superstruct = { workspace = true }
swap_or_not_shuffle = { workspace = true, features = ["arbitrary"] }
tempfile = { workspace = true }
test_random_derive = { path = "../../common/test_random_derive" }
tracing = { workspace = true }
tree_hash = { workspace = true }
tree_hash_derive = { workspace = true }
@@ -65,7 +64,7 @@ tokio = { workspace = true }
default = ["sqlite", "legacy-arith"]
# Allow saturating arithmetic on slots and epochs. Enabled by default, but deprecated.
legacy-arith = []
sqlite = []
sqlite = ["dep:rusqlite"]
# The `arbitrary-fuzz` feature is a no-op provided for backwards compatibility.
# For simplicity `Arbitrary` is now derived regardless of the feature's presence.
arbitrary-fuzz = []

View File

@@ -18,6 +18,7 @@ use super::{
#[derive(Debug, PartialEq)]
pub enum Error {
SszTypesError(ssz_types::Error),
BitfieldError(ssz::BitfieldError),
AlreadySigned(usize),
IncorrectStateVariant,
InvalidCommitteeLength,
@@ -223,7 +224,7 @@ impl<E: EthSpec> Attestation<E> {
}
}
pub fn get_aggregation_bit(&self, index: usize) -> Result<bool, ssz_types::Error> {
pub fn get_aggregation_bit(&self, index: usize) -> Result<bool, ssz::BitfieldError> {
match self {
Attestation::Base(att) => att.aggregation_bits.get(index),
Attestation::Electra(att) => att.aggregation_bits.get(index),
@@ -353,13 +354,13 @@ impl<E: EthSpec> AttestationElectra<E> {
if self
.aggregation_bits
.get(committee_position)
.map_err(Error::SszTypesError)?
.map_err(Error::BitfieldError)?
{
Err(Error::AlreadySigned(committee_position))
} else {
self.aggregation_bits
.set(committee_position, true)
.map_err(Error::SszTypesError)?;
.map_err(Error::BitfieldError)?;
self.signature.add_assign(signature);
@@ -427,13 +428,13 @@ impl<E: EthSpec> AttestationBase<E> {
if self
.aggregation_bits
.get(committee_position)
.map_err(Error::SszTypesError)?
.map_err(Error::BitfieldError)?
{
Err(Error::AlreadySigned(committee_position))
} else {
self.aggregation_bits
.set(committee_position, true)
.map_err(Error::SszTypesError)?;
.map_err(Error::BitfieldError)?;
self.signature.add_assign(signature);
@@ -443,7 +444,7 @@ impl<E: EthSpec> AttestationBase<E> {
pub fn extend_aggregation_bits(
&self,
) -> Result<BitList<E::MaxValidatorsPerSlot>, ssz_types::Error> {
) -> Result<BitList<E::MaxValidatorsPerSlot>, ssz::BitfieldError> {
self.aggregation_bits.resize::<E::MaxValidatorsPerSlot>()
}
}
@@ -600,12 +601,12 @@ mod tests {
let attestation_data = size_of::<AttestationData>();
let signature = size_of::<AggregateSignature>();
assert_eq!(aggregation_bits, 56);
assert_eq!(aggregation_bits, 152);
assert_eq!(attestation_data, 128);
assert_eq!(signature, 288 + 16);
let attestation_expected = aggregation_bits + attestation_data + signature;
assert_eq!(attestation_expected, 488);
assert_eq!(attestation_expected, 584);
assert_eq!(
size_of::<AttestationBase<MainnetEthSpec>>(),
attestation_expected
@@ -623,13 +624,13 @@ mod tests {
size_of::<BitList<<MainnetEthSpec as EthSpec>::MaxCommitteesPerSlot>>();
let signature = size_of::<AggregateSignature>();
assert_eq!(aggregation_bits, 56);
assert_eq!(committee_bits, 56);
assert_eq!(aggregation_bits, 152);
assert_eq!(committee_bits, 152);
assert_eq!(attestation_data, 128);
assert_eq!(signature, 288 + 16);
let attestation_expected = aggregation_bits + committee_bits + attestation_data + signature;
assert_eq!(attestation_expected, 544);
assert_eq!(attestation_expected, 736);
assert_eq!(
size_of::<AttestationElectra<MainnetEthSpec>>(),
attestation_expected

View File

@@ -277,9 +277,9 @@ impl<'a, E: EthSpec, Payload: AbstractExecPayload<E>> BeaconBlockBodyRef<'a, E,
// https://github.com/ethereum/consensus-specs/blob/dev/specs/deneb/beacon-chain.md#beaconblockbody
generalized_index
.checked_sub(NUM_BEACON_BLOCK_BODY_HASH_TREE_ROOT_LEAVES)
.ok_or(Error::IndexNotSupported(generalized_index))?
.ok_or(Error::GeneralizedIndexNotSupported(generalized_index))?
}
_ => return Err(Error::IndexNotSupported(generalized_index)),
_ => return Err(Error::GeneralizedIndexNotSupported(generalized_index)),
};
let leaves = self.body_merkle_leaves();
@@ -971,6 +971,7 @@ impl<E: EthSpec> From<BeaconBlockBody<E, FullPayload<E>>>
Option<ExecutionPayload<E>>,
)
{
#[allow(clippy::useless_conversion)] // Not a useless conversion
fn from(body: BeaconBlockBody<E, FullPayload<E>>) -> Self {
map_beacon_block_body!(body, |inner, cons| {
let (block, payload) = inner.into();

View File

@@ -157,6 +157,7 @@ pub enum Error {
current_fork: ForkName,
},
TotalActiveBalanceDiffUninitialized,
GeneralizedIndexNotSupported(usize),
IndexNotSupported(usize),
InvalidFlagIndex(usize),
MerkleTreeError(merkle_proof::MerkleTreeError),
@@ -2580,11 +2581,12 @@ impl<E: EthSpec> BeaconState<E> {
// for the internal nodes. Result should be 22 or 23, the field offset of the committee
// in the `BeaconState`:
// https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/beacon-chain.md#beaconstate
let field_index = if self.fork_name_unchecked().electra_enabled() {
let field_gindex = if self.fork_name_unchecked().electra_enabled() {
light_client_update::CURRENT_SYNC_COMMITTEE_INDEX_ELECTRA
} else {
light_client_update::CURRENT_SYNC_COMMITTEE_INDEX
};
let field_index = field_gindex.safe_sub(self.num_fields_pow2())?;
let leaves = self.get_beacon_state_leaves();
self.generate_proof(field_index, &leaves)
}
@@ -2594,11 +2596,12 @@ impl<E: EthSpec> BeaconState<E> {
// for the internal nodes. Result should be 22 or 23, the field offset of the committee
// in the `BeaconState`:
// https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/beacon-chain.md#beaconstate
let field_index = if self.fork_name_unchecked().electra_enabled() {
let field_gindex = if self.fork_name_unchecked().electra_enabled() {
light_client_update::NEXT_SYNC_COMMITTEE_INDEX_ELECTRA
} else {
light_client_update::NEXT_SYNC_COMMITTEE_INDEX
};
let field_index = field_gindex.safe_sub(self.num_fields_pow2())?;
let leaves = self.get_beacon_state_leaves();
self.generate_proof(field_index, &leaves)
}
@@ -2606,17 +2609,24 @@ impl<E: EthSpec> BeaconState<E> {
pub fn compute_finalized_root_proof(&self) -> Result<Vec<Hash256>, Error> {
// Finalized root is the right child of `finalized_checkpoint`, divide by two to get
// the generalized index of `state.finalized_checkpoint`.
let field_index = if self.fork_name_unchecked().electra_enabled() {
// Index should be 169/2 - 64 = 20 which matches the position
// of `finalized_checkpoint` in `BeaconState`
let checkpoint_root_gindex = if self.fork_name_unchecked().electra_enabled() {
light_client_update::FINALIZED_ROOT_INDEX_ELECTRA
} else {
// Index should be 105/2 - 32 = 20 which matches the position
// of `finalized_checkpoint` in `BeaconState`
light_client_update::FINALIZED_ROOT_INDEX
};
let checkpoint_gindex = checkpoint_root_gindex / 2;
// Convert gindex to index by subtracting 2**depth (gindex = 2**depth + index).
//
// After Electra, the index should be 169/2 - 64 = 20 which matches the position
// of `finalized_checkpoint` in `BeaconState`.
//
// Prior to Electra, the index should be 105/2 - 32 = 20 which matches the position
// of `finalized_checkpoint` in `BeaconState`.
let checkpoint_index = checkpoint_gindex.safe_sub(self.num_fields_pow2())?;
let leaves = self.get_beacon_state_leaves();
let mut proof = self.generate_proof(field_index, &leaves)?;
let mut proof = self.generate_proof(checkpoint_index, &leaves)?;
proof.insert(0, self.finalized_checkpoint().epoch.tree_hash_root());
Ok(proof)
}
@@ -2626,6 +2636,10 @@ impl<E: EthSpec> BeaconState<E> {
field_index: usize,
leaves: &[Hash256],
) -> Result<Vec<Hash256>, Error> {
if field_index >= leaves.len() {
return Err(Error::IndexNotSupported(field_index));
}
let depth = self.num_fields_pow2().ilog2() as usize;
let tree = merkle_proof::MerkleTree::create(leaves, depth);
let (_, proof) = tree.generate_proof(field_index, depth)?;

View File

@@ -213,12 +213,16 @@ impl<E: EthSpec> LightClientUpdate<E> {
.map_err(|_| Error::InconsistentFork)?
{
ForkName::Base => return Err(Error::AltairForkNotActive),
ForkName::Altair | ForkName::Bellatrix => {
fork_name @ ForkName::Altair | fork_name @ ForkName::Bellatrix => {
let attested_header =
LightClientHeaderAltair::block_to_light_client_header(attested_block)?;
let finalized_header = if let Some(finalized_block) = finalized_block {
LightClientHeaderAltair::block_to_light_client_header(finalized_block)?
if finalized_block.fork_name_unchecked() == fork_name {
LightClientHeaderAltair::block_to_light_client_header(finalized_block)?
} else {
LightClientHeaderAltair::default()
}
} else {
LightClientHeaderAltair::default()
};
@@ -233,12 +237,16 @@ impl<E: EthSpec> LightClientUpdate<E> {
signature_slot: block_slot,
})
}
ForkName::Capella => {
fork_name @ ForkName::Capella => {
let attested_header =
LightClientHeaderCapella::block_to_light_client_header(attested_block)?;
let finalized_header = if let Some(finalized_block) = finalized_block {
LightClientHeaderCapella::block_to_light_client_header(finalized_block)?
if finalized_block.fork_name_unchecked() == fork_name {
LightClientHeaderCapella::block_to_light_client_header(finalized_block)?
} else {
LightClientHeaderCapella::default()
}
} else {
LightClientHeaderCapella::default()
};
@@ -253,12 +261,16 @@ impl<E: EthSpec> LightClientUpdate<E> {
signature_slot: block_slot,
})
}
ForkName::Deneb => {
fork_name @ ForkName::Deneb => {
let attested_header =
LightClientHeaderDeneb::block_to_light_client_header(attested_block)?;
let finalized_header = if let Some(finalized_block) = finalized_block {
LightClientHeaderDeneb::block_to_light_client_header(finalized_block)?
if finalized_block.fork_name_unchecked() == fork_name {
LightClientHeaderDeneb::block_to_light_client_header(finalized_block)?
} else {
LightClientHeaderDeneb::default()
}
} else {
LightClientHeaderDeneb::default()
};
@@ -273,12 +285,16 @@ impl<E: EthSpec> LightClientUpdate<E> {
signature_slot: block_slot,
})
}
ForkName::Electra => {
fork_name @ ForkName::Electra => {
let attested_header =
LightClientHeaderElectra::block_to_light_client_header(attested_block)?;
let finalized_header = if let Some(finalized_block) = finalized_block {
LightClientHeaderElectra::block_to_light_client_header(finalized_block)?
if finalized_block.fork_name_unchecked() == fork_name {
LightClientHeaderElectra::block_to_light_client_header(finalized_block)?
} else {
LightClientHeaderElectra::default()
}
} else {
LightClientHeaderElectra::default()
};
@@ -293,12 +309,16 @@ impl<E: EthSpec> LightClientUpdate<E> {
signature_slot: block_slot,
})
}
ForkName::Fulu => {
fork_name @ ForkName::Fulu => {
let attested_header =
LightClientHeaderFulu::block_to_light_client_header(attested_block)?;
let finalized_header = if let Some(finalized_block) = finalized_block {
LightClientHeaderFulu::block_to_light_client_header(finalized_block)?
if finalized_block.fork_name_unchecked() == fork_name {
LightClientHeaderFulu::block_to_light_client_header(finalized_block)?
} else {
LightClientHeaderFulu::default()
}
} else {
LightClientHeaderFulu::default()
};

View File

@@ -134,13 +134,13 @@ impl<T: Decode> RuntimeVariableList<T> {
)));
}
bytes
.chunks(<T as Decode>::ssz_fixed_len())
.try_fold(Vec::with_capacity(num_items), |mut vec, chunk| {
bytes.chunks(<T as Decode>::ssz_fixed_len()).try_fold(
Vec::with_capacity(num_items),
|mut vec, chunk| {
vec.push(<T as Decode>::from_ssz_bytes(chunk)?);
Ok(vec)
})
.map(Into::into)?
},
)?
} else {
ssz::decode_list_of_variable_length_items(bytes, Some(max_len))?
};

View File

@@ -227,17 +227,6 @@ macro_rules! impl_display {
write!(f, "{}", self.0)
}
}
impl slog::Value for $type {
fn serialize(
&self,
record: &slog::Record,
key: slog::Key,
serializer: &mut dyn slog::Serializer,
) -> slog::Result {
slog::Value::serialize(&self.0, record, key, serializer)
}
}
};
}

View File

@@ -11,6 +11,7 @@ use tree_hash_derive::TreeHash;
#[derive(Debug, PartialEq)]
pub enum Error {
SszTypesError(ssz_types::Error),
BitfieldError(ssz::BitfieldError),
ArithError(ArithError),
}
@@ -68,7 +69,7 @@ impl<E: EthSpec> SyncAggregate<E> {
sync_aggregate
.sync_committee_bits
.set(participant_index, true)
.map_err(Error::SszTypesError)?;
.map_err(Error::BitfieldError)?;
}
}
sync_aggregate

View File

@@ -9,6 +9,7 @@ use tree_hash_derive::TreeHash;
#[derive(Debug, PartialEq)]
pub enum Error {
SszTypesError(ssz_types::Error),
BitfieldError(ssz::BitfieldError),
AlreadySigned(usize),
}
@@ -51,7 +52,7 @@ impl<E: EthSpec> SyncCommitteeContribution<E> {
) -> Result<Self, Error> {
let mut bits = BitVector::new();
bits.set(validator_sync_committee_index, true)
.map_err(Error::SszTypesError)?;
.map_err(Error::BitfieldError)?;
Ok(Self {
slot: message.slot,
beacon_block_root: message.beacon_block_root,

View File

@@ -1,8 +1,8 @@
use crate::*;
use eth2_interop_keypairs::{keypair, keypairs_from_yaml_file};
use log::debug;
use rayon::prelude::*;
use std::path::PathBuf;
use tracing::debug;
/// Generates `validator_count` keypairs where the secret key is derived solely from the index of
/// the validator.

View File

@@ -4,7 +4,7 @@ use ssz_derive::{Decode, Encode};
use tree_hash_derive::TreeHash;
/// Validator registration, for use in interacting with servers implementing the builder API.
#[derive(PartialEq, Debug, Serialize, Deserialize, Clone)]
#[derive(PartialEq, Debug, Serialize, Deserialize, Clone, Encode, Decode)]
pub struct SignedValidatorRegistrationData {
pub message: ValidatorRegistrationData,
pub signature: Signature,