mirror of
https://github.com/sigp/lighthouse.git
synced 2026-05-30 12:47:05 +00:00
use correct state
This commit is contained in:
@@ -1,27 +1,24 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::{
|
||||
BeaconChain, BeaconChainTypes, CanonicalHead,
|
||||
BeaconChain, BeaconChainTypes, BeaconStore, CanonicalHead,
|
||||
proposer_preferences_verification::{
|
||||
ProposerPreferencesError, proposer_preference_cache::GossipVerifiedProposerPreferenceCache,
|
||||
},
|
||||
};
|
||||
use slot_clock::SlotClock;
|
||||
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 types::{
|
||||
BeaconState, ChainSpec, EthSpec, ProposerPreferences, SignedProposerPreferences, Slot,
|
||||
};
|
||||
use types::{ChainSpec, EthSpec, ProposerPreferences, SignedProposerPreferences, Slot};
|
||||
|
||||
/// Verify that proposer preferences are consistent with the current chain state
|
||||
pub(crate) fn verify_preferences_consistency<E: EthSpec>(
|
||||
preferences: &ProposerPreferences,
|
||||
current_slot: Slot,
|
||||
head_state: &BeaconState<E>,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<(), ProposerPreferencesError> {
|
||||
let proposal_slot = preferences.proposal_slot;
|
||||
let validator_index = preferences.validator_index;
|
||||
let current_epoch = current_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(())
|
||||
}
|
||||
|
||||
@@ -53,6 +43,7 @@ pub struct GossipVerificationContext<'a, T: BeaconChainTypes> {
|
||||
pub gossip_verified_proposer_preferences_cache: &'a GossipVerifiedProposerPreferenceCache,
|
||||
pub slot_clock: &'a T::SlotClock,
|
||||
pub spec: &'a ChainSpec,
|
||||
pub store: &'a BeaconStore<T>,
|
||||
}
|
||||
|
||||
/// A wrapper around `SignedProposerPreferences` that has been verified for gossip propagation.
|
||||
@@ -74,7 +65,6 @@ impl GossipVerifiedProposerPreferences {
|
||||
.slot_clock
|
||||
.now()
|
||||
.ok_or(ProposerPreferencesError::UnableToReadSlot)?;
|
||||
let head_state = &cached_head.snapshot.beacon_state;
|
||||
|
||||
if ctx
|
||||
.gossip_verified_proposer_preferences_cache
|
||||
@@ -86,17 +76,61 @@ impl GossipVerifiedProposerPreferences {
|
||||
});
|
||||
}
|
||||
|
||||
verify_preferences_consistency(
|
||||
verify_preferences_consistency::<T::EthSpec>(
|
||||
&signed_preferences.message,
|
||||
current_slot,
|
||||
head_state,
|
||||
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(
|
||||
head_state,
|
||||
|i| get_pubkey_from_state(head_state, i),
|
||||
&dependent_state,
|
||||
|i| get_pubkey_from_state(&dependent_state, i),
|
||||
&signed_preferences,
|
||||
ctx.spec,
|
||||
)
|
||||
@@ -127,6 +161,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
.gossip_verified_proposer_preferences_cache,
|
||||
slot_clock: &self.slot_clock,
|
||||
spec: &self.spec,
|
||||
store: &self.store,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -162,10 +197,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use types::{
|
||||
Address, BeaconState, ChainSpec, EthSpec, Hash256, MinimalEthSpec, ProposerPreferences,
|
||||
Slot,
|
||||
};
|
||||
use types::{Address, ChainSpec, EthSpec, Hash256, MinimalEthSpec, ProposerPreferences, Slot};
|
||||
|
||||
use super::verify_preferences_consistency;
|
||||
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 {
|
||||
test_spec::<E>()
|
||||
}
|
||||
@@ -200,7 +227,7 @@ mod tests {
|
||||
let current_slot = Slot::new(2 * E::slots_per_epoch());
|
||||
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!(
|
||||
result,
|
||||
Err(ProposerPreferencesError::InvalidProposalEpoch { .. })
|
||||
@@ -215,7 +242,7 @@ mod tests {
|
||||
let current_slot = Slot::new(E::slots_per_epoch());
|
||||
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!(
|
||||
result,
|
||||
Err(ProposerPreferencesError::InvalidProposalEpoch { .. })
|
||||
@@ -230,7 +257,7 @@ mod tests {
|
||||
let current_slot = Slot::new(10);
|
||||
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!(
|
||||
result,
|
||||
Err(ProposerPreferencesError::ProposalSlotAlreadyPassed { .. })
|
||||
@@ -245,7 +272,7 @@ mod tests {
|
||||
let current_slot = Slot::new(10);
|
||||
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!(
|
||||
result,
|
||||
Err(ProposerPreferencesError::ProposalSlotAlreadyPassed { .. })
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use types::{BeaconStateError, Epoch, Slot};
|
||||
use types::{BeaconStateError, Epoch, Hash256, Slot};
|
||||
|
||||
use crate::BeaconChainError;
|
||||
|
||||
@@ -38,6 +38,10 @@ pub enum ProposerPreferencesError {
|
||||
},
|
||||
/// The slot clock cannot be read.
|
||||
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.
|
||||
AlreadySeen {
|
||||
validator_index: u64,
|
||||
|
||||
Reference in New Issue
Block a user