Skip to content

Commit 22faccb

Browse files
authored
Merge pull request #7200 from dknopik/into-anchor
Anchor Pre-PR: merge `unstable`
2 parents 397eb3e + 68f5208 commit 22faccb

File tree

141 files changed

+1946
-637
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

141 files changed

+1946
-637
lines changed

Cargo.lock

Lines changed: 10 additions & 11 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ fnv = "1"
144144
fs2 = "0.4"
145145
futures = "0.3"
146146
graffiti_file = { path = "validator_client/graffiti_file" }
147+
gossipsub = { package = "libp2p-gossipsub", git = "https://github.com/sigp/rust-libp2p.git", rev = "7a36e4c" }
147148
hex = "0.4"
148149
hashlink = "0.9.0"
149150
hyper = "1"

beacon_node/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "beacon_node"
3-
version = "7.0.0-beta.0"
3+
version = "7.0.0-beta.4"
44
authors = [
55
"Paul Hauner <[email protected]>",
66
"Age Manning <[email protected]",

beacon_node/beacon_chain/src/attestation_rewards.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,10 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
5151
.state_root_at_slot(state_slot)?
5252
.ok_or(BeaconChainError::NoStateForSlot(state_slot))?;
5353

54+
// This branch is reached from the HTTP API. We assume the user wants
55+
// to cache states so that future calls are faster.
5456
let state = self
55-
.get_state(&state_root, Some(state_slot))?
57+
.get_state(&state_root, Some(state_slot), true)?
5658
.ok_or(BeaconChainError::MissingBeaconState(state_root))?;
5759

5860
if state.fork_name_unchecked().altair_enabled() {

beacon_node/beacon_chain/src/attestation_verification.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1126,6 +1126,12 @@ fn verify_head_block_is_known<T: BeaconChainTypes>(
11261126
}
11271127
}
11281128

1129+
if !verify_attestation_is_finalized_checkpoint_or_descendant(attestation.data(), chain) {
1130+
return Err(Error::HeadBlockFinalized {
1131+
beacon_block_root: attestation.data().beacon_block_root,
1132+
});
1133+
}
1134+
11291135
Ok(block)
11301136
} else if chain.is_pre_finalization_block(attestation.data().beacon_block_root)? {
11311137
Err(Error::HeadBlockFinalized {
@@ -1359,6 +1365,29 @@ pub fn verify_committee_index<E: EthSpec>(attestation: AttestationRef<E>) -> Res
13591365
Ok(())
13601366
}
13611367

1368+
fn verify_attestation_is_finalized_checkpoint_or_descendant<T: BeaconChainTypes>(
1369+
attestation_data: &AttestationData,
1370+
chain: &BeaconChain<T>,
1371+
) -> bool {
1372+
// If we have a split block newer than finalization then we also ban attestations which are not
1373+
// descended from that split block. It's important not to try checking `is_descendant` if
1374+
// finality is ahead of the split and the split block has been pruned, as `is_descendant` will
1375+
// return `false` in this case.
1376+
let fork_choice = chain.canonical_head.fork_choice_read_lock();
1377+
let attestation_block_root = attestation_data.beacon_block_root;
1378+
let finalized_slot = fork_choice
1379+
.finalized_checkpoint()
1380+
.epoch
1381+
.start_slot(T::EthSpec::slots_per_epoch());
1382+
let split = chain.store.get_split_info();
1383+
let is_descendant_from_split_block = split.slot == 0
1384+
|| split.slot <= finalized_slot
1385+
|| fork_choice.is_descendant(split.block_root, attestation_block_root);
1386+
1387+
fork_choice.is_finalized_checkpoint_or_descendant(attestation_block_root)
1388+
&& is_descendant_from_split_block
1389+
}
1390+
13621391
/// Assists in readability.
13631392
type CommitteesPerSlot = u64;
13641393

beacon_node/beacon_chain/src/attester_cache.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -325,8 +325,10 @@ impl AttesterCache {
325325
return Ok(value);
326326
}
327327

328+
// We use `cache_state = true` here because if we are attesting to the state it's likely
329+
// to be recent and useful for other things.
328330
let mut state: BeaconState<T::EthSpec> = chain
329-
.get_state(&state_root, None)?
331+
.get_state(&state_root, None, true)?
330332
.ok_or(Error::MissingBeaconState(state_root))?;
331333

332334
if state.slot() > slot {

beacon_node/beacon_chain/src/beacon_chain.rs

Lines changed: 78 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ use crate::light_client_optimistic_update_verification::{
4242
Error as LightClientOptimisticUpdateError, VerifiedLightClientOptimisticUpdate,
4343
};
4444
use crate::light_client_server_cache::LightClientServerCache;
45-
use crate::migrate::BackgroundMigrator;
45+
use crate::migrate::{BackgroundMigrator, ManualFinalizationNotification};
4646
use crate::naive_aggregation_pool::{
4747
AggregatedAttestationMap, Error as NaiveAggregationError, NaiveAggregationPool,
4848
SyncContributionAggregateMap,
@@ -118,8 +118,8 @@ use std::sync::Arc;
118118
use std::time::Duration;
119119
use store::iter::{BlockRootsIterator, ParentRootBlockIterator, StateRootsIterator};
120120
use store::{
121-
BlobSidecarListFromRoot, DatabaseBlock, Error as DBError, HotColdDB, KeyValueStore,
122-
KeyValueStoreOp, StoreItem, StoreOp,
121+
BlobSidecarListFromRoot, DatabaseBlock, Error as DBError, HotColdDB, HotStateSummary,
122+
KeyValueStore, KeyValueStoreOp, StoreItem, StoreOp,
123123
};
124124
use task_executor::{ShutdownReason, TaskExecutor};
125125
use tokio::sync::oneshot;
@@ -812,8 +812,10 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
812812
let block = self
813813
.get_blinded_block(&block_root)?
814814
.ok_or(Error::MissingBeaconBlock(block_root))?;
815+
// This method is only used in tests, so we may as well cache states to make CI go brr.
816+
// TODO(release-v7) move this method out of beacon chain and into `store_tests`` or something equivalent.
815817
let state = self
816-
.get_state(&block.state_root(), Some(block.slot()))?
818+
.get_state(&block.state_root(), Some(block.slot()), true)?
817819
.ok_or_else(|| Error::MissingBeaconState(block.state_root()))?;
818820
let iter = BlockRootsIterator::owned(&self.store, state);
819821
Ok(std::iter::once(Ok((block_root, block.slot())))
@@ -1339,8 +1341,9 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
13391341
&self,
13401342
state_root: &Hash256,
13411343
slot: Option<Slot>,
1344+
update_cache: bool,
13421345
) -> Result<Option<BeaconState<T::EthSpec>>, Error> {
1343-
Ok(self.store.get_state(state_root, slot)?)
1346+
Ok(self.store.get_state(state_root, slot, update_cache)?)
13441347
}
13451348

13461349
/// Return the sync committee at `slot + 1` from the canonical chain.
@@ -1512,8 +1515,14 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
15121515
})?
15131516
.ok_or(Error::NoStateForSlot(slot))?;
15141517

1518+
// This branch is mostly reached from the HTTP API when doing analysis, or in niche
1519+
// situations when producing a block. In the HTTP API case we assume the user wants
1520+
// to cache states so that future calls are faster, and that if the cache is
1521+
// struggling due to non-finality that they will dial down inessential calls. In the
1522+
// block proposal case we want to cache the state so that we can process the block
1523+
// quickly after it has been signed.
15151524
Ok(self
1516-
.get_state(&state_root, Some(slot))?
1525+
.get_state(&state_root, Some(slot), true)?
15171526
.ok_or(Error::NoStateForSlot(slot))?)
15181527
}
15191528
}
@@ -1695,6 +1704,45 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
16951704
}
16961705
}
16971706

1707+
pub fn manually_compact_database(&self) {
1708+
self.store_migrator.process_manual_compaction();
1709+
}
1710+
1711+
pub fn manually_finalize_state(
1712+
&self,
1713+
state_root: Hash256,
1714+
checkpoint: Checkpoint,
1715+
) -> Result<(), Error> {
1716+
let HotStateSummary {
1717+
slot,
1718+
latest_block_root,
1719+
..
1720+
} = self
1721+
.store
1722+
.load_hot_state_summary(&state_root)
1723+
.map_err(BeaconChainError::DBError)?
1724+
.ok_or(BeaconChainError::MissingHotStateSummary(state_root))?;
1725+
1726+
if slot != checkpoint.epoch.start_slot(T::EthSpec::slots_per_epoch())
1727+
|| latest_block_root != *checkpoint.root
1728+
{
1729+
return Err(BeaconChainError::InvalidCheckpoint {
1730+
state_root,
1731+
checkpoint,
1732+
});
1733+
}
1734+
1735+
let notif = ManualFinalizationNotification {
1736+
state_root: state_root.into(),
1737+
checkpoint,
1738+
head_tracker: self.head_tracker.clone(),
1739+
genesis_block_root: self.genesis_block_root,
1740+
};
1741+
1742+
self.store_migrator.process_manual_finalization(notif);
1743+
Ok(())
1744+
}
1745+
16981746
/// Returns an aggregated `Attestation`, if any, that has a matching `attestation.data`.
16991747
///
17001748
/// The attestation will be obtained from `self.naive_aggregation_pool`.
@@ -2839,6 +2887,15 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
28392887
chain_segment: Vec<RpcBlock<T::EthSpec>>,
28402888
notify_execution_layer: NotifyExecutionLayer,
28412889
) -> ChainSegmentResult {
2890+
for block in chain_segment.iter() {
2891+
if let Err(error) = self.check_invalid_block_roots(block.block_root()) {
2892+
return ChainSegmentResult::Failed {
2893+
imported_blocks: vec![],
2894+
error,
2895+
};
2896+
}
2897+
}
2898+
28422899
let mut imported_blocks = vec![];
28432900

28442901
// Filter uninteresting blocks from the chain segment in a blocking task.
@@ -3330,6 +3387,15 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
33303387
self.remove_notified(&block_root, r)
33313388
}
33323389

3390+
/// Check for known and configured invalid block roots before processing.
3391+
pub fn check_invalid_block_roots(&self, block_root: Hash256) -> Result<(), BlockError> {
3392+
if self.config.invalid_block_roots.contains(&block_root) {
3393+
Err(BlockError::KnownInvalidExecutionPayload(block_root))
3394+
} else {
3395+
Ok(())
3396+
}
3397+
}
3398+
33333399
/// Returns `Ok(block_root)` if the given `unverified_block` was successfully verified and
33343400
/// imported into the chain.
33353401
///
@@ -6775,9 +6841,11 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
67756841
})?;
67766842
let beacon_state_root = beacon_block.state_root();
67776843

6844+
// This branch is reached from the HTTP API. We assume the user wants
6845+
// to cache states so that future calls are faster.
67786846
let mut beacon_state = self
67796847
.store
6780-
.get_state(&beacon_state_root, Some(beacon_block.slot()))?
6848+
.get_state(&beacon_state_root, Some(beacon_block.slot()), true)?
67816849
.ok_or_else(|| {
67826850
Error::DBInconsistent(format!("Missing state {:?}", beacon_state_root))
67836851
})?;
@@ -6929,8 +6997,10 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
69296997

69306998
if signed_beacon_block.slot() % T::EthSpec::slots_per_epoch() == 0 {
69316999
let block = self.get_blinded_block(&block_hash).unwrap().unwrap();
7000+
// This branch is reached from the HTTP API. We assume the user wants
7001+
// to cache states so that future calls are faster.
69327002
let state = self
6933-
.get_state(&block.state_root(), Some(block.slot()))
7003+
.get_state(&block.state_root(), Some(block.slot()), true)
69347004
.unwrap()
69357005
.unwrap();
69367006
finalized_blocks.insert(state.finalized_checkpoint().root);

beacon_node/beacon_chain/src/block_verification.rs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,9 @@ pub enum BlockError {
282282
/// problems to worry about than losing peers, and we're doing the network a favour by
283283
/// disconnecting.
284284
ParentExecutionPayloadInvalid { parent_root: Hash256 },
285+
/// This is a known invalid block that was listed in Lighthouses configuration.
286+
/// At the moment this error is only relevant as part of the Holesky network recovery efforts.
287+
KnownInvalidExecutionPayload(Hash256),
285288
/// The block is a slashable equivocation from the proposer.
286289
///
287290
/// ## Peer scoring
@@ -862,6 +865,9 @@ impl<T: BeaconChainTypes> GossipVerifiedBlock<T> {
862865
return Err(BlockError::DuplicateFullyImported(block_root));
863866
}
864867

868+
// Do not process a block that is known to be invalid.
869+
chain.check_invalid_block_roots(block_root)?;
870+
865871
// Do not process a block that doesn't descend from the finalized root.
866872
//
867873
// We check this *before* we load the parent so that we can return a more detailed error.
@@ -1080,6 +1086,9 @@ impl<T: BeaconChainTypes> SignatureVerifiedBlock<T> {
10801086
.fork_name(&chain.spec)
10811087
.map_err(BlockError::InconsistentFork)?;
10821088

1089+
// Check whether the block is a banned block prior to loading the parent.
1090+
chain.check_invalid_block_roots(block_root)?;
1091+
10831092
let (mut parent, block) = load_parent(block, chain)?;
10841093

10851094
let state = cheap_state_advance_to_obtain_committees::<_, BlockError>(
@@ -1746,7 +1755,22 @@ pub fn check_block_is_finalized_checkpoint_or_descendant<
17461755
fork_choice: &BeaconForkChoice<T>,
17471756
block: B,
17481757
) -> Result<B, BlockError> {
1749-
if fork_choice.is_finalized_checkpoint_or_descendant(block.parent_root()) {
1758+
// If we have a split block newer than finalization then we also ban blocks which are not
1759+
// descended from that split block. It's important not to try checking `is_descendant` if
1760+
// finality is ahead of the split and the split block has been pruned, as `is_descendant` will
1761+
// return `false` in this case.
1762+
let finalized_slot = fork_choice
1763+
.finalized_checkpoint()
1764+
.epoch
1765+
.start_slot(T::EthSpec::slots_per_epoch());
1766+
let split = chain.store.get_split_info();
1767+
let is_descendant_from_split_block = split.slot == 0
1768+
|| split.slot <= finalized_slot
1769+
|| fork_choice.is_descendant(split.block_root, block.parent_root());
1770+
1771+
if fork_choice.is_finalized_checkpoint_or_descendant(block.parent_root())
1772+
&& is_descendant_from_split_block
1773+
{
17501774
Ok(block)
17511775
} else {
17521776
// If fork choice does *not* consider the parent to be a descendant of the finalized block,

beacon_node/beacon_chain/src/builder.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -282,8 +282,13 @@ where
282282
.get_blinded_block(&chain.genesis_block_root)
283283
.map_err(|e| descriptive_db_error("genesis block", &e))?
284284
.ok_or("Genesis block not found in store")?;
285+
// We're resuming from some state in the db so it makes sense to cache it.
285286
let genesis_state = store
286-
.get_state(&genesis_block.state_root(), Some(genesis_block.slot()))
287+
.get_state(
288+
&genesis_block.state_root(),
289+
Some(genesis_block.slot()),
290+
true,
291+
)
287292
.map_err(|e| descriptive_db_error("genesis state", &e))?
288293
.ok_or("Genesis state not found in store")?;
289294

0 commit comments

Comments
 (0)