mirror of
https://github.com/sigp/lighthouse.git
synced 2026-05-30 12:47:05 +00:00
merge conflicts
This commit is contained in:
@@ -147,7 +147,7 @@ fn build_rpc_block(
|
||||
RpcBlock::new_with_custody_columns(None, block, columns.clone(), columns.len(), spec)
|
||||
.unwrap()
|
||||
}
|
||||
None => RpcBlock::new_without_blobs(None, block),
|
||||
None => RpcBlock::new_without_blobs(None, block, 0),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -370,6 +370,7 @@ async fn chain_segment_non_linear_parent_roots() {
|
||||
blocks[3] = RpcBlock::new_without_blobs(
|
||||
None,
|
||||
Arc::new(SignedBeaconBlock::from_block(block, signature)),
|
||||
harness.sampling_column_count,
|
||||
);
|
||||
|
||||
assert!(
|
||||
@@ -407,6 +408,7 @@ async fn chain_segment_non_linear_slots() {
|
||||
blocks[3] = RpcBlock::new_without_blobs(
|
||||
None,
|
||||
Arc::new(SignedBeaconBlock::from_block(block, signature)),
|
||||
harness.sampling_column_count,
|
||||
);
|
||||
|
||||
assert!(
|
||||
@@ -434,6 +436,7 @@ async fn chain_segment_non_linear_slots() {
|
||||
blocks[3] = RpcBlock::new_without_blobs(
|
||||
None,
|
||||
Arc::new(SignedBeaconBlock::from_block(block, signature)),
|
||||
harness.sampling_column_count,
|
||||
);
|
||||
|
||||
assert!(
|
||||
@@ -575,11 +578,16 @@ async fn invalid_signature_gossip_block() {
|
||||
.into_block_error()
|
||||
.expect("should import all blocks prior to the one being tested");
|
||||
let signed_block = SignedBeaconBlock::from_block(block, junk_signature());
|
||||
let rpc_block = RpcBlock::new_without_blobs(
|
||||
None,
|
||||
Arc::new(signed_block),
|
||||
harness.sampling_column_count,
|
||||
);
|
||||
let process_res = harness
|
||||
.chain
|
||||
.process_block(
|
||||
signed_block.canonical_root(),
|
||||
Arc::new(signed_block),
|
||||
rpc_block.block_root(),
|
||||
rpc_block,
|
||||
NotifyExecutionLayer::Yes,
|
||||
BlockImportSource::Lookup,
|
||||
|| Ok(()),
|
||||
@@ -1550,12 +1558,13 @@ async fn add_base_block_to_altair_chain() {
|
||||
));
|
||||
|
||||
// Ensure that it would be impossible to import via `BeaconChain::process_block`.
|
||||
let base_rpc_block = RpcBlock::new_without_blobs(None, Arc::new(base_block.clone()), 0);
|
||||
assert!(matches!(
|
||||
harness
|
||||
.chain
|
||||
.process_block(
|
||||
base_block.canonical_root(),
|
||||
Arc::new(base_block.clone()),
|
||||
base_rpc_block.block_root(),
|
||||
base_rpc_block,
|
||||
NotifyExecutionLayer::Yes,
|
||||
BlockImportSource::Lookup,
|
||||
|| Ok(()),
|
||||
@@ -1573,7 +1582,7 @@ async fn add_base_block_to_altair_chain() {
|
||||
harness
|
||||
.chain
|
||||
.process_chain_segment(
|
||||
vec![RpcBlock::new_without_blobs(None, Arc::new(base_block))],
|
||||
vec![RpcBlock::new_without_blobs(None, Arc::new(base_block), 0)],
|
||||
NotifyExecutionLayer::Yes,
|
||||
)
|
||||
.await,
|
||||
@@ -1686,12 +1695,13 @@ async fn add_altair_block_to_base_chain() {
|
||||
));
|
||||
|
||||
// Ensure that it would be impossible to import via `BeaconChain::process_block`.
|
||||
let altair_rpc_block = RpcBlock::new_without_blobs(None, Arc::new(altair_block.clone()), 0);
|
||||
assert!(matches!(
|
||||
harness
|
||||
.chain
|
||||
.process_block(
|
||||
altair_block.canonical_root(),
|
||||
Arc::new(altair_block.clone()),
|
||||
altair_rpc_block.block_root(),
|
||||
altair_rpc_block,
|
||||
NotifyExecutionLayer::Yes,
|
||||
BlockImportSource::Lookup,
|
||||
|| Ok(()),
|
||||
@@ -1709,7 +1719,7 @@ async fn add_altair_block_to_base_chain() {
|
||||
harness
|
||||
.chain
|
||||
.process_chain_segment(
|
||||
vec![RpcBlock::new_without_blobs(None, Arc::new(altair_block))],
|
||||
vec![RpcBlock::new_without_blobs(None, Arc::new(altair_block), 0)],
|
||||
NotifyExecutionLayer::Yes
|
||||
)
|
||||
.await,
|
||||
@@ -1770,11 +1780,16 @@ async fn import_duplicate_block_unrealized_justification() {
|
||||
// Create two verified variants of the block, representing the same block being processed in
|
||||
// parallel.
|
||||
let notify_execution_layer = NotifyExecutionLayer::Yes;
|
||||
let verified_block1 = block
|
||||
let rpc_block = RpcBlock::new_without_blobs(
|
||||
Some(block_root),
|
||||
block.clone(),
|
||||
harness.sampling_column_count,
|
||||
);
|
||||
let verified_block1 = rpc_block
|
||||
.clone()
|
||||
.into_execution_pending_block(block_root, chain, notify_execution_layer)
|
||||
.unwrap();
|
||||
let verified_block2 = block
|
||||
let verified_block2 = rpc_block
|
||||
.into_execution_pending_block(block_root, chain, notify_execution_layer)
|
||||
.unwrap();
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#![cfg(not(debug_assertions))]
|
||||
|
||||
use beacon_chain::block_verification_types::RpcBlock;
|
||||
use beacon_chain::{
|
||||
canonical_head::{CachedHead, CanonicalHead},
|
||||
test_utils::{BeaconChainHarness, EphemeralHarnessType},
|
||||
@@ -507,13 +508,11 @@ async fn justified_checkpoint_becomes_invalid() {
|
||||
let is_valid = Payload::Invalid {
|
||||
latest_valid_hash: Some(parent_hash_of_justified),
|
||||
};
|
||||
rig.import_block_parametric(is_valid, is_valid, None, |error| {
|
||||
matches!(
|
||||
error,
|
||||
// The block import should fail since the beacon chain knows the justified payload
|
||||
// is invalid.
|
||||
BlockError::BeaconChainError(BeaconChainError::JustifiedPayloadInvalid { .. })
|
||||
)
|
||||
rig.import_block_parametric(is_valid, is_valid, None, |error| match error {
|
||||
BlockError::BeaconChainError(e) => {
|
||||
matches!(e.as_ref(), BeaconChainError::JustifiedPayloadInvalid { .. })
|
||||
}
|
||||
_ => false,
|
||||
})
|
||||
.await;
|
||||
|
||||
@@ -687,12 +686,14 @@ async fn invalidates_all_descendants() {
|
||||
assert_eq!(fork_parent_state.slot(), fork_parent_slot);
|
||||
let ((fork_block, _), _fork_post_state) =
|
||||
rig.harness.make_block(fork_parent_state, fork_slot).await;
|
||||
let fork_rpc_block =
|
||||
RpcBlock::new_without_blobs(None, fork_block.clone(), rig.harness.sampling_column_count);
|
||||
let fork_block_root = rig
|
||||
.harness
|
||||
.chain
|
||||
.process_block(
|
||||
fork_block.canonical_root(),
|
||||
fork_block,
|
||||
fork_rpc_block.block_root(),
|
||||
fork_rpc_block,
|
||||
NotifyExecutionLayer::Yes,
|
||||
BlockImportSource::Lookup,
|
||||
|| Ok(()),
|
||||
@@ -788,12 +789,14 @@ async fn switches_heads() {
|
||||
let ((fork_block, _), _fork_post_state) =
|
||||
rig.harness.make_block(fork_parent_state, fork_slot).await;
|
||||
let fork_parent_root = fork_block.parent_root();
|
||||
let fork_rpc_block =
|
||||
RpcBlock::new_without_blobs(None, fork_block.clone(), rig.harness.sampling_column_count);
|
||||
let fork_block_root = rig
|
||||
.harness
|
||||
.chain
|
||||
.process_block(
|
||||
fork_block.canonical_root(),
|
||||
fork_block,
|
||||
fork_rpc_block.block_root(),
|
||||
fork_rpc_block,
|
||||
NotifyExecutionLayer::Yes,
|
||||
BlockImportSource::Lookup,
|
||||
|| Ok(()),
|
||||
@@ -1057,8 +1060,10 @@ async fn invalid_parent() {
|
||||
));
|
||||
|
||||
// Ensure the block built atop an invalid payload is invalid for import.
|
||||
let rpc_block =
|
||||
RpcBlock::new_without_blobs(None, block.clone(), rig.harness.sampling_column_count);
|
||||
assert!(matches!(
|
||||
rig.harness.chain.process_block(block.canonical_root(), block.clone(), NotifyExecutionLayer::Yes, BlockImportSource::Lookup,
|
||||
rig.harness.chain.process_block(rpc_block.block_root(), rpc_block, NotifyExecutionLayer::Yes, BlockImportSource::Lookup,
|
||||
|| Ok(()),
|
||||
).await,
|
||||
Err(BlockError::ParentExecutionPayloadInvalid { parent_root: invalid_root })
|
||||
@@ -1380,11 +1385,13 @@ async fn recover_from_invalid_head_by_importing_blocks() {
|
||||
} = InvalidHeadSetup::new().await;
|
||||
|
||||
// Import the fork block, it should become the head.
|
||||
let fork_rpc_block =
|
||||
RpcBlock::new_without_blobs(None, fork_block.clone(), rig.harness.sampling_column_count);
|
||||
rig.harness
|
||||
.chain
|
||||
.process_block(
|
||||
fork_block.canonical_root(),
|
||||
fork_block.clone(),
|
||||
fork_rpc_block.block_root(),
|
||||
fork_rpc_block,
|
||||
NotifyExecutionLayer::Yes,
|
||||
BlockImportSource::Lookup,
|
||||
|| Ok(()),
|
||||
@@ -1419,8 +1426,8 @@ async fn recover_from_invalid_head_after_persist_and_reboot() {
|
||||
|
||||
let slot_clock = rig.harness.chain.slot_clock.clone();
|
||||
|
||||
// Forcefully persist the head and fork choice.
|
||||
rig.harness.chain.persist_head_and_fork_choice().unwrap();
|
||||
// Forcefully persist fork choice.
|
||||
rig.harness.chain.persist_fork_choice().unwrap();
|
||||
|
||||
let resumed = BeaconChainHarness::builder(MainnetEthSpec)
|
||||
.default_spec()
|
||||
|
||||
@@ -254,6 +254,35 @@ async fn test_rewards_base_inactivity_leak_justification_epoch() {
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_rewards_electra_slashings() {
|
||||
let spec = ForkName::Electra.make_genesis_spec(E::default_spec());
|
||||
let harness = get_electra_harness(spec);
|
||||
let state = harness.get_current_state();
|
||||
|
||||
harness.extend_slots(E::slots_per_epoch() as usize).await;
|
||||
|
||||
let mut initial_balances = harness.get_current_state().balances().to_vec();
|
||||
|
||||
// add an attester slashing and calculate slashing penalties
|
||||
harness.add_attester_slashing(vec![0]).unwrap();
|
||||
let slashed_balance_1 = initial_balances.get_mut(0).unwrap();
|
||||
let validator_1_effective_balance = state.get_effective_balance(0).unwrap();
|
||||
let delta_1 = validator_1_effective_balance
|
||||
/ harness.spec.min_slashing_penalty_quotient_for_state(&state);
|
||||
*slashed_balance_1 -= delta_1;
|
||||
|
||||
// add a proposer slashing and calculating slashing penalties
|
||||
harness.add_proposer_slashing(1).unwrap();
|
||||
let slashed_balance_2 = initial_balances.get_mut(1).unwrap();
|
||||
let validator_2_effective_balance = state.get_effective_balance(1).unwrap();
|
||||
let delta_2 = validator_2_effective_balance
|
||||
/ harness.spec.min_slashing_penalty_quotient_for_state(&state);
|
||||
*slashed_balance_2 -= delta_2;
|
||||
|
||||
check_all_electra_rewards(&harness, initial_balances).await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_rewards_base_slashings() {
|
||||
let spec = ForkName::Base.make_genesis_spec(E::default_spec());
|
||||
@@ -693,6 +722,75 @@ async fn test_rewards_base_subset_only() {
|
||||
check_all_base_rewards_for_subset(&harness, initial_balances, validators_subset).await;
|
||||
}
|
||||
|
||||
async fn check_all_electra_rewards(
|
||||
harness: &BeaconChainHarness<EphemeralHarnessType<E>>,
|
||||
mut balances: Vec<u64>,
|
||||
) {
|
||||
let mut proposal_rewards_map = HashMap::new();
|
||||
let mut sync_committee_rewards_map = HashMap::new();
|
||||
for _ in 0..E::slots_per_epoch() {
|
||||
let state = harness.get_current_state();
|
||||
let slot = state.slot() + Slot::new(1);
|
||||
|
||||
// calculate beacon block rewards / penalties
|
||||
let ((signed_block, _maybe_blob_sidecars), mut state) =
|
||||
harness.make_block_return_pre_state(state, slot).await;
|
||||
let beacon_block_reward = harness
|
||||
.chain
|
||||
.compute_beacon_block_reward(signed_block.message(), &mut state)
|
||||
.unwrap();
|
||||
|
||||
let total_proposer_reward = proposal_rewards_map
|
||||
.entry(beacon_block_reward.proposer_index)
|
||||
.or_insert(0);
|
||||
*total_proposer_reward += beacon_block_reward.total as i64;
|
||||
|
||||
// calculate sync committee rewards / penalties
|
||||
let reward_payload = harness
|
||||
.chain
|
||||
.compute_sync_committee_rewards(signed_block.message(), &mut state)
|
||||
.unwrap();
|
||||
|
||||
for reward in reward_payload {
|
||||
let total_sync_reward = sync_committee_rewards_map
|
||||
.entry(reward.validator_index)
|
||||
.or_insert(0);
|
||||
*total_sync_reward += reward.reward;
|
||||
}
|
||||
|
||||
harness.extend_slots(1).await;
|
||||
}
|
||||
|
||||
// compute reward deltas for all validators in epoch 0
|
||||
let StandardAttestationRewards {
|
||||
ideal_rewards,
|
||||
total_rewards,
|
||||
} = harness
|
||||
.chain
|
||||
.compute_attestation_rewards(Epoch::new(0), vec![])
|
||||
.unwrap();
|
||||
|
||||
// assert ideal rewards are greater than 0
|
||||
assert_eq!(
|
||||
ideal_rewards.len() as u64,
|
||||
harness.spec.max_effective_balance_electra / harness.spec.effective_balance_increment
|
||||
);
|
||||
|
||||
assert!(ideal_rewards
|
||||
.iter()
|
||||
.all(|reward| reward.head > 0 && reward.target > 0 && reward.source > 0));
|
||||
|
||||
// apply attestation, proposal, and sync committee rewards and penalties to initial balances
|
||||
apply_attestation_rewards(&mut balances, total_rewards);
|
||||
apply_other_rewards(&mut balances, &proposal_rewards_map);
|
||||
apply_other_rewards(&mut balances, &sync_committee_rewards_map);
|
||||
|
||||
// verify expected balances against actual balances
|
||||
let actual_balances: Vec<u64> = harness.get_current_state().balances().to_vec();
|
||||
|
||||
assert_eq!(balances, actual_balances);
|
||||
}
|
||||
|
||||
async fn check_all_base_rewards(
|
||||
harness: &BeaconChainHarness<EphemeralHarnessType<E>>,
|
||||
balances: Vec<u64>,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#![cfg(not(debug_assertions))]
|
||||
|
||||
use beacon_chain::attestation_verification::Error as AttnError;
|
||||
use beacon_chain::block_verification_types::RpcBlock;
|
||||
use beacon_chain::builder::BeaconChainBuilder;
|
||||
use beacon_chain::data_availability_checker::AvailableBlock;
|
||||
use beacon_chain::schema_change::migrate_schema;
|
||||
@@ -16,6 +17,7 @@ use beacon_chain::{
|
||||
};
|
||||
use logging::create_test_tracing_subscriber;
|
||||
use maplit::hashset;
|
||||
use rand::rngs::StdRng;
|
||||
use rand::Rng;
|
||||
use slot_clock::{SlotClock, TestingSlotClock};
|
||||
use state_processing::{state_advance::complete_state_advance, BlockReplayer};
|
||||
@@ -31,7 +33,6 @@ use store::{
|
||||
BlobInfo, DBColumn, HotColdDB, StoreConfig,
|
||||
};
|
||||
use tempfile::{tempdir, TempDir};
|
||||
use tokio::time::sleep;
|
||||
use types::test_utils::{SeedableRng, XorShiftRng};
|
||||
use types::*;
|
||||
|
||||
@@ -120,6 +121,17 @@ fn get_harness_generic(
|
||||
harness
|
||||
}
|
||||
|
||||
fn count_states_descendant_of_block(
|
||||
store: &HotColdDB<E, BeaconNodeBackend<E>, BeaconNodeBackend<E>>,
|
||||
block_root: Hash256,
|
||||
) -> usize {
|
||||
let summaries = store.load_hot_state_summaries().unwrap();
|
||||
summaries
|
||||
.iter()
|
||||
.filter(|(_, s)| s.latest_block_root == block_root)
|
||||
.count()
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn light_client_bootstrap_test() {
|
||||
let spec = test_spec::<E>();
|
||||
@@ -166,7 +178,6 @@ async fn light_client_bootstrap_test() {
|
||||
LightClientBootstrap::Capella(lc_bootstrap) => lc_bootstrap.header.beacon.slot,
|
||||
LightClientBootstrap::Deneb(lc_bootstrap) => lc_bootstrap.header.beacon.slot,
|
||||
LightClientBootstrap::Electra(lc_bootstrap) => lc_bootstrap.header.beacon.slot,
|
||||
LightClientBootstrap::Eip7805(lc_bootstrap) => lc_bootstrap.header.beacon.slot,
|
||||
LightClientBootstrap::Fulu(lc_bootstrap) => lc_bootstrap.header.beacon.slot,
|
||||
};
|
||||
|
||||
@@ -1226,7 +1237,7 @@ async fn prunes_abandoned_fork_between_two_finalized_checkpoints() {
|
||||
|
||||
assert_eq!(rig.get_finalized_checkpoints(), hashset! {});
|
||||
|
||||
assert!(rig.chain.knows_head(&stray_head));
|
||||
rig.assert_knows_head(stray_head.into());
|
||||
|
||||
// Trigger finalization
|
||||
let finalization_slots: Vec<Slot> = ((canonical_chain_slot + 1)
|
||||
@@ -1274,7 +1285,7 @@ async fn prunes_abandoned_fork_between_two_finalized_checkpoints() {
|
||||
);
|
||||
}
|
||||
|
||||
assert!(!rig.chain.knows_head(&stray_head));
|
||||
assert!(!rig.knows_head(&stray_head));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
@@ -1400,7 +1411,7 @@ async fn pruning_does_not_touch_abandoned_block_shared_with_canonical_chain() {
|
||||
);
|
||||
}
|
||||
|
||||
assert!(!rig.chain.knows_head(&stray_head));
|
||||
assert!(!rig.knows_head(&stray_head));
|
||||
let chain_dump = rig.chain.chain_dump().unwrap();
|
||||
assert!(get_blocks(&chain_dump).contains(&shared_head));
|
||||
}
|
||||
@@ -1493,7 +1504,7 @@ async fn pruning_does_not_touch_blocks_prior_to_finalization() {
|
||||
);
|
||||
}
|
||||
|
||||
assert!(rig.chain.knows_head(&stray_head));
|
||||
rig.assert_knows_head(stray_head.into());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
@@ -1577,7 +1588,7 @@ async fn prunes_fork_growing_past_youngest_finalized_checkpoint() {
|
||||
// Precondition: Nothing is finalized yet
|
||||
assert_eq!(rig.get_finalized_checkpoints(), hashset! {},);
|
||||
|
||||
assert!(rig.chain.knows_head(&stray_head));
|
||||
rig.assert_knows_head(stray_head.into());
|
||||
|
||||
// Trigger finalization
|
||||
let canonical_slots: Vec<Slot> = (rig.epoch_start_slot(2)..=rig.epoch_start_slot(6))
|
||||
@@ -1632,7 +1643,7 @@ async fn prunes_fork_growing_past_youngest_finalized_checkpoint() {
|
||||
);
|
||||
}
|
||||
|
||||
assert!(!rig.chain.knows_head(&stray_head));
|
||||
assert!(!rig.knows_head(&stray_head));
|
||||
}
|
||||
|
||||
// This is to check if state outside of normal block processing are pruned correctly.
|
||||
@@ -2151,64 +2162,6 @@ async fn pruning_test(
|
||||
check_no_blocks_exist(&harness, stray_blocks.values());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn garbage_collect_temp_states_from_failed_block_on_startup() {
|
||||
let db_path = tempdir().unwrap();
|
||||
|
||||
// Wrap these functions to ensure the variables are dropped before we try to open another
|
||||
// instance of the store.
|
||||
let mut store = {
|
||||
let store = get_store(&db_path);
|
||||
let harness = get_harness(store.clone(), LOW_VALIDATOR_COUNT);
|
||||
|
||||
let slots_per_epoch = E::slots_per_epoch();
|
||||
|
||||
let genesis_state = harness.get_current_state();
|
||||
let block_slot = Slot::new(2 * slots_per_epoch);
|
||||
let ((signed_block, _), state) = harness.make_block(genesis_state, block_slot).await;
|
||||
|
||||
let (mut block, _) = (*signed_block).clone().deconstruct();
|
||||
|
||||
// Mutate the block to make it invalid, and re-sign it.
|
||||
*block.state_root_mut() = Hash256::repeat_byte(0xff);
|
||||
let proposer_index = block.proposer_index() as usize;
|
||||
let block = Arc::new(block.sign(
|
||||
&harness.validator_keypairs[proposer_index].sk,
|
||||
&state.fork(),
|
||||
state.genesis_validators_root(),
|
||||
&harness.spec,
|
||||
));
|
||||
|
||||
// The block should be rejected, but should store a bunch of temporary states.
|
||||
harness.set_current_slot(block_slot);
|
||||
harness
|
||||
.process_block_result((block, None))
|
||||
.await
|
||||
.unwrap_err();
|
||||
|
||||
assert_eq!(
|
||||
store.iter_temporary_state_roots().count(),
|
||||
block_slot.as_usize() - 1
|
||||
);
|
||||
store
|
||||
};
|
||||
|
||||
// Wait until all the references to the store have been dropped, this helps ensure we can
|
||||
// re-open the store later.
|
||||
loop {
|
||||
store = if let Err(store_arc) = Arc::try_unwrap(store) {
|
||||
sleep(Duration::from_millis(500)).await;
|
||||
store_arc
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// On startup, the store should garbage collect all the temporary states.
|
||||
let store = get_store(&db_path);
|
||||
assert_eq!(store.iter_temporary_state_roots().count(), 0);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn garbage_collect_temp_states_from_failed_block_on_finalization() {
|
||||
let db_path = tempdir().unwrap();
|
||||
@@ -2223,6 +2176,7 @@ async fn garbage_collect_temp_states_from_failed_block_on_finalization() {
|
||||
let ((signed_block, _), state) = harness.make_block(genesis_state, block_slot).await;
|
||||
|
||||
let (mut block, _) = (*signed_block).clone().deconstruct();
|
||||
let bad_block_parent_root = block.parent_root();
|
||||
|
||||
// Mutate the block to make it invalid, and re-sign it.
|
||||
*block.state_root_mut() = Hash256::repeat_byte(0xff);
|
||||
@@ -2241,9 +2195,11 @@ async fn garbage_collect_temp_states_from_failed_block_on_finalization() {
|
||||
.await
|
||||
.unwrap_err();
|
||||
|
||||
// The bad block parent root is the genesis block root. There's `block_slot - 1` temporary
|
||||
// states to remove + the genesis state = block_slot.
|
||||
assert_eq!(
|
||||
store.iter_temporary_state_roots().count(),
|
||||
block_slot.as_usize() - 1
|
||||
count_states_descendant_of_block(&store, bad_block_parent_root),
|
||||
block_slot.as_usize(),
|
||||
);
|
||||
|
||||
// Finalize the chain without the block, which should result in pruning of all temporary states.
|
||||
@@ -2260,8 +2216,12 @@ async fn garbage_collect_temp_states_from_failed_block_on_finalization() {
|
||||
// Check that the finalization migration ran.
|
||||
assert_ne!(store.get_split_slot(), 0);
|
||||
|
||||
// Check that temporary states have been pruned.
|
||||
assert_eq!(store.iter_temporary_state_roots().count(), 0);
|
||||
// Check that temporary states have been pruned. The genesis block is not a descendant of the
|
||||
// latest finalized checkpoint, so all its states have been pruned from the hot DB, = 0.
|
||||
assert_eq!(
|
||||
count_states_descendant_of_block(&store, bad_block_parent_root),
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
@@ -2415,6 +2375,7 @@ async fn weak_subjectivity_sync_test(slots: Vec<Slot>, checkpoint_slot: Slot) {
|
||||
.chain_config(ChainConfig::default())
|
||||
.event_handler(Some(ServerSentEventHandler::new_with_capacity(1)))
|
||||
.execution_layer(Some(mock.el))
|
||||
.rng(Box::new(StdRng::seed_from_u64(42)))
|
||||
.build()
|
||||
.expect("should build");
|
||||
|
||||
@@ -2683,12 +2644,17 @@ async fn process_blocks_and_attestations_for_unaligned_checkpoint() {
|
||||
assert_eq!(split.block_root, valid_fork_block.parent_root());
|
||||
assert_ne!(split.state_root, unadvanced_split_state_root);
|
||||
|
||||
let invalid_fork_rpc_block = RpcBlock::new_without_blobs(
|
||||
None,
|
||||
invalid_fork_block.clone(),
|
||||
harness.sampling_column_count,
|
||||
);
|
||||
// Applying the invalid block should fail.
|
||||
let err = harness
|
||||
.chain
|
||||
.process_block(
|
||||
invalid_fork_block.canonical_root(),
|
||||
invalid_fork_block.clone(),
|
||||
invalid_fork_rpc_block.block_root(),
|
||||
invalid_fork_rpc_block,
|
||||
NotifyExecutionLayer::Yes,
|
||||
BlockImportSource::Lookup,
|
||||
|| Ok(()),
|
||||
@@ -2698,11 +2664,16 @@ async fn process_blocks_and_attestations_for_unaligned_checkpoint() {
|
||||
assert!(matches!(err, BlockError::WouldRevertFinalizedSlot { .. }));
|
||||
|
||||
// Applying the valid block should succeed, but it should not become head.
|
||||
let valid_fork_rpc_block = RpcBlock::new_without_blobs(
|
||||
None,
|
||||
valid_fork_block.clone(),
|
||||
harness.sampling_column_count,
|
||||
);
|
||||
harness
|
||||
.chain
|
||||
.process_block(
|
||||
valid_fork_block.canonical_root(),
|
||||
valid_fork_block.clone(),
|
||||
valid_fork_rpc_block.block_root(),
|
||||
valid_fork_rpc_block,
|
||||
NotifyExecutionLayer::Yes,
|
||||
BlockImportSource::Lookup,
|
||||
|| Ok(()),
|
||||
@@ -2786,8 +2757,8 @@ async fn finalizes_after_resuming_from_db() {
|
||||
|
||||
harness
|
||||
.chain
|
||||
.persist_head_and_fork_choice()
|
||||
.expect("should persist the head and fork choice");
|
||||
.persist_fork_choice()
|
||||
.expect("should persist fork choice");
|
||||
harness
|
||||
.chain
|
||||
.persist_op_pool()
|
||||
@@ -3000,11 +2971,13 @@ async fn revert_minority_fork_on_resume() {
|
||||
resumed_harness.chain.recompute_head_at_current_slot().await;
|
||||
assert_eq!(resumed_harness.head_slot(), fork_slot - 1);
|
||||
|
||||
// Head track should know the canonical head and the rogue head.
|
||||
assert_eq!(resumed_harness.chain.heads().len(), 2);
|
||||
assert!(resumed_harness
|
||||
.chain
|
||||
.knows_head(&resumed_harness.head_block_root().into()));
|
||||
// Fork choice should only know the canonical head. When we reverted the head we also should
|
||||
// have called `reset_fork_choice_to_finalization` which rebuilds fork choice from scratch
|
||||
// without the reverted block.
|
||||
assert_eq!(
|
||||
resumed_harness.chain.heads(),
|
||||
vec![(resumed_harness.head_block_root(), fork_slot - 1)]
|
||||
);
|
||||
|
||||
// Apply blocks from the majority chain and trigger finalization.
|
||||
let initial_split_slot = resumed_harness.chain.store.get_split_slot();
|
||||
|
||||
Reference in New Issue
Block a user