mirror of
https://github.com/sigp/lighthouse.git
synced 2026-05-30 04:37:13 +00:00
use correct state
This commit is contained in:
@@ -1,27 +1,24 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
BeaconChain, BeaconChainTypes, CanonicalHead,
|
BeaconChain, BeaconChainTypes, BeaconStore, CanonicalHead,
|
||||||
proposer_preferences_verification::{
|
proposer_preferences_verification::{
|
||||||
ProposerPreferencesError, proposer_preference_cache::GossipVerifiedProposerPreferenceCache,
|
ProposerPreferencesError, proposer_preference_cache::GossipVerifiedProposerPreferenceCache,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use slot_clock::SlotClock;
|
use slot_clock::SlotClock;
|
||||||
use state_processing::signature_sets::{get_pubkey_from_state, proposer_preferences_signature_set};
|
use state_processing::signature_sets::{get_pubkey_from_state, proposer_preferences_signature_set};
|
||||||
|
use state_processing::state_advance::partial_state_advance;
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
use types::{
|
use types::{ChainSpec, EthSpec, ProposerPreferences, SignedProposerPreferences, Slot};
|
||||||
BeaconState, ChainSpec, EthSpec, ProposerPreferences, SignedProposerPreferences, Slot,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Verify that proposer preferences are consistent with the current chain state
|
/// Verify that proposer preferences are consistent with the current chain state
|
||||||
pub(crate) fn verify_preferences_consistency<E: EthSpec>(
|
pub(crate) fn verify_preferences_consistency<E: EthSpec>(
|
||||||
preferences: &ProposerPreferences,
|
preferences: &ProposerPreferences,
|
||||||
current_slot: Slot,
|
current_slot: Slot,
|
||||||
head_state: &BeaconState<E>,
|
|
||||||
spec: &ChainSpec,
|
spec: &ChainSpec,
|
||||||
) -> Result<(), ProposerPreferencesError> {
|
) -> Result<(), ProposerPreferencesError> {
|
||||||
let proposal_slot = preferences.proposal_slot;
|
let proposal_slot = preferences.proposal_slot;
|
||||||
let validator_index = preferences.validator_index;
|
|
||||||
let current_epoch = current_slot.epoch(E::slots_per_epoch());
|
let current_epoch = current_slot.epoch(E::slots_per_epoch());
|
||||||
let proposal_epoch = proposal_slot.epoch(E::slots_per_epoch());
|
let proposal_epoch = proposal_slot.epoch(E::slots_per_epoch());
|
||||||
|
|
||||||
@@ -38,13 +35,6 @@ pub(crate) fn verify_preferences_consistency<E: EthSpec>(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if !head_state.is_valid_proposal_slot(preferences, spec)? {
|
|
||||||
return Err(ProposerPreferencesError::InvalidProposalSlot {
|
|
||||||
validator_index,
|
|
||||||
proposal_slot,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -53,6 +43,7 @@ pub struct GossipVerificationContext<'a, T: BeaconChainTypes> {
|
|||||||
pub gossip_verified_proposer_preferences_cache: &'a GossipVerifiedProposerPreferenceCache,
|
pub gossip_verified_proposer_preferences_cache: &'a GossipVerifiedProposerPreferenceCache,
|
||||||
pub slot_clock: &'a T::SlotClock,
|
pub slot_clock: &'a T::SlotClock,
|
||||||
pub spec: &'a ChainSpec,
|
pub spec: &'a ChainSpec,
|
||||||
|
pub store: &'a BeaconStore<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A wrapper around `SignedProposerPreferences` that has been verified for gossip propagation.
|
/// A wrapper around `SignedProposerPreferences` that has been verified for gossip propagation.
|
||||||
@@ -74,7 +65,6 @@ impl GossipVerifiedProposerPreferences {
|
|||||||
.slot_clock
|
.slot_clock
|
||||||
.now()
|
.now()
|
||||||
.ok_or(ProposerPreferencesError::UnableToReadSlot)?;
|
.ok_or(ProposerPreferencesError::UnableToReadSlot)?;
|
||||||
let head_state = &cached_head.snapshot.beacon_state;
|
|
||||||
|
|
||||||
if ctx
|
if ctx
|
||||||
.gossip_verified_proposer_preferences_cache
|
.gossip_verified_proposer_preferences_cache
|
||||||
@@ -86,17 +76,61 @@ impl GossipVerifiedProposerPreferences {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
verify_preferences_consistency(
|
verify_preferences_consistency::<T::EthSpec>(
|
||||||
&signed_preferences.message,
|
&signed_preferences.message,
|
||||||
current_slot,
|
current_slot,
|
||||||
head_state,
|
|
||||||
ctx.spec,
|
ctx.spec,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// Verify signature
|
// Get the block at dependent_root from fork choice to verify canonicity and get state_root
|
||||||
|
let fork_choice = ctx.canonical_head.fork_choice_read_lock();
|
||||||
|
let dependent_block = fork_choice
|
||||||
|
.get_block(&dependent_root)
|
||||||
|
.ok_or(ProposerPreferencesError::DependentRootUnknown { dependent_root })?;
|
||||||
|
let head_root = cached_head.head_block_root();
|
||||||
|
if !fork_choice.is_descendant(dependent_root, head_root) {
|
||||||
|
return Err(ProposerPreferencesError::DependentRootNotCanonical { dependent_root });
|
||||||
|
}
|
||||||
|
let dependent_state_root = dependent_block.state_root;
|
||||||
|
let dependent_block_slot = dependent_block.slot;
|
||||||
|
drop(fork_choice);
|
||||||
|
|
||||||
|
// Fetch the state at the dependent_root block.
|
||||||
|
// Per spec, we need the checkpoint state at epoch (proposal_epoch - MIN_SEED_LOOKAHEAD).
|
||||||
|
// The dependent_root is the block root at the proposer shuffling decision slot.
|
||||||
|
let (state_root, mut dependent_state) = ctx
|
||||||
|
.store
|
||||||
|
.get_advanced_hot_state(dependent_root, dependent_block_slot, dependent_state_root)
|
||||||
|
.map_err(crate::BeaconChainError::DBError)?
|
||||||
|
.ok_or(ProposerPreferencesError::DependentRootUnknown { dependent_root })?;
|
||||||
|
|
||||||
|
// We need to advance the state to `target_epoch` so epoch transition runs and
|
||||||
|
// `process_proposer_lookahead` populates the lookahead for the proposal epoch.
|
||||||
|
let proposal_epoch = proposal_slot.epoch(T::EthSpec::slots_per_epoch());
|
||||||
|
let target_epoch = proposal_epoch.saturating_sub(ctx.spec.min_seed_lookahead);
|
||||||
|
let target_slot = target_epoch.start_slot(T::EthSpec::slots_per_epoch());
|
||||||
|
|
||||||
|
if dependent_state.current_epoch() < target_epoch {
|
||||||
|
partial_state_advance(
|
||||||
|
&mut dependent_state,
|
||||||
|
Some(state_root),
|
||||||
|
target_slot,
|
||||||
|
ctx.spec,
|
||||||
|
)
|
||||||
|
.map_err(crate::BeaconChainError::StateAdvanceError)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !dependent_state.is_valid_proposal_slot(&signed_preferences.message, ctx.spec)? {
|
||||||
|
return Err(ProposerPreferencesError::InvalidProposalSlot {
|
||||||
|
validator_index,
|
||||||
|
proposal_slot,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify signature using the dependent state (which has the validator pubkeys)
|
||||||
proposer_preferences_signature_set(
|
proposer_preferences_signature_set(
|
||||||
head_state,
|
&dependent_state,
|
||||||
|i| get_pubkey_from_state(head_state, i),
|
|i| get_pubkey_from_state(&dependent_state, i),
|
||||||
&signed_preferences,
|
&signed_preferences,
|
||||||
ctx.spec,
|
ctx.spec,
|
||||||
)
|
)
|
||||||
@@ -127,6 +161,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
|||||||
.gossip_verified_proposer_preferences_cache,
|
.gossip_verified_proposer_preferences_cache,
|
||||||
slot_clock: &self.slot_clock,
|
slot_clock: &self.slot_clock,
|
||||||
spec: &self.spec,
|
spec: &self.spec,
|
||||||
|
store: &self.store,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,10 +197,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use types::{
|
use types::{Address, ChainSpec, EthSpec, Hash256, MinimalEthSpec, ProposerPreferences, Slot};
|
||||||
Address, BeaconState, ChainSpec, EthSpec, Hash256, MinimalEthSpec, ProposerPreferences,
|
|
||||||
Slot,
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::verify_preferences_consistency;
|
use super::verify_preferences_consistency;
|
||||||
use crate::proposer_preferences_verification::ProposerPreferencesError;
|
use crate::proposer_preferences_verification::ProposerPreferencesError;
|
||||||
@@ -183,11 +215,6 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn state() -> BeaconState<E> {
|
|
||||||
let spec = spec();
|
|
||||||
BeaconState::new(0, <_>::default(), &spec)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn spec() -> ChainSpec {
|
fn spec() -> ChainSpec {
|
||||||
test_spec::<E>()
|
test_spec::<E>()
|
||||||
}
|
}
|
||||||
@@ -200,7 +227,7 @@ mod tests {
|
|||||||
let current_slot = Slot::new(2 * E::slots_per_epoch());
|
let current_slot = Slot::new(2 * E::slots_per_epoch());
|
||||||
let prefs = make_preferences(Slot::new(3), 0);
|
let prefs = make_preferences(Slot::new(3), 0);
|
||||||
|
|
||||||
let result = verify_preferences_consistency::<E>(&prefs, current_slot, &state(), &spec());
|
let result = verify_preferences_consistency::<E>(&prefs, current_slot, &spec());
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
result,
|
result,
|
||||||
Err(ProposerPreferencesError::InvalidProposalEpoch { .. })
|
Err(ProposerPreferencesError::InvalidProposalEpoch { .. })
|
||||||
@@ -215,7 +242,7 @@ mod tests {
|
|||||||
let current_slot = Slot::new(E::slots_per_epoch());
|
let current_slot = Slot::new(E::slots_per_epoch());
|
||||||
let prefs = make_preferences(Slot::new(3 * E::slots_per_epoch() + 1), 0);
|
let prefs = make_preferences(Slot::new(3 * E::slots_per_epoch() + 1), 0);
|
||||||
|
|
||||||
let result = verify_preferences_consistency::<E>(&prefs, current_slot, &state(), &spec());
|
let result = verify_preferences_consistency::<E>(&prefs, current_slot, &spec());
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
result,
|
result,
|
||||||
Err(ProposerPreferencesError::InvalidProposalEpoch { .. })
|
Err(ProposerPreferencesError::InvalidProposalEpoch { .. })
|
||||||
@@ -230,7 +257,7 @@ mod tests {
|
|||||||
let current_slot = Slot::new(10);
|
let current_slot = Slot::new(10);
|
||||||
let prefs = make_preferences(Slot::new(9), 0);
|
let prefs = make_preferences(Slot::new(9), 0);
|
||||||
|
|
||||||
let result = verify_preferences_consistency::<E>(&prefs, current_slot, &state(), &spec());
|
let result = verify_preferences_consistency::<E>(&prefs, current_slot, &spec());
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
result,
|
result,
|
||||||
Err(ProposerPreferencesError::ProposalSlotAlreadyPassed { .. })
|
Err(ProposerPreferencesError::ProposalSlotAlreadyPassed { .. })
|
||||||
@@ -245,7 +272,7 @@ mod tests {
|
|||||||
let current_slot = Slot::new(10);
|
let current_slot = Slot::new(10);
|
||||||
let prefs = make_preferences(Slot::new(10), 0);
|
let prefs = make_preferences(Slot::new(10), 0);
|
||||||
|
|
||||||
let result = verify_preferences_consistency::<E>(&prefs, current_slot, &state(), &spec());
|
let result = verify_preferences_consistency::<E>(&prefs, current_slot, &spec());
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
result,
|
result,
|
||||||
Err(ProposerPreferencesError::ProposalSlotAlreadyPassed { .. })
|
Err(ProposerPreferencesError::ProposalSlotAlreadyPassed { .. })
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use types::{BeaconStateError, Epoch, Slot};
|
use types::{BeaconStateError, Epoch, Hash256, Slot};
|
||||||
|
|
||||||
use crate::BeaconChainError;
|
use crate::BeaconChainError;
|
||||||
|
|
||||||
@@ -38,6 +38,10 @@ pub enum ProposerPreferencesError {
|
|||||||
},
|
},
|
||||||
/// The slot clock cannot be read.
|
/// The slot clock cannot be read.
|
||||||
UnableToReadSlot,
|
UnableToReadSlot,
|
||||||
|
/// The block with root `dependent_root` has not been seen.
|
||||||
|
DependentRootUnknown { dependent_root: Hash256 },
|
||||||
|
/// The block with root `dependent_root` is not canonical.
|
||||||
|
DependentRootNotCanonical { dependent_root: Hash256 },
|
||||||
/// A valid message from this validator for this slot has already been seen.
|
/// A valid message from this validator for this slot has already been seen.
|
||||||
AlreadySeen {
|
AlreadySeen {
|
||||||
validator_index: u64,
|
validator_index: u64,
|
||||||
|
|||||||
Reference in New Issue
Block a user