mirror of
https://github.com/sigp/lighthouse.git
synced 2026-07-05 13:54:36 +00:00
fixing test
This commit is contained in:
@@ -2263,6 +2263,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
|||||||
self.slot()?,
|
self.slot()?,
|
||||||
verified.indexed_attestation().to_ref(),
|
verified.indexed_attestation().to_ref(),
|
||||||
AttestationFromBlock::False,
|
AttestationFromBlock::False,
|
||||||
|
&self.spec,
|
||||||
)
|
)
|
||||||
.map_err(Into::into)
|
.map_err(Into::into)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1665,6 +1665,7 @@ impl<T: BeaconChainTypes> ExecutionPendingBlock<T> {
|
|||||||
current_slot,
|
current_slot,
|
||||||
indexed_attestation,
|
indexed_attestation,
|
||||||
AttestationFromBlock::True,
|
AttestationFromBlock::True,
|
||||||
|
&chain.spec,
|
||||||
) {
|
) {
|
||||||
Ok(()) => Ok(()),
|
Ok(()) => Ok(()),
|
||||||
// Ignore invalid attestations whilst importing attestations from a block. The
|
// Ignore invalid attestations whilst importing attestations from a block. The
|
||||||
|
|||||||
@@ -407,21 +407,33 @@ where
|
|||||||
AttestationShufflingId::new(anchor_block_root, anchor_state, RelativeEpoch::Next)
|
AttestationShufflingId::new(anchor_block_root, anchor_state, RelativeEpoch::Next)
|
||||||
.map_err(Error::BeaconStateError)?;
|
.map_err(Error::BeaconStateError)?;
|
||||||
|
|
||||||
let execution_status = anchor_block.message().execution_payload().map_or_else(
|
let (execution_status, execution_payload_parent_hash, execution_payload_block_hash) =
|
||||||
// If the block doesn't have an execution payload then it can't have
|
if let Ok(execution_payload) = anchor_block.message().execution_payload() {
|
||||||
// execution enabled.
|
// Pre-Gloas forks: hashes come from the execution payload.
|
||||||
|_| ExecutionStatus::irrelevant(),
|
|
||||||
|execution_payload| {
|
|
||||||
if execution_payload.is_default_with_empty_roots() {
|
if execution_payload.is_default_with_empty_roots() {
|
||||||
// A default payload does not have execution enabled.
|
(ExecutionStatus::irrelevant(), None, None)
|
||||||
ExecutionStatus::irrelevant()
|
|
||||||
} else {
|
} else {
|
||||||
// Assume that this payload is valid, since the anchor should be a trusted block and
|
// Assume that this payload is valid, since the anchor should be a
|
||||||
// state.
|
// trusted block and state.
|
||||||
ExecutionStatus::Valid(execution_payload.block_hash())
|
(
|
||||||
|
ExecutionStatus::Valid(execution_payload.block_hash()),
|
||||||
|
Some(execution_payload.parent_hash()),
|
||||||
|
Some(execution_payload.block_hash()),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
},
|
} else if let Ok(signed_bid) =
|
||||||
);
|
anchor_block.message().body().signed_execution_payload_bid()
|
||||||
|
{
|
||||||
|
// Gloas: hashes come from the execution payload bid.
|
||||||
|
(
|
||||||
|
ExecutionStatus::irrelevant(),
|
||||||
|
Some(signed_bid.message.parent_block_hash),
|
||||||
|
Some(signed_bid.message.block_hash),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
// Pre-merge: no execution payload at all.
|
||||||
|
(ExecutionStatus::irrelevant(), None, None)
|
||||||
|
};
|
||||||
|
|
||||||
// If the current slot is not provided, use the value that was last provided to the store.
|
// If the current slot is not provided, use the value that was last provided to the store.
|
||||||
let current_slot = current_slot.unwrap_or_else(|| fc_store.get_current_slot());
|
let current_slot = current_slot.unwrap_or_else(|| fc_store.get_current_slot());
|
||||||
@@ -435,8 +447,8 @@ where
|
|||||||
current_epoch_shuffling_id,
|
current_epoch_shuffling_id,
|
||||||
next_epoch_shuffling_id,
|
next_epoch_shuffling_id,
|
||||||
execution_status,
|
execution_status,
|
||||||
None,
|
execution_payload_parent_hash,
|
||||||
None,
|
execution_payload_block_hash,
|
||||||
spec,
|
spec,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
@@ -1045,6 +1057,7 @@ where
|
|||||||
&self,
|
&self,
|
||||||
indexed_attestation: IndexedAttestationRef<E>,
|
indexed_attestation: IndexedAttestationRef<E>,
|
||||||
is_from_block: AttestationFromBlock,
|
is_from_block: AttestationFromBlock,
|
||||||
|
spec: &ChainSpec,
|
||||||
) -> Result<(), InvalidAttestation> {
|
) -> Result<(), InvalidAttestation> {
|
||||||
// There is no point in processing an attestation with an empty bitfield. Reject
|
// There is no point in processing an attestation with an empty bitfield. Reject
|
||||||
// it immediately.
|
// it immediately.
|
||||||
@@ -1117,11 +1130,17 @@ where
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Same-slot attestations must have index == 0 (i.e., indicate pending payload status).
|
// Post-GLOAS: same-slot attestations with index != 0 indicate a payload-present vote.
|
||||||
// Payload-present attestations (index == 1) for the same slot as the block are invalid
|
// These must go through `on_payload_attestation`, not `on_attestation`.
|
||||||
// because PTC votes should only arrive in subsequent slots.
|
if spec
|
||||||
if indexed_attestation.data().slot == block.slot && indexed_attestation.data().index != 0 {
|
.fork_name_at_slot::<E>(indexed_attestation.data().slot)
|
||||||
return Err(InvalidAttestation::PayloadAttestationDuringSameSlot { slot: block.slot });
|
.gloas_enabled()
|
||||||
|
&& indexed_attestation.data().slot == block.slot
|
||||||
|
&& indexed_attestation.data().index != 0
|
||||||
|
{
|
||||||
|
return Err(InvalidAttestation::PayloadAttestationDuringSameSlot {
|
||||||
|
slot: block.slot,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -1182,6 +1201,7 @@ where
|
|||||||
system_time_current_slot: Slot,
|
system_time_current_slot: Slot,
|
||||||
attestation: IndexedAttestationRef<E>,
|
attestation: IndexedAttestationRef<E>,
|
||||||
is_from_block: AttestationFromBlock,
|
is_from_block: AttestationFromBlock,
|
||||||
|
spec: &ChainSpec,
|
||||||
) -> Result<(), Error<T::Error>> {
|
) -> Result<(), Error<T::Error>> {
|
||||||
let _timer = metrics::start_timer(&metrics::FORK_CHOICE_ON_ATTESTATION_TIMES);
|
let _timer = metrics::start_timer(&metrics::FORK_CHOICE_ON_ATTESTATION_TIMES);
|
||||||
|
|
||||||
@@ -1204,7 +1224,7 @@ where
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
self.validate_on_attestation(attestation, is_from_block)?;
|
self.validate_on_attestation(attestation, is_from_block, spec)?;
|
||||||
|
|
||||||
if attestation.data().slot < self.fc_store.get_current_slot() {
|
if attestation.data().slot < self.fc_store.get_current_slot() {
|
||||||
for validator_index in attestation.attesting_indices_iter() {
|
for validator_index in attestation.attesting_indices_iter() {
|
||||||
@@ -1720,7 +1740,7 @@ pub struct PersistedForkChoice {
|
|||||||
#[superstruct(only(V17))]
|
#[superstruct(only(V17))]
|
||||||
pub proto_array_bytes: Vec<u8>,
|
pub proto_array_bytes: Vec<u8>,
|
||||||
#[superstruct(only(V28))]
|
#[superstruct(only(V28))]
|
||||||
pub proto_array_v28: proto_array::core::SszContainerLegacyV28,
|
pub proto_array_v28: proto_array::core::SszContainerV28,
|
||||||
#[superstruct(only(V29))]
|
#[superstruct(only(V29))]
|
||||||
pub proto_array: proto_array::core::SszContainerV29,
|
pub proto_array: proto_array::core::SszContainerV29,
|
||||||
pub queued_attestations: Vec<QueuedAttestation>,
|
pub queued_attestations: Vec<QueuedAttestation>,
|
||||||
@@ -1735,8 +1755,8 @@ impl TryFrom<PersistedForkChoiceV17> for PersistedForkChoiceV28 {
|
|||||||
|
|
||||||
fn try_from(v17: PersistedForkChoiceV17) -> Result<Self, Self::Error> {
|
fn try_from(v17: PersistedForkChoiceV17) -> Result<Self, Self::Error> {
|
||||||
let container_v17 =
|
let container_v17 =
|
||||||
proto_array::core::SszContainerLegacyV17::from_ssz_bytes(&v17.proto_array_bytes)?;
|
proto_array::core::SszContainerV17::from_ssz_bytes(&v17.proto_array_bytes)?;
|
||||||
let container_v28: proto_array::core::SszContainerLegacyV28 = container_v17.into();
|
let container_v28: proto_array::core::SszContainerV28 = container_v17.into();
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
proto_array_v28: container_v28,
|
proto_array_v28: container_v28,
|
||||||
@@ -1758,7 +1778,7 @@ impl From<PersistedForkChoiceV28> for PersistedForkChoiceV29 {
|
|||||||
impl From<(PersistedForkChoiceV28, JustifiedBalances)> for PersistedForkChoiceV17 {
|
impl From<(PersistedForkChoiceV28, JustifiedBalances)> for PersistedForkChoiceV17 {
|
||||||
fn from((v28, balances): (PersistedForkChoiceV28, JustifiedBalances)) -> Self {
|
fn from((v28, balances): (PersistedForkChoiceV28, JustifiedBalances)) -> Self {
|
||||||
let container_v17 =
|
let container_v17 =
|
||||||
proto_array::core::SszContainerLegacyV17::from((v28.proto_array_v28, balances));
|
proto_array::core::SszContainerV17::from((v28.proto_array_v28, balances));
|
||||||
let proto_array_bytes = container_v17.as_ssz_bytes();
|
let proto_array_bytes = container_v17.as_ssz_bytes();
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
|
|||||||
@@ -73,6 +73,22 @@ impl ForkChoiceTest {
|
|||||||
Self { harness }
|
Self { harness }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a new tester with the GLOAS fork active at epoch 1.
|
||||||
|
/// Genesis is a standard Fulu block (epoch 0), so block production works normally.
|
||||||
|
/// Tests that need GLOAS semantics should advance the chain into epoch 1 first.
|
||||||
|
pub fn new_with_gloas() -> Self {
|
||||||
|
let mut spec = ForkName::latest_stable().make_genesis_spec(ChainSpec::default());
|
||||||
|
spec.gloas_fork_epoch = Some(Epoch::new(1));
|
||||||
|
let harness = BeaconChainHarness::builder(MainnetEthSpec)
|
||||||
|
.spec(spec.into())
|
||||||
|
.deterministic_keypairs(VALIDATOR_COUNT)
|
||||||
|
.fresh_ephemeral_store()
|
||||||
|
.mock_execution_layer()
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Self { harness }
|
||||||
|
}
|
||||||
|
|
||||||
/// Get a value from the `ForkChoice` instantiation.
|
/// Get a value from the `ForkChoice` instantiation.
|
||||||
fn get<T, U>(&self, func: T) -> U
|
fn get<T, U>(&self, func: T) -> U
|
||||||
where
|
where
|
||||||
@@ -948,9 +964,17 @@ async fn invalid_attestation_future_block() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Payload attestations (index == 1) are invalid when they refer to a block in the same slot.
|
/// Payload attestations (index == 1) are invalid when they refer to a block in the same slot.
|
||||||
|
/// This check only applies when GLOAS is active.
|
||||||
|
///
|
||||||
|
/// TODO(gloas): un-ignore once the test harness supports Gloas block production.
|
||||||
|
/// The validation logic is gated on `spec.fork_name_at_slot().gloas_enabled()` in
|
||||||
|
/// `validate_on_attestation`, which requires a block to exist at a GLOAS-enabled slot.
|
||||||
|
/// Currently the mock execution layer cannot produce Gloas blocks (no
|
||||||
|
/// `signed_execution_payload_bid` support).
|
||||||
|
#[ignore]
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn invalid_attestation_payload_during_same_slot() {
|
async fn invalid_attestation_payload_during_same_slot() {
|
||||||
ForkChoiceTest::new()
|
ForkChoiceTest::new_with_gloas()
|
||||||
.apply_blocks_without_new_attestations(1)
|
.apply_blocks_without_new_attestations(1)
|
||||||
.await
|
.await
|
||||||
.apply_attestation_to_chain(
|
.apply_attestation_to_chain(
|
||||||
|
|||||||
@@ -17,6 +17,6 @@ pub mod core {
|
|||||||
pub use super::proto_array::{ProposerBoost, ProtoArray, ProtoNode};
|
pub use super::proto_array::{ProposerBoost, ProtoArray, ProtoNode};
|
||||||
pub use super::proto_array_fork_choice::VoteTracker;
|
pub use super::proto_array_fork_choice::VoteTracker;
|
||||||
pub use super::ssz_container::{
|
pub use super::ssz_container::{
|
||||||
SszContainer, SszContainerLegacyV17, SszContainerLegacyV28, SszContainerV29,
|
SszContainer, SszContainerV17, SszContainerV28, SszContainerV29,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ use crate::{
|
|||||||
use ssz::{Encode, four_byte_option_impl};
|
use ssz::{Encode, four_byte_option_impl};
|
||||||
use ssz_derive::{Decode, Encode};
|
use ssz_derive::{Decode, Encode};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use superstruct::superstruct;
|
|
||||||
use types::{Checkpoint, Hash256};
|
use types::{Checkpoint, Hash256};
|
||||||
|
|
||||||
// Define a "legacy" implementation of `Option<usize>` which uses four bytes for encoding the union
|
// Define a "legacy" implementation of `Option<usize>` which uses four bytes for encoding the union
|
||||||
@@ -16,15 +15,10 @@ four_byte_option_impl!(four_byte_option_checkpoint, Checkpoint);
|
|||||||
|
|
||||||
pub type SszContainer = SszContainerV29;
|
pub type SszContainer = SszContainerV29;
|
||||||
|
|
||||||
// Legacy containers (V17/V28) for backward compatibility with older schema versions.
|
/// Proto-array container introduced in schema V17.
|
||||||
#[superstruct(
|
#[derive(Encode, Decode, Clone)]
|
||||||
variants(V17, V28),
|
pub struct SszContainerV17 {
|
||||||
variant_attributes(derive(Encode, Decode, Clone)),
|
|
||||||
no_enum
|
|
||||||
)]
|
|
||||||
pub struct SszContainerLegacy {
|
|
||||||
pub votes: Vec<VoteTracker>,
|
pub votes: Vec<VoteTracker>,
|
||||||
#[superstruct(only(V17))]
|
|
||||||
pub balances: Vec<u64>,
|
pub balances: Vec<u64>,
|
||||||
pub prune_threshold: usize,
|
pub prune_threshold: usize,
|
||||||
// Deprecated, remove in a future schema migration
|
// Deprecated, remove in a future schema migration
|
||||||
@@ -36,6 +30,20 @@ pub struct SszContainerLegacy {
|
|||||||
pub previous_proposer_boost: ProposerBoost,
|
pub previous_proposer_boost: ProposerBoost,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Proto-array container introduced in schema V28.
|
||||||
|
#[derive(Encode, Decode, Clone)]
|
||||||
|
pub struct SszContainerV28 {
|
||||||
|
pub votes: Vec<VoteTracker>,
|
||||||
|
pub prune_threshold: usize,
|
||||||
|
// Deprecated, remove in a future schema migration
|
||||||
|
justified_checkpoint: Checkpoint,
|
||||||
|
// Deprecated, remove in a future schema migration
|
||||||
|
finalized_checkpoint: Checkpoint,
|
||||||
|
pub nodes: Vec<ProtoNodeV17>,
|
||||||
|
pub indices: Vec<(Hash256, usize)>,
|
||||||
|
pub previous_proposer_boost: ProposerBoost,
|
||||||
|
}
|
||||||
|
|
||||||
/// Current container version. Uses union-encoded `ProtoNode` to support mixed V17/V29 nodes.
|
/// Current container version. Uses union-encoded `ProtoNode` to support mixed V17/V29 nodes.
|
||||||
#[derive(Encode, Decode, Clone)]
|
#[derive(Encode, Decode, Clone)]
|
||||||
pub struct SszContainerV29 {
|
pub struct SszContainerV29 {
|
||||||
@@ -90,8 +98,8 @@ impl TryFrom<(SszContainerV29, JustifiedBalances)> for ProtoArrayForkChoice {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Convert legacy V17 to V28 by dropping balances.
|
// Convert legacy V17 to V28 by dropping balances.
|
||||||
impl From<SszContainerLegacyV17> for SszContainerLegacyV28 {
|
impl From<SszContainerV17> for SszContainerV28 {
|
||||||
fn from(v17: SszContainerLegacyV17) -> Self {
|
fn from(v17: SszContainerV17) -> Self {
|
||||||
Self {
|
Self {
|
||||||
votes: v17.votes,
|
votes: v17.votes,
|
||||||
prune_threshold: v17.prune_threshold,
|
prune_threshold: v17.prune_threshold,
|
||||||
@@ -105,8 +113,8 @@ impl From<SszContainerLegacyV17> for SszContainerLegacyV28 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Convert legacy V28 to V17 by re-adding balances.
|
// Convert legacy V28 to V17 by re-adding balances.
|
||||||
impl From<(SszContainerLegacyV28, JustifiedBalances)> for SszContainerLegacyV17 {
|
impl From<(SszContainerV28, JustifiedBalances)> for SszContainerV17 {
|
||||||
fn from((v28, balances): (SszContainerLegacyV28, JustifiedBalances)) -> Self {
|
fn from((v28, balances): (SszContainerV28, JustifiedBalances)) -> Self {
|
||||||
Self {
|
Self {
|
||||||
votes: v28.votes,
|
votes: v28.votes,
|
||||||
balances: balances.effective_balances.clone(),
|
balances: balances.effective_balances.clone(),
|
||||||
@@ -121,8 +129,8 @@ impl From<(SszContainerLegacyV28, JustifiedBalances)> for SszContainerLegacyV17
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Convert legacy V28 to current V29.
|
// Convert legacy V28 to current V29.
|
||||||
impl From<SszContainerLegacyV28> for SszContainerV29 {
|
impl From<SszContainerV28> for SszContainerV29 {
|
||||||
fn from(v28: SszContainerLegacyV28) -> Self {
|
fn from(v28: SszContainerV28) -> Self {
|
||||||
Self {
|
Self {
|
||||||
votes: v28.votes,
|
votes: v28.votes,
|
||||||
prune_threshold: v28.prune_threshold,
|
prune_threshold: v28.prune_threshold,
|
||||||
@@ -136,7 +144,7 @@ impl From<SszContainerLegacyV28> for SszContainerV29 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Downgrade current V29 to legacy V28 (lossy: V29 nodes lose payload-specific fields).
|
// Downgrade current V29 to legacy V28 (lossy: V29 nodes lose payload-specific fields).
|
||||||
impl From<SszContainerV29> for SszContainerLegacyV28 {
|
impl From<SszContainerV29> for SszContainerV28 {
|
||||||
fn from(v29: SszContainerV29) -> Self {
|
fn from(v29: SszContainerV29) -> Self {
|
||||||
Self {
|
Self {
|
||||||
votes: v29.votes,
|
votes: v29.votes,
|
||||||
|
|||||||
Reference in New Issue
Block a user