From 7251a93c5edf0b5014e6cac499e643c37e630eab Mon Sep 17 00:00:00 2001 From: Michael Sproul Date: Thu, 17 Aug 2023 02:37:29 +0000 Subject: [PATCH 01/10] Don't kill SSE stream if channel fills up (#4500) ## Issue Addressed Closes #4245 ## Proposed Changes - If an SSE channel fills up, send a comment instead of terminating the stream. - Add a CLI flag for scaling up the SSE buffer: `--http-sse-capacity-multiplier N`. ## Additional Info ~~Blocked on #4462. I haven't rebased on that PR yet for initial testing, because it still needs some more work to handle long-running HTTP threads.~~ - [x] Add CLI flag tests. --- beacon_node/beacon_chain/src/events.rs | 7 ++-- beacon_node/client/src/builder.rs | 5 ++- beacon_node/http_api/src/lib.rs | 48 ++++++++++++++++---------- beacon_node/http_api/src/test_utils.rs | 1 + beacon_node/src/cli.rs | 9 +++++ beacon_node/src/config.rs | 3 ++ lighthouse/tests/beacon_node.rs | 15 ++++++++ 7 files changed, 67 insertions(+), 21 deletions(-) diff --git a/beacon_node/beacon_chain/src/events.rs b/beacon_node/beacon_chain/src/events.rs index fed050323..b267cc853 100644 --- a/beacon_node/beacon_chain/src/events.rs +++ b/beacon_node/beacon_chain/src/events.rs @@ -21,8 +21,11 @@ pub struct ServerSentEventHandler { } impl ServerSentEventHandler { - pub fn new(log: Logger) -> Self { - Self::new_with_capacity(log, DEFAULT_CHANNEL_CAPACITY) + pub fn new(log: Logger, capacity_multiplier: usize) -> Self { + Self::new_with_capacity( + log, + capacity_multiplier.saturating_mul(DEFAULT_CHANNEL_CAPACITY), + ) } pub fn new_with_capacity(log: Logger, capacity: usize) -> Self { diff --git a/beacon_node/client/src/builder.rs b/beacon_node/client/src/builder.rs index 8383963b7..bd2946bb7 100644 --- a/beacon_node/client/src/builder.rs +++ b/beacon_node/client/src/builder.rs @@ -157,7 +157,10 @@ where let context = runtime_context.service_context("beacon".into()); let spec = chain_spec.ok_or("beacon_chain_start_method requires a chain spec")?; let event_handler = if self.http_api_config.enabled { - Some(ServerSentEventHandler::new(context.log().clone())) + Some(ServerSentEventHandler::new( + context.log().clone(), + self.http_api_config.sse_capacity_multiplier, + )) } else { None }; diff --git a/beacon_node/http_api/src/lib.rs b/beacon_node/http_api/src/lib.rs index 4d5b98a82..8e316834d 100644 --- a/beacon_node/http_api/src/lib.rs +++ b/beacon_node/http_api/src/lib.rs @@ -65,7 +65,10 @@ use tokio::sync::{ mpsc::{Sender, UnboundedSender}, oneshot, }; -use tokio_stream::{wrappers::BroadcastStream, StreamExt}; +use tokio_stream::{ + wrappers::{errors::BroadcastStreamRecvError, BroadcastStream}, + StreamExt, +}; use types::{ Attestation, AttestationData, AttestationShufflingId, AttesterSlashing, BeaconStateError, BlindedPayload, CommitteeCache, ConfigAndPreset, Epoch, EthSpec, ForkName, FullPayload, @@ -132,6 +135,7 @@ pub struct Config { pub allow_sync_stalled: bool, pub spec_fork_name: Option, pub data_dir: PathBuf, + pub sse_capacity_multiplier: usize, pub enable_beacon_processor: bool, } @@ -146,6 +150,7 @@ impl Default for Config { allow_sync_stalled: false, spec_fork_name: None, data_dir: PathBuf::from(DEFAULT_ROOT_DIR), + sse_capacity_multiplier: 1, enable_beacon_processor: true, } } @@ -4348,22 +4353,29 @@ pub fn serve( } }; - receivers.push(BroadcastStream::new(receiver).map(|msg| { - match msg { - Ok(data) => Event::default() - .event(data.topic_name()) - .json_data(data) - .map_err(|e| { - warp_utils::reject::server_sent_event_error(format!( - "{:?}", - e - )) - }), - Err(e) => Err(warp_utils::reject::server_sent_event_error( - format!("{:?}", e), - )), - } - })); + receivers.push( + BroadcastStream::new(receiver) + .map(|msg| { + match msg { + Ok(data) => Event::default() + .event(data.topic_name()) + .json_data(data) + .unwrap_or_else(|e| { + Event::default() + .comment(format!("error - bad json: {e:?}")) + }), + // Do not terminate the stream if the channel fills + // up. Just drop some messages and send a comment to + // the client. + Err(BroadcastStreamRecvError::Lagged(n)) => { + Event::default().comment(format!( + "error - dropped {n} messages" + )) + } + } + }) + .map(Ok::<_, std::convert::Infallible>), + ); } } else { return Err(warp_utils::reject::custom_server_error( @@ -4373,7 +4385,7 @@ pub fn serve( let s = futures::stream::select_all(receivers); - Ok::<_, warp::Rejection>(warp::sse::reply(warp::sse::keep_alive().stream(s))) + Ok(warp::sse::reply(warp::sse::keep_alive().stream(s))) }) }, ); diff --git a/beacon_node/http_api/src/test_utils.rs b/beacon_node/http_api/src/test_utils.rs index 0367776f8..dcc253222 100644 --- a/beacon_node/http_api/src/test_utils.rs +++ b/beacon_node/http_api/src/test_utils.rs @@ -225,6 +225,7 @@ pub async fn create_api_server_on_port( allow_sync_stalled: false, data_dir: std::path::PathBuf::from(DEFAULT_ROOT_DIR), spec_fork_name: None, + sse_capacity_multiplier: 1, enable_beacon_processor: true, }, chain: Some(chain), diff --git a/beacon_node/src/cli.rs b/beacon_node/src/cli.rs index 0330bd3f7..974dabbf0 100644 --- a/beacon_node/src/cli.rs +++ b/beacon_node/src/cli.rs @@ -382,6 +382,15 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> { stalled. This is useful for very small testnets. TESTING ONLY. DO NOT USE ON \ MAINNET.") ) + .arg( + Arg::with_name("http-sse-capacity-multiplier") + .long("http-sse-capacity-multiplier") + .takes_value(true) + .default_value("1") + .value_name("N") + .help("Multiplier to apply to the length of HTTP server-sent-event (SSE) channels. \ + Increasing this value can prevent messages from being dropped.") + ) .arg( Arg::with_name("http-enable-beacon-processor") .long("http-enable-beacon-processor") diff --git a/beacon_node/src/config.rs b/beacon_node/src/config.rs index 21df86620..0d2a5d812 100644 --- a/beacon_node/src/config.rs +++ b/beacon_node/src/config.rs @@ -149,6 +149,9 @@ pub fn get_config( client_config.http_api.allow_sync_stalled = true; } + client_config.http_api.sse_capacity_multiplier = + parse_required(cli_args, "http-sse-capacity-multiplier")?; + client_config.http_api.enable_beacon_processor = parse_required(cli_args, "http-enable-beacon-processor")?; diff --git a/lighthouse/tests/beacon_node.rs b/lighthouse/tests/beacon_node.rs index ecc936cbf..02b951201 100644 --- a/lighthouse/tests/beacon_node.rs +++ b/lighthouse/tests/beacon_node.rs @@ -2349,3 +2349,18 @@ fn beacon_processor_zero_workers() { .flag("beacon-processor-max-workers", Some("0")) .run_with_zero_port(); } + +#[test] +fn http_sse_capacity_multiplier_default() { + CommandLineTest::new() + .run_with_zero_port() + .with_config(|config| assert_eq!(config.http_api.sse_capacity_multiplier, 1)); +} + +#[test] +fn http_sse_capacity_multiplier_override() { + CommandLineTest::new() + .flag("http-sse-capacity-multiplier", Some("10")) + .run_with_zero_port() + .with_config(|config| assert_eq!(config.http_api.sse_capacity_multiplier, 10)); +} From 609819bb4d08faef914a26b681b6f121cb55ab56 Mon Sep 17 00:00:00 2001 From: zhiqiangxu <652732310@qq.com> Date: Thu, 17 Aug 2023 02:37:30 +0000 Subject: [PATCH 02/10] `attester_duties`: remove unnecessary case (#4614) Since `tolerant_current_epoch` is expected to be either `current_epoch` or `current_epoch+1`, we can eliminate a case here. And added a comment about `compute_historic_attester_duties` , since `RelativeEpoch::from_epoch` will only allow `request_epoch == current_epoch-1` when `request_epoch < current_epoch`. --- beacon_node/http_api/src/attester_duties.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/beacon_node/http_api/src/attester_duties.rs b/beacon_node/http_api/src/attester_duties.rs index aad405d56..f3242a2b3 100644 --- a/beacon_node/http_api/src/attester_duties.rs +++ b/beacon_node/http_api/src/attester_duties.rs @@ -35,7 +35,6 @@ pub fn attester_duties( .epoch(T::EthSpec::slots_per_epoch()); if request_epoch == current_epoch - || request_epoch == tolerant_current_epoch || request_epoch == current_epoch + 1 || request_epoch == tolerant_current_epoch + 1 { @@ -46,7 +45,7 @@ pub fn attester_duties( request_epoch, current_epoch ))) } else { - // request_epoch < current_epoch + // request_epoch < current_epoch, in fact we only allow `request_epoch == current_epoch-1` in this case compute_historic_attester_duties(request_epoch, request_indices, chain) } } From b33bfe25b7bc6ea82a97a270a3d4acd72f4e9ee0 Mon Sep 17 00:00:00 2001 From: zhiqiangxu <652732310@qq.com> Date: Thu, 17 Aug 2023 02:37:31 +0000 Subject: [PATCH 03/10] add `metrics::VALIDATOR_DUTIES_SYNC_HTTP_POST` for `post_validator_duties_sync` (#4617) It seems `post_validator_duties_sync` is the only api which doesn't have its own metric in `duties_service`, this PR adds `metrics::VALIDATOR_DUTIES_SYNC_HTTP_POST` for completeness. --- validator_client/src/duties_service/sync.rs | 6 ++++++ validator_client/src/http_metrics/metrics.rs | 1 + 2 files changed, 7 insertions(+) diff --git a/validator_client/src/duties_service/sync.rs b/validator_client/src/duties_service/sync.rs index 1e66d947a..cf63d8ac6 100644 --- a/validator_client/src/duties_service/sync.rs +++ b/validator_client/src/duties_service/sync.rs @@ -2,8 +2,10 @@ use crate::beacon_node_fallback::{OfflineOnFailure, RequireSynced}; use crate::{ doppelganger_service::DoppelgangerStatus, duties_service::{DutiesService, Error}, + http_metrics::metrics, validator_store::Error as ValidatorStoreError, }; + use futures::future::join_all; use itertools::Itertools; use parking_lot::{MappedRwLockReadGuard, RwLock, RwLockReadGuard, RwLockWriteGuard}; @@ -426,6 +428,10 @@ pub async fn poll_sync_committee_duties_for_period Date: Thu, 17 Aug 2023 02:37:32 +0000 Subject: [PATCH 04/10] Update blst to 0.3.11 (#4624) ## Proposed Changes This PR updates `blst` to 0.3.11, which gives us _runtime detection of CPU features_ :tada: Although [performance benchmarks](https://gist.github.com/michaelsproul/f759fa28dfa4003962507db34b439d6c) don't show a substantial detriment to running the `portable` build vs `modern`, in order to take things slowly I propose the following roll-out strategy: - Keep both `modern` and `portable` builds for releases/Docker images. - Run the `portable` build on half of SigP's infrastructure to monitor for performance deficits. - Listen out for user issues with the `portable` builds (e.g. SIGILLs from misdetected hardware). - Make the `portable` build the default and remove the `modern` build from our release binaries & Docker images. --- Cargo.lock | 16 ++-------------- Makefile | 2 +- 2 files changed, 3 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 233b3901e..116f8081f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -732,14 +732,13 @@ dependencies = [ [[package]] name = "blst" -version = "0.3.10" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a30d0edd9dd1c60ddb42b80341c7852f6f985279a5c1a83659dcb65899dec99" +checksum = "c94087b935a822949d3291a9989ad2b2051ea141eda0fd4e478a75f6aa3e604b" dependencies = [ "cc", "glob", "threadpool", - "which", "zeroize", ] @@ -8981,17 +8980,6 @@ dependencies = [ "rustls-webpki 0.100.1", ] -[[package]] -name = "which" -version = "4.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2441c784c52b289a054b7201fc93253e288f094e2f4be9058343127c4226a269" -dependencies = [ - "either", - "libc", - "once_cell", -] - [[package]] name = "widestring" version = "0.4.3" diff --git a/Makefile b/Makefile index b833686e1..cb447e26a 100644 --- a/Makefile +++ b/Makefile @@ -207,7 +207,7 @@ arbitrary-fuzz: # Runs cargo audit (Audit Cargo.lock files for crates with security vulnerabilities reported to the RustSec Advisory Database) audit: cargo install --force cargo-audit - cargo audit --ignore RUSTSEC-2020-0071 + cargo audit --ignore RUSTSEC-2020-0071 --ignore RUSTSEC-2022-0093 # Runs `cargo vendor` to make sure dependencies can be vendored for packaging, reproducibility and archival purpose. vendor: From 687c58fde02b406441e8e8f2b46449adf6458cb8 Mon Sep 17 00:00:00 2001 From: ethDreamer Date: Fri, 18 Aug 2023 03:22:27 +0000 Subject: [PATCH 05/10] Fix Prefer Builder Flag (#4622) --- beacon_node/client/src/config.rs | 2 -- beacon_node/src/config.rs | 7 ++--- lighthouse/tests/beacon_node.rs | 47 ++++++++++++++++++++++---------- 3 files changed, 35 insertions(+), 21 deletions(-) diff --git a/beacon_node/client/src/config.rs b/beacon_node/client/src/config.rs index b4deb52fc..283efe9c3 100644 --- a/beacon_node/client/src/config.rs +++ b/beacon_node/client/src/config.rs @@ -80,7 +80,6 @@ pub struct Config { pub monitoring_api: Option, pub slasher: Option, pub logger_config: LoggerConfig, - pub always_prefer_builder_payload: bool, pub beacon_processor: BeaconProcessorConfig, } @@ -108,7 +107,6 @@ impl Default for Config { validator_monitor_pubkeys: vec![], validator_monitor_individual_tracking_threshold: DEFAULT_INDIVIDUAL_TRACKING_THRESHOLD, logger_config: LoggerConfig::default(), - always_prefer_builder_payload: false, beacon_processor: <_>::default(), } } diff --git a/beacon_node/src/config.rs b/beacon_node/src/config.rs index 0d2a5d812..d2e92b48f 100644 --- a/beacon_node/src/config.rs +++ b/beacon_node/src/config.rs @@ -351,6 +351,9 @@ pub fn get_config( el_config.default_datadir = client_config.data_dir().clone(); el_config.builder_profit_threshold = clap_utils::parse_required(cli_args, "builder-profit-threshold")?; + el_config.always_prefer_builder_payload = + cli_args.is_present("always-prefer-builder-payload"); + let execution_timeout_multiplier = clap_utils::parse_required(cli_args, "execution-timeout-multiplier")?; el_config.execution_timeout_multiplier = Some(execution_timeout_multiplier); @@ -801,10 +804,6 @@ pub fn get_config( if cli_args.is_present("genesis-backfill") { client_config.chain.genesis_backfill = true; } - // Payload selection configs - if cli_args.is_present("always-prefer-builder-payload") { - client_config.always_prefer_builder_payload = true; - } // Backfill sync rate-limiting client_config.beacon_processor.enable_backfill_rate_limiting = diff --git a/lighthouse/tests/beacon_node.rs b/lighthouse/tests/beacon_node.rs index 02b951201..37d224dbc 100644 --- a/lighthouse/tests/beacon_node.rs +++ b/lighthouse/tests/beacon_node.rs @@ -366,21 +366,6 @@ fn genesis_backfill_with_historic_flag() { .with_config(|config| assert_eq!(config.chain.genesis_backfill, true)); } -#[test] -fn always_prefer_builder_payload_flag() { - CommandLineTest::new() - .flag("always-prefer-builder-payload", None) - .run_with_zero_port() - .with_config(|config| assert!(config.always_prefer_builder_payload)); -} - -#[test] -fn no_flag_sets_always_prefer_builder_payload_to_false() { - CommandLineTest::new() - .run_with_zero_port() - .with_config(|config| assert!(!config.always_prefer_builder_payload)); -} - // Tests for Eth1 flags. #[test] fn dummy_eth1_flag() { @@ -735,6 +720,38 @@ fn builder_fallback_flags() { ); }, ); + run_payload_builder_flag_test_with_config( + "builder", + "http://meow.cats", + Some("always-prefer-builder-payload"), + None, + |config| { + assert_eq!( + config + .execution_layer + .as_ref() + .unwrap() + .always_prefer_builder_payload, + true + ); + }, + ); + run_payload_builder_flag_test_with_config( + "builder", + "http://meow.cats", + None, + None, + |config| { + assert_eq!( + config + .execution_layer + .as_ref() + .unwrap() + .always_prefer_builder_payload, + false + ); + }, + ); } #[test] From 20067b94655c9964c62b536831b1d093b3dc57f8 Mon Sep 17 00:00:00 2001 From: Michael Sproul Date: Mon, 21 Aug 2023 05:02:32 +0000 Subject: [PATCH 06/10] Remove checkpoint alignment requirements and enable historic state pruning (#4610) ## Issue Addressed Closes #3210 Closes #3211 ## Proposed Changes - Checkpoint sync from the latest finalized state regardless of its alignment. - Add the `block_root` to the database's split point. This is _only_ added to the in-memory split in order to avoid a schema migration. See `load_split`. - Add a new method to the DB called `get_advanced_state`, which looks up a state _by block root_, with a `state_root` as fallback. Using this method prevents accidental accesses of the split's unadvanced state, which does not exist in the hot DB and is not guaranteed to exist in the freezer DB at all. Previously Lighthouse would look up this state _from the freezer DB_, even if it was required for block/attestation processing, which was suboptimal. - Replace several state look-ups in block and attestation processing with `get_advanced_state` so that they can't hit the split block's unadvanced state. - Do not store any states in the freezer database by default. All states will be deleted upon being evicted from the hot database unless `--reconstruct-historic-states` is set. The anchor info which was previously used for checkpoint sync is used to implement this, including when syncing from genesis. ## Additional Info Needs further testing. I want to stress-test the pruned database under Hydra. The `get_advanced_state` method is intended to become more relevant over time: `tree-states` includes an identically named method that returns advanced states from its in-memory cache. Co-authored-by: realbigsean --- beacon_node/beacon_chain/src/beacon_chain.rs | 13 +- .../src/beacon_fork_choice_store.rs | 12 +- .../beacon_chain/src/block_verification.rs | 17 +- beacon_node/beacon_chain/src/builder.rs | 86 +++-- .../beacon_chain/src/canonical_head.rs | 23 +- beacon_node/beacon_chain/src/migrate.rs | 8 +- .../tests/attestation_verification.rs | 10 +- .../beacon_chain/tests/block_verification.rs | 7 +- .../tests/payload_invalidation.rs | 6 +- beacon_node/beacon_chain/tests/store_tests.rs | 360 +++++++++++++----- beacon_node/beacon_chain/tests/tests.rs | 6 +- beacon_node/client/Cargo.toml | 2 +- beacon_node/client/src/builder.rs | 76 +--- beacon_node/http_api/tests/tests.rs | 21 +- .../gossip_methods.rs | 2 +- beacon_node/store/src/hot_cold_store.rs | 230 ++++++++--- beacon_node/store/src/metadata.rs | 3 + book/src/checkpoint-sync.md | 23 +- consensus/fork_choice/src/fork_choice.rs | 3 +- .../src/fork_choice_test_definition.rs | 1 + .../src/proto_array_fork_choice.rs | 5 +- .../src/per_slot_processing.rs | 2 +- testing/ef_tests/src/cases/fork_choice.rs | 6 +- testing/node_test_rig/src/lib.rs | 3 + watch/tests/tests.rs | 9 +- 25 files changed, 633 insertions(+), 301 deletions(-) diff --git a/beacon_node/beacon_chain/src/beacon_chain.rs b/beacon_node/beacon_chain/src/beacon_chain.rs index 987ea9e7c..d5b86d63f 100644 --- a/beacon_node/beacon_chain/src/beacon_chain.rs +++ b/beacon_node/beacon_chain/src/beacon_chain.rs @@ -4656,6 +4656,7 @@ impl BeaconChain { self.log, "Produced block on state"; "block_size" => block_size, + "slot" => block.slot(), ); metrics::observe(&metrics::BLOCK_SIZE, block_size as f64); @@ -5571,14 +5572,16 @@ impl BeaconChain { let (mut state, state_root) = if let Some((state, state_root)) = head_state_opt { (state, state_root) } else { - let state_root = head_block.state_root; - let state = self + let block_state_root = head_block.state_root; + let max_slot = shuffling_epoch.start_slot(T::EthSpec::slots_per_epoch()); + let (state_root, state) = self .store .get_inconsistent_state_for_attestation_verification_only( - &state_root, - Some(head_block.slot), + &head_block_root, + max_slot, + block_state_root, )? - .ok_or(Error::MissingBeaconState(head_block.state_root))?; + .ok_or(Error::MissingBeaconState(block_state_root))?; (state, state_root) }; diff --git a/beacon_node/beacon_chain/src/beacon_fork_choice_store.rs b/beacon_node/beacon_chain/src/beacon_fork_choice_store.rs index 9b2edbd8b..2a42b49b4 100644 --- a/beacon_node/beacon_chain/src/beacon_fork_choice_store.rs +++ b/beacon_node/beacon_chain/src/beacon_fork_choice_store.rs @@ -321,9 +321,17 @@ where .deconstruct() .0; - let state = self + let max_slot = self + .justified_checkpoint + .epoch + .start_slot(E::slots_per_epoch()); + let (_, state) = self .store - .get_state(&justified_block.state_root(), Some(justified_block.slot())) + .get_advanced_hot_state( + self.justified_checkpoint.root, + max_slot, + justified_block.state_root(), + ) .map_err(Error::FailedToReadState)? .ok_or_else(|| Error::MissingState(justified_block.state_root()))?; diff --git a/beacon_node/beacon_chain/src/block_verification.rs b/beacon_node/beacon_chain/src/block_verification.rs index 0a82eae37..3654484e1 100644 --- a/beacon_node/beacon_chain/src/block_verification.rs +++ b/beacon_node/beacon_chain/src/block_verification.rs @@ -1261,7 +1261,7 @@ impl ExecutionPendingBlock { // Perform a sanity check on the pre-state. let parent_slot = parent.beacon_block.slot(); - if state.slot() < parent_slot || state.slot() > parent_slot + 1 { + if state.slot() < parent_slot || state.slot() > block.slot() { return Err(BeaconChainError::BadPreState { parent_root: parent.beacon_block_root, parent_slot, @@ -1760,13 +1760,18 @@ fn load_parent( BlockError::from(BeaconChainError::MissingBeaconBlock(block.parent_root())) })?; - // Load the parent blocks state from the database, returning an error if it is not found. + // Load the parent block's state from the database, returning an error if it is not found. // It is an error because if we know the parent block we should also know the parent state. - let parent_state_root = parent_block.state_root(); - let parent_state = chain - .get_state(&parent_state_root, Some(parent_block.slot()))? + // Retrieve any state that is advanced through to at most `block.slot()`: this is + // particularly important if `block` descends from the finalized/split block, but at a slot + // prior to the finalized slot (which is invalid and inaccessible in our DB schema). + let (parent_state_root, parent_state) = chain + .store + .get_advanced_hot_state(root, block.slot(), parent_block.state_root())? .ok_or_else(|| { - BeaconChainError::DBInconsistent(format!("Missing state {:?}", parent_state_root)) + BeaconChainError::DBInconsistent( + format!("Missing state for parent block {root:?}",), + ) })?; metrics::inc_counter(&metrics::BLOCK_PROCESSING_SNAPSHOT_CACHE_MISSES); diff --git a/beacon_node/beacon_chain/src/builder.rs b/beacon_node/beacon_chain/src/builder.rs index 044391c41..bb629d662 100644 --- a/beacon_node/beacon_chain/src/builder.rs +++ b/beacon_node/beacon_chain/src/builder.rs @@ -24,8 +24,9 @@ use operation_pool::{OperationPool, PersistedOperationPool}; use parking_lot::RwLock; use proto_array::{DisallowedReOrgOffsets, ReOrgThreshold}; use slasher::Slasher; -use slog::{crit, error, info, Logger}; +use slog::{crit, debug, error, info, Logger}; use slot_clock::{SlotClock, TestingSlotClock}; +use state_processing::per_slot_processing; use std::marker::PhantomData; use std::sync::Arc; use std::time::Duration; @@ -287,7 +288,7 @@ where let genesis_state = store .get_state(&genesis_block.state_root(), Some(genesis_block.slot())) .map_err(|e| descriptive_db_error("genesis state", &e))? - .ok_or("Genesis block not found in store")?; + .ok_or("Genesis state not found in store")?; self.genesis_time = Some(genesis_state.genesis_time()); @@ -382,6 +383,16 @@ where let (genesis, updated_builder) = self.set_genesis_state(beacon_state)?; self = updated_builder; + // Stage the database's metadata fields for atomic storage when `build` is called. + // Since v4.4.0 we will set the anchor with a dummy state upper limit in order to prevent + // historic states from being retained (unless `--reconstruct-historic-states` is set). + let retain_historic_states = self.chain_config.reconstruct_historic_states; + self.pending_io_batch.push( + store + .init_anchor_info(genesis.beacon_block.message(), retain_historic_states) + .map_err(|e| format!("Failed to initialize genesis anchor: {:?}", e))?, + ); + let fc_store = BeaconForkChoiceStore::get_forkchoice_store(store, &genesis) .map_err(|e| format!("Unable to initialize fork choice store: {e:?}"))?; let current_slot = None; @@ -408,30 +419,28 @@ where weak_subj_block: SignedBeaconBlock, genesis_state: BeaconState, ) -> Result { - let store = self.store.clone().ok_or("genesis_state requires a store")?; + let store = self + .store + .clone() + .ok_or("weak_subjectivity_state requires a store")?; + let log = self + .log + .as_ref() + .ok_or("weak_subjectivity_state requires a log")?; - let weak_subj_slot = weak_subj_state.slot(); - let weak_subj_block_root = weak_subj_block.canonical_root(); - let weak_subj_state_root = weak_subj_block.state_root(); - - // Check that the given block lies on an epoch boundary. Due to the database only storing - // full states on epoch boundaries and at restore points it would be difficult to support - // starting from a mid-epoch state. - if weak_subj_slot % TEthSpec::slots_per_epoch() != 0 { - return Err(format!( - "Checkpoint block at slot {} is not aligned to epoch start. \ - Please supply an aligned checkpoint with block.slot % 32 == 0", - weak_subj_block.slot(), - )); - } - - // Check that the block and state have consistent slots and state roots. - if weak_subj_state.slot() != weak_subj_block.slot() { - return Err(format!( - "Slot of snapshot block ({}) does not match snapshot state ({})", - weak_subj_block.slot(), - weak_subj_state.slot(), - )); + // Ensure the state is advanced to an epoch boundary. + let slots_per_epoch = TEthSpec::slots_per_epoch(); + if weak_subj_state.slot() % slots_per_epoch != 0 { + debug!( + log, + "Advancing checkpoint state to boundary"; + "state_slot" => weak_subj_state.slot(), + "block_slot" => weak_subj_block.slot(), + ); + while weak_subj_state.slot() % slots_per_epoch != 0 { + per_slot_processing(&mut weak_subj_state, None, &self.spec) + .map_err(|e| format!("Error advancing state: {e:?}"))?; + } } // Prime all caches before storing the state in the database and computing the tree hash @@ -439,15 +448,19 @@ where weak_subj_state .build_caches(&self.spec) .map_err(|e| format!("Error building caches on checkpoint state: {e:?}"))?; - - let computed_state_root = weak_subj_state + let weak_subj_state_root = weak_subj_state .update_tree_hash_cache() .map_err(|e| format!("Error computing checkpoint state root: {:?}", e))?; - if weak_subj_state_root != computed_state_root { + let weak_subj_slot = weak_subj_state.slot(); + let weak_subj_block_root = weak_subj_block.canonical_root(); + + // Validate the state's `latest_block_header` against the checkpoint block. + let state_latest_block_root = weak_subj_state.get_latest_block_root(weak_subj_state_root); + if weak_subj_block_root != state_latest_block_root { return Err(format!( - "Snapshot state root does not match block, expected: {:?}, got: {:?}", - weak_subj_state_root, computed_state_root + "Snapshot state's most recent block root does not match block, expected: {:?}, got: {:?}", + weak_subj_block_root, state_latest_block_root )); } @@ -464,7 +477,7 @@ where // Set the store's split point *before* storing genesis so that genesis is stored // immediately in the freezer DB. - store.set_split(weak_subj_slot, weak_subj_state_root); + store.set_split(weak_subj_slot, weak_subj_state_root, weak_subj_block_root); let (_, updated_builder) = self.set_genesis_state(genesis_state)?; self = updated_builder; @@ -480,10 +493,11 @@ where // Stage the database's metadata fields for atomic storage when `build` is called. // This prevents the database from restarting in an inconsistent state if the anchor // info or split point is written before the `PersistedBeaconChain`. + let retain_historic_states = self.chain_config.reconstruct_historic_states; self.pending_io_batch.push(store.store_split_in_batch()); self.pending_io_batch.push( store - .init_anchor_info(weak_subj_block.message()) + .init_anchor_info(weak_subj_block.message(), retain_historic_states) .map_err(|e| format!("Failed to initialize anchor info: {:?}", e))?, ); @@ -503,13 +517,12 @@ where let fc_store = BeaconForkChoiceStore::get_forkchoice_store(store, &snapshot) .map_err(|e| format!("Unable to initialize fork choice store: {e:?}"))?; - let current_slot = Some(snapshot.beacon_block.slot()); let fork_choice = ForkChoice::from_anchor( fc_store, snapshot.beacon_block_root, &snapshot.beacon_block, &snapshot.beacon_state, - current_slot, + Some(weak_subj_slot), &self.spec, ) .map_err(|e| format!("Unable to initialize ForkChoice: {:?}", e))?; @@ -672,9 +685,8 @@ where Err(e) => return Err(descriptive_db_error("head block", &e)), }; - let head_state_root = head_block.state_root(); - let head_state = store - .get_state(&head_state_root, Some(head_block.slot())) + let (_head_state_root, head_state) = store + .get_advanced_hot_state(head_block_root, current_slot, head_block.state_root()) .map_err(|e| descriptive_db_error("head state", &e))? .ok_or("Head state not found in store")?; diff --git a/beacon_node/beacon_chain/src/canonical_head.rs b/beacon_node/beacon_chain/src/canonical_head.rs index 2b1f71436..7fa5b0152 100644 --- a/beacon_node/beacon_chain/src/canonical_head.rs +++ b/beacon_node/beacon_chain/src/canonical_head.rs @@ -47,7 +47,8 @@ use crate::{ }; use eth2::types::{EventKind, SseChainReorg, SseFinalizedCheckpoint, SseHead, SseLateHead}; use fork_choice::{ - ExecutionStatus, ForkChoiceView, ForkchoiceUpdateParameters, ProtoBlock, ResetPayloadStatuses, + ExecutionStatus, ForkChoiceStore, ForkChoiceView, ForkchoiceUpdateParameters, ProtoBlock, + ResetPayloadStatuses, }; use itertools::process_results; use parking_lot::{Mutex, RwLock, RwLockReadGuard, RwLockWriteGuard}; @@ -298,10 +299,10 @@ impl CanonicalHead { let beacon_block = store .get_full_block(&beacon_block_root)? .ok_or(Error::MissingBeaconBlock(beacon_block_root))?; - let beacon_state_root = beacon_block.state_root(); - let beacon_state = store - .get_state(&beacon_state_root, Some(beacon_block.slot()))? - .ok_or(Error::MissingBeaconState(beacon_state_root))?; + let current_slot = fork_choice.fc_store().get_current_slot(); + let (_, beacon_state) = store + .get_advanced_hot_state(beacon_block_root, current_slot, beacon_block.state_root())? + .ok_or(Error::MissingBeaconState(beacon_block.state_root()))?; let snapshot = BeaconSnapshot { beacon_block_root, @@ -669,10 +670,14 @@ impl BeaconChain { .get_full_block(&new_view.head_block_root)? .ok_or(Error::MissingBeaconBlock(new_view.head_block_root))?; - let beacon_state_root = beacon_block.state_root(); - let beacon_state: BeaconState = self - .get_state(&beacon_state_root, Some(beacon_block.slot()))? - .ok_or(Error::MissingBeaconState(beacon_state_root))?; + let (_, beacon_state) = self + .store + .get_advanced_hot_state( + new_view.head_block_root, + current_slot, + beacon_block.state_root(), + )? + .ok_or(Error::MissingBeaconState(beacon_block.state_root()))?; Ok(BeaconSnapshot { beacon_block: Arc::new(beacon_block), diff --git a/beacon_node/beacon_chain/src/migrate.rs b/beacon_node/beacon_chain/src/migrate.rs index 8306b66d7..6353a64e0 100644 --- a/beacon_node/beacon_chain/src/migrate.rs +++ b/beacon_node/beacon_chain/src/migrate.rs @@ -266,6 +266,7 @@ impl, Cold: ItemStore> BackgroundMigrator state, @@ -319,7 +320,12 @@ impl, Cold: ItemStore> BackgroundMigrator {} Err(Error::HotColdDBError(HotColdDBError::FreezeSlotUnaligned(slot))) => { debug!( diff --git a/beacon_node/beacon_chain/tests/attestation_verification.rs b/beacon_node/beacon_chain/tests/attestation_verification.rs index 5cea51090..7878fd14a 100644 --- a/beacon_node/beacon_chain/tests/attestation_verification.rs +++ b/beacon_node/beacon_chain/tests/attestation_verification.rs @@ -9,7 +9,7 @@ use beacon_chain::{ test_utils::{ test_spec, AttestationStrategy, BeaconChainHarness, BlockStrategy, EphemeralHarnessType, }, - BeaconChain, BeaconChainError, BeaconChainTypes, WhenSlotSkipped, + BeaconChain, BeaconChainError, BeaconChainTypes, ChainConfig, WhenSlotSkipped, }; use genesis::{interop_genesis_state, DEFAULT_ETH1_BLOCK_HASH}; use int_to_bytes::int_to_bytes32; @@ -47,6 +47,10 @@ fn get_harness(validator_count: usize) -> BeaconChainHarness Vec> { fn get_harness(validator_count: usize) -> BeaconChainHarness> { let harness = BeaconChainHarness::builder(MainnetEthSpec) .default_spec() + .chain_config(ChainConfig { + reconstruct_historic_states: true, + ..ChainConfig::default() + }) .keypairs(KEYPAIRS[0..validator_count].to_vec()) .fresh_ephemeral_store() .mock_execution_layer() diff --git a/beacon_node/beacon_chain/tests/payload_invalidation.rs b/beacon_node/beacon_chain/tests/payload_invalidation.rs index 9a8c324d0..cd4351297 100644 --- a/beacon_node/beacon_chain/tests/payload_invalidation.rs +++ b/beacon_node/beacon_chain/tests/payload_invalidation.rs @@ -7,7 +7,7 @@ use beacon_chain::otb_verification_service::{ use beacon_chain::{ canonical_head::{CachedHead, CanonicalHead}, test_utils::{BeaconChainHarness, EphemeralHarnessType}, - BeaconChainError, BlockError, ExecutionPayloadError, NotifyExecutionLayer, + BeaconChainError, BlockError, ChainConfig, ExecutionPayloadError, NotifyExecutionLayer, OverrideForkchoiceUpdate, StateSkipConfig, WhenSlotSkipped, INVALID_FINALIZED_MERGE_TRANSITION_BLOCK_SHUTDOWN_REASON, INVALID_JUSTIFIED_PAYLOAD_SHUTDOWN_REASON, @@ -59,6 +59,10 @@ impl InvalidPayloadRig { let harness = BeaconChainHarness::builder(MainnetEthSpec) .spec(spec) + .chain_config(ChainConfig { + reconstruct_historic_states: true, + ..ChainConfig::default() + }) .logger(test_logger()) .deterministic_keypairs(VALIDATOR_COUNT) .mock_execution_layer() diff --git a/beacon_node/beacon_chain/tests/store_tests.rs b/beacon_node/beacon_chain/tests/store_tests.rs index 290277482..bf68657b4 100644 --- a/beacon_node/beacon_chain/tests/store_tests.rs +++ b/beacon_node/beacon_chain/tests/store_tests.rs @@ -9,14 +9,15 @@ use beacon_chain::test_utils::{ use beacon_chain::validator_monitor::DEFAULT_INDIVIDUAL_TRACKING_THRESHOLD; use beacon_chain::{ historical_blocks::HistoricalBlockError, migrate::MigratorConfig, BeaconChain, - BeaconChainError, BeaconChainTypes, BeaconSnapshot, ChainConfig, NotifyExecutionLayer, - ServerSentEventHandler, WhenSlotSkipped, + BeaconChainError, BeaconChainTypes, BeaconSnapshot, BlockError, ChainConfig, + NotifyExecutionLayer, ServerSentEventHandler, WhenSlotSkipped, }; use lazy_static::lazy_static; use logging::test_logger; use maplit::hashset; use rand::Rng; -use state_processing::BlockReplayer; +use slot_clock::{SlotClock, TestingSlotClock}; +use state_processing::{state_advance::complete_state_advance, BlockReplayer}; use std::collections::HashMap; use std::collections::HashSet; use std::convert::TryInto; @@ -65,6 +66,19 @@ fn get_store_with_spec( fn get_harness( store: Arc, LevelDB>>, validator_count: usize, +) -> TestHarness { + // Most tests expect to retain historic states, so we use this as the default. + let chain_config = ChainConfig { + reconstruct_historic_states: true, + ..ChainConfig::default() + }; + get_harness_generic(store, validator_count, chain_config) +} + +fn get_harness_generic( + store: Arc, LevelDB>>, + validator_count: usize, + chain_config: ChainConfig, ) -> TestHarness { let harness = BeaconChainHarness::builder(MinimalEthSpec) .default_spec() @@ -72,6 +86,7 @@ fn get_harness( .logger(store.logger().clone()) .fresh_disk_store(store) .mock_execution_layer() + .chain_config(chain_config) .build(); harness.advance_slot(); harness @@ -460,13 +475,15 @@ async fn block_replay_with_inaccurate_state_roots() { .await; // Slot must not be 0 mod 32 or else no blocks will be replayed. - let (mut head_state, head_root) = harness.get_current_state_and_root(); + let (mut head_state, head_state_root) = harness.get_current_state_and_root(); + let head_block_root = harness.head_block_root(); assert_ne!(head_state.slot() % 32, 0); - let mut fast_head_state = store + let (_, mut fast_head_state) = store .get_inconsistent_state_for_attestation_verification_only( - &head_root, - Some(head_state.slot()), + &head_block_root, + head_state.slot(), + head_state_root, ) .unwrap() .unwrap(); @@ -565,14 +582,7 @@ async fn block_replayer_hooks() { async fn delete_blocks_and_states() { let db_path = tempdir().unwrap(); let store = get_store(&db_path); - let validators_keypairs = - types::test_utils::generate_deterministic_keypairs(LOW_VALIDATOR_COUNT); - let harness = BeaconChainHarness::builder(MinimalEthSpec) - .default_spec() - .keypairs(validators_keypairs) - .fresh_disk_store(store.clone()) - .mock_execution_layer() - .build(); + let harness = get_harness(store.clone(), LOW_VALIDATOR_COUNT); let unforked_blocks: u64 = 4 * E::slots_per_epoch(); @@ -1015,18 +1025,14 @@ fn check_shuffling_compatible( // Ensure blocks from abandoned forks are pruned from the Hot DB #[tokio::test] async fn prunes_abandoned_fork_between_two_finalized_checkpoints() { - const HONEST_VALIDATOR_COUNT: usize = 32 + 0; - const ADVERSARIAL_VALIDATOR_COUNT: usize = 16 - 0; + const HONEST_VALIDATOR_COUNT: usize = 32; + const ADVERSARIAL_VALIDATOR_COUNT: usize = 16; const VALIDATOR_COUNT: usize = HONEST_VALIDATOR_COUNT + ADVERSARIAL_VALIDATOR_COUNT; - let validators_keypairs = types::test_utils::generate_deterministic_keypairs(VALIDATOR_COUNT); let honest_validators: Vec = (0..HONEST_VALIDATOR_COUNT).collect(); let adversarial_validators: Vec = (HONEST_VALIDATOR_COUNT..VALIDATOR_COUNT).collect(); - let rig = BeaconChainHarness::builder(MinimalEthSpec) - .default_spec() - .keypairs(validators_keypairs) - .fresh_ephemeral_store() - .mock_execution_layer() - .build(); + let db_path = tempdir().unwrap(); + let store = get_store(&db_path); + let rig = get_harness(store.clone(), VALIDATOR_COUNT); let slots_per_epoch = rig.slots_per_epoch(); let (mut state, state_root) = rig.get_current_state_and_root(); @@ -1125,18 +1131,14 @@ async fn prunes_abandoned_fork_between_two_finalized_checkpoints() { #[tokio::test] async fn pruning_does_not_touch_abandoned_block_shared_with_canonical_chain() { - const HONEST_VALIDATOR_COUNT: usize = 32 + 0; - const ADVERSARIAL_VALIDATOR_COUNT: usize = 16 - 0; + const HONEST_VALIDATOR_COUNT: usize = 32; + const ADVERSARIAL_VALIDATOR_COUNT: usize = 16; const VALIDATOR_COUNT: usize = HONEST_VALIDATOR_COUNT + ADVERSARIAL_VALIDATOR_COUNT; - let validators_keypairs = types::test_utils::generate_deterministic_keypairs(VALIDATOR_COUNT); let honest_validators: Vec = (0..HONEST_VALIDATOR_COUNT).collect(); let adversarial_validators: Vec = (HONEST_VALIDATOR_COUNT..VALIDATOR_COUNT).collect(); - let rig = BeaconChainHarness::builder(MinimalEthSpec) - .default_spec() - .keypairs(validators_keypairs) - .fresh_ephemeral_store() - .mock_execution_layer() - .build(); + let db_path = tempdir().unwrap(); + let store = get_store(&db_path); + let rig = get_harness(store.clone(), VALIDATOR_COUNT); let slots_per_epoch = rig.slots_per_epoch(); let (state, state_root) = rig.get_current_state_and_root(); @@ -1260,15 +1262,11 @@ async fn pruning_does_not_touch_blocks_prior_to_finalization() { const HONEST_VALIDATOR_COUNT: usize = 32; const ADVERSARIAL_VALIDATOR_COUNT: usize = 16; const VALIDATOR_COUNT: usize = HONEST_VALIDATOR_COUNT + ADVERSARIAL_VALIDATOR_COUNT; - let validators_keypairs = types::test_utils::generate_deterministic_keypairs(VALIDATOR_COUNT); let honest_validators: Vec = (0..HONEST_VALIDATOR_COUNT).collect(); let adversarial_validators: Vec = (HONEST_VALIDATOR_COUNT..VALIDATOR_COUNT).collect(); - let rig = BeaconChainHarness::builder(MinimalEthSpec) - .default_spec() - .keypairs(validators_keypairs) - .fresh_ephemeral_store() - .mock_execution_layer() - .build(); + let db_path = tempdir().unwrap(); + let store = get_store(&db_path); + let rig = get_harness(store.clone(), VALIDATOR_COUNT); let slots_per_epoch = rig.slots_per_epoch(); let (mut state, state_root) = rig.get_current_state_and_root(); @@ -1352,18 +1350,14 @@ async fn pruning_does_not_touch_blocks_prior_to_finalization() { #[tokio::test] async fn prunes_fork_growing_past_youngest_finalized_checkpoint() { - const HONEST_VALIDATOR_COUNT: usize = 32 + 0; - const ADVERSARIAL_VALIDATOR_COUNT: usize = 16 - 0; + const HONEST_VALIDATOR_COUNT: usize = 32; + const ADVERSARIAL_VALIDATOR_COUNT: usize = 16; const VALIDATOR_COUNT: usize = HONEST_VALIDATOR_COUNT + ADVERSARIAL_VALIDATOR_COUNT; - let validators_keypairs = types::test_utils::generate_deterministic_keypairs(VALIDATOR_COUNT); let honest_validators: Vec = (0..HONEST_VALIDATOR_COUNT).collect(); let adversarial_validators: Vec = (HONEST_VALIDATOR_COUNT..VALIDATOR_COUNT).collect(); - let rig = BeaconChainHarness::builder(MinimalEthSpec) - .default_spec() - .keypairs(validators_keypairs) - .fresh_ephemeral_store() - .mock_execution_layer() - .build(); + let db_path = tempdir().unwrap(); + let store = get_store(&db_path); + let rig = get_harness(store.clone(), VALIDATOR_COUNT); let (state, state_root) = rig.get_current_state_and_root(); // Fill up 0th epoch with canonical chain blocks @@ -1497,18 +1491,14 @@ async fn prunes_fork_growing_past_youngest_finalized_checkpoint() { // This is to check if state outside of normal block processing are pruned correctly. #[tokio::test] async fn prunes_skipped_slots_states() { - const HONEST_VALIDATOR_COUNT: usize = 32 + 0; - const ADVERSARIAL_VALIDATOR_COUNT: usize = 16 - 0; + const HONEST_VALIDATOR_COUNT: usize = 32; + const ADVERSARIAL_VALIDATOR_COUNT: usize = 16; const VALIDATOR_COUNT: usize = HONEST_VALIDATOR_COUNT + ADVERSARIAL_VALIDATOR_COUNT; - let validators_keypairs = types::test_utils::generate_deterministic_keypairs(VALIDATOR_COUNT); let honest_validators: Vec = (0..HONEST_VALIDATOR_COUNT).collect(); let adversarial_validators: Vec = (HONEST_VALIDATOR_COUNT..VALIDATOR_COUNT).collect(); - let rig = BeaconChainHarness::builder(MinimalEthSpec) - .default_spec() - .keypairs(validators_keypairs) - .fresh_ephemeral_store() - .mock_execution_layer() - .build(); + let db_path = tempdir().unwrap(); + let store = get_store(&db_path); + let rig = get_harness(store.clone(), VALIDATOR_COUNT); let (state, state_root) = rig.get_current_state_and_root(); let canonical_slots_zeroth_epoch: Vec = @@ -1626,18 +1616,14 @@ async fn prunes_skipped_slots_states() { // This is to check if state outside of normal block processing are pruned correctly. #[tokio::test] async fn finalizes_non_epoch_start_slot() { - const HONEST_VALIDATOR_COUNT: usize = 32 + 0; - const ADVERSARIAL_VALIDATOR_COUNT: usize = 16 - 0; + const HONEST_VALIDATOR_COUNT: usize = 32; + const ADVERSARIAL_VALIDATOR_COUNT: usize = 16; const VALIDATOR_COUNT: usize = HONEST_VALIDATOR_COUNT + ADVERSARIAL_VALIDATOR_COUNT; - let validators_keypairs = types::test_utils::generate_deterministic_keypairs(VALIDATOR_COUNT); let honest_validators: Vec = (0..HONEST_VALIDATOR_COUNT).collect(); let adversarial_validators: Vec = (HONEST_VALIDATOR_COUNT..VALIDATOR_COUNT).collect(); - let rig = BeaconChainHarness::builder(MinimalEthSpec) - .default_spec() - .keypairs(validators_keypairs) - .fresh_ephemeral_store() - .mock_execution_layer() - .build(); + let db_path = tempdir().unwrap(); + let store = get_store(&db_path); + let rig = get_harness(store.clone(), VALIDATOR_COUNT); let (state, state_root) = rig.get_current_state_and_root(); let canonical_slots_zeroth_epoch: Vec = @@ -2053,39 +2039,82 @@ async fn garbage_collect_temp_states_from_failed_block() { } #[tokio::test] -async fn weak_subjectivity_sync() { +async fn weak_subjectivity_sync_easy() { + let num_initial_slots = E::slots_per_epoch() * 11; + let checkpoint_slot = Slot::new(E::slots_per_epoch() * 9); + let slots = (1..num_initial_slots).map(Slot::new).collect(); + weak_subjectivity_sync_test(slots, checkpoint_slot).await +} + +#[tokio::test] +async fn weak_subjectivity_sync_unaligned_advanced_checkpoint() { + let num_initial_slots = E::slots_per_epoch() * 11; + let checkpoint_slot = Slot::new(E::slots_per_epoch() * 9); + let slots = (1..num_initial_slots) + .map(Slot::new) + .filter(|&slot| { + // Skip 3 slots leading up to the checkpoint slot. + slot <= checkpoint_slot - 3 || slot > checkpoint_slot + }) + .collect(); + weak_subjectivity_sync_test(slots, checkpoint_slot).await +} + +#[tokio::test] +async fn weak_subjectivity_sync_unaligned_unadvanced_checkpoint() { + let num_initial_slots = E::slots_per_epoch() * 11; + let checkpoint_slot = Slot::new(E::slots_per_epoch() * 9 - 3); + let slots = (1..num_initial_slots) + .map(Slot::new) + .filter(|&slot| { + // Skip 3 slots after the checkpoint slot. + slot <= checkpoint_slot || slot > checkpoint_slot + 3 + }) + .collect(); + weak_subjectivity_sync_test(slots, checkpoint_slot).await +} + +async fn weak_subjectivity_sync_test(slots: Vec, checkpoint_slot: Slot) { // Build an initial chain on one harness, representing a synced node with full history. - let num_initial_blocks = E::slots_per_epoch() * 11; let num_final_blocks = E::slots_per_epoch() * 2; let temp1 = tempdir().unwrap(); let full_store = get_store(&temp1); let harness = get_harness(full_store.clone(), LOW_VALIDATOR_COUNT); + let all_validators = (0..LOW_VALIDATOR_COUNT).collect::>(); + + let (genesis_state, genesis_state_root) = harness.get_current_state_and_root(); harness - .extend_chain( - num_initial_blocks as usize, - BlockStrategy::OnCanonicalHead, - AttestationStrategy::AllValidators, + .add_attested_blocks_at_slots( + genesis_state.clone(), + genesis_state_root, + &slots, + &all_validators, ) .await; - let genesis_state = full_store - .get_state(&harness.chain.genesis_state_root, Some(Slot::new(0))) + let wss_block_root = harness + .chain + .block_root_at_slot(checkpoint_slot, WhenSlotSkipped::Prev) .unwrap() .unwrap(); - let wss_checkpoint = harness.finalized_checkpoint(); + let wss_state_root = harness + .chain + .state_root_at_slot(checkpoint_slot) + .unwrap() + .unwrap(); + let wss_block = harness .chain .store - .get_full_block(&wss_checkpoint.root) + .get_full_block(&wss_block_root) .unwrap() .unwrap(); let wss_state = full_store - .get_state(&wss_block.state_root(), None) + .get_state(&wss_state_root, Some(checkpoint_slot)) .unwrap() .unwrap(); - let wss_slot = wss_block.slot(); // Add more blocks that advance finalization further. harness.advance_slot(); @@ -2104,20 +2133,26 @@ async fn weak_subjectivity_sync() { let spec = test_spec::(); let seconds_per_slot = spec.seconds_per_slot; - // Initialise a new beacon chain from the finalized checkpoint + // Initialise a new beacon chain from the finalized checkpoint. + // The slot clock must be set to a time ahead of the checkpoint state. + let slot_clock = TestingSlotClock::new( + Slot::new(0), + Duration::from_secs(harness.chain.genesis_time), + Duration::from_secs(seconds_per_slot), + ); + slot_clock.set_slot(harness.get_current_slot().as_u64()); let beacon_chain = Arc::new( BeaconChainBuilder::new(MinimalEthSpec) .store(store.clone()) .custom_spec(test_spec::()) .task_executor(harness.chain.task_executor.clone()) + .logger(log.clone()) .weak_subjectivity_state(wss_state, wss_block.clone(), genesis_state) .unwrap() - .logger(log.clone()) .store_migrator_config(MigratorConfig::default().blocking()) .dummy_eth1_backend() .expect("should build dummy backend") - .testing_slot_clock(Duration::from_secs(seconds_per_slot)) - .expect("should configure testing slot clock") + .slot_clock(slot_clock) .shutdown_sender(shutdown_tx) .chain_config(ChainConfig::default()) .event_handler(Some(ServerSentEventHandler::new_with_capacity( @@ -2131,9 +2166,9 @@ async fn weak_subjectivity_sync() { // Apply blocks forward to reach head. let chain_dump = harness.chain.chain_dump().unwrap(); - let new_blocks = &chain_dump[wss_slot.as_usize() + 1..]; - - assert_eq!(new_blocks[0].beacon_block.slot(), wss_slot + 1); + let new_blocks = chain_dump + .iter() + .filter(|snapshot| snapshot.beacon_block.slot() > checkpoint_slot); for snapshot in new_blocks { let full_block = harness @@ -2219,13 +2254,17 @@ async fn weak_subjectivity_sync() { assert_eq!(forwards, expected); // All blocks can be loaded. + let mut prev_block_root = Hash256::zero(); for (block_root, slot) in beacon_chain .forwards_iter_block_roots(Slot::new(0)) .unwrap() .map(Result::unwrap) { let block = store.get_blinded_block(&block_root).unwrap().unwrap(); - assert_eq!(block.slot(), slot); + if block_root != prev_block_root { + assert_eq!(block.slot(), slot); + } + prev_block_root = block_root; } // All states from the oldest state slot can be loaded. @@ -2240,14 +2279,141 @@ async fn weak_subjectivity_sync() { assert_eq!(state.canonical_root(), state_root); } - // Anchor slot is still set to the starting slot. - assert_eq!(store.get_anchor_slot(), Some(wss_slot)); + // Anchor slot is still set to the slot of the checkpoint block. + assert_eq!(store.get_anchor_slot(), Some(wss_block.slot())); // Reconstruct states. store.clone().reconstruct_historic_states().unwrap(); assert_eq!(store.get_anchor_slot(), None); } +/// Test that blocks and attestations that refer to states around an unaligned split state are +/// processed correctly. +#[tokio::test] +async fn process_blocks_and_attestations_for_unaligned_checkpoint() { + let temp = tempdir().unwrap(); + let store = get_store(&temp); + let chain_config = ChainConfig { + reconstruct_historic_states: false, + ..ChainConfig::default() + }; + let harness = get_harness_generic(store.clone(), LOW_VALIDATOR_COUNT, chain_config); + + let all_validators = (0..LOW_VALIDATOR_COUNT).collect::>(); + + let split_slot = Slot::new(E::slots_per_epoch() * 4); + let pre_skips = 1; + let post_skips = 1; + + // Build the chain up to the intended split slot, with 3 skips before the split. + let slots = (1..=split_slot.as_u64() - pre_skips) + .map(Slot::new) + .collect::>(); + + let (genesis_state, genesis_state_root) = harness.get_current_state_and_root(); + harness + .add_attested_blocks_at_slots( + genesis_state.clone(), + genesis_state_root, + &slots, + &all_validators, + ) + .await; + + // Before the split slot becomes finalized, create two forking blocks that build on the split + // block: + // + // - one that is invalid because it conflicts with finalization (slot <= finalized_slot) + // - one that is valid because its slot is not finalized (slot > finalized_slot) + let (unadvanced_split_state, unadvanced_split_state_root) = + harness.get_current_state_and_root(); + + let (invalid_fork_block, _) = harness + .make_block(unadvanced_split_state.clone(), split_slot) + .await; + let (valid_fork_block, _) = harness + .make_block(unadvanced_split_state.clone(), split_slot + 1) + .await; + + // Advance the chain so that the intended split slot is finalized. + // Do not attest in the epoch boundary slot, to make attestation production later easier (no + // equivocations). + let finalizing_slot = split_slot + 2 * E::slots_per_epoch(); + for _ in 0..pre_skips + post_skips { + harness.advance_slot(); + } + harness.extend_to_slot(finalizing_slot - 1).await; + harness + .add_block_at_slot(finalizing_slot, harness.get_current_state()) + .await + .unwrap(); + + // Check that the split slot is as intended. + let split = store.get_split_info(); + assert_eq!(split.slot, split_slot); + assert_eq!(split.block_root, valid_fork_block.parent_root()); + assert_ne!(split.state_root, unadvanced_split_state_root); + + // Applying the invalid block should fail. + let err = harness + .chain + .process_block( + invalid_fork_block.canonical_root(), + Arc::new(invalid_fork_block.clone()), + NotifyExecutionLayer::Yes, + || Ok(()), + ) + .await + .unwrap_err(); + assert!(matches!(err, BlockError::WouldRevertFinalizedSlot { .. })); + + // Applying the valid block should succeed, but it should not become head. + harness + .chain + .process_block( + valid_fork_block.canonical_root(), + Arc::new(valid_fork_block.clone()), + NotifyExecutionLayer::Yes, + || Ok(()), + ) + .await + .unwrap(); + harness.chain.recompute_head_at_current_slot().await; + assert_ne!(harness.head_block_root(), valid_fork_block.canonical_root()); + + // Attestations to the split block in the next 2 epochs should be processed successfully. + let attestation_start_slot = harness.get_current_slot(); + let attestation_end_slot = attestation_start_slot + 2 * E::slots_per_epoch(); + let (split_state_root, mut advanced_split_state) = harness + .chain + .store + .get_advanced_hot_state(split.block_root, split.slot, split.state_root) + .unwrap() + .unwrap(); + complete_state_advance( + &mut advanced_split_state, + Some(split_state_root), + attestation_start_slot, + &harness.chain.spec, + ) + .unwrap(); + advanced_split_state + .build_caches(&harness.chain.spec) + .unwrap(); + let advanced_split_state_root = advanced_split_state.update_tree_hash_cache().unwrap(); + for slot in (attestation_start_slot.as_u64()..attestation_end_slot.as_u64()).map(Slot::new) { + let attestations = harness.make_attestations( + &all_validators, + &advanced_split_state, + advanced_split_state_root, + split.block_root.into(), + slot, + ); + harness.advance_slot(); + harness.process_attestations(attestations); + } +} + #[tokio::test] async fn finalizes_after_resuming_from_db() { let validator_count = 16; @@ -2306,6 +2472,7 @@ async fn finalizes_after_resuming_from_db() { .default_spec() .keypairs(KEYPAIRS[0..validator_count].to_vec()) .resumed_disk_store(store) + .testing_slot_clock(original_chain.slot_clock.clone()) .mock_execution_layer() .build(); @@ -2559,6 +2726,9 @@ async fn schema_downgrade_to_min_version() { SchemaVersion(11) }; + // Save the slot clock so that the new harness doesn't revert in time. + let slot_clock = harness.chain.slot_clock.clone(); + // Close the database to ensure everything is written to disk. drop(store); drop(harness); @@ -2589,11 +2759,21 @@ async fn schema_downgrade_to_min_version() { ) .expect("schema upgrade from minimum version should work"); - // Rescreate the harness. + // Recreate the harness. + /* + let slot_clock = TestingSlotClock::new( + Slot::new(0), + Duration::from_secs(harness.chain.genesis_time), + Duration::from_secs(spec.seconds_per_slot), + ); + slot_clock.set_slot(harness.get_current_slot().as_u64()); + */ + let harness = BeaconChainHarness::builder(MinimalEthSpec) .default_spec() .keypairs(KEYPAIRS[0..LOW_VALIDATOR_COUNT].to_vec()) .logger(store.logger().clone()) + .testing_slot_clock(slot_clock) .resumed_disk_store(store.clone()) .mock_execution_layer() .build(); diff --git a/beacon_node/beacon_chain/tests/tests.rs b/beacon_node/beacon_chain/tests/tests.rs index c5b2892cb..8935c6992 100644 --- a/beacon_node/beacon_chain/tests/tests.rs +++ b/beacon_node/beacon_chain/tests/tests.rs @@ -6,7 +6,7 @@ use beacon_chain::{ AttestationStrategy, BeaconChainHarness, BlockStrategy, EphemeralHarnessType, OP_POOL_DB_KEY, }, - BeaconChain, NotifyExecutionLayer, StateSkipConfig, WhenSlotSkipped, + BeaconChain, ChainConfig, NotifyExecutionLayer, StateSkipConfig, WhenSlotSkipped, }; use lazy_static::lazy_static; use operation_pool::PersistedOperationPool; @@ -28,6 +28,10 @@ lazy_static! { fn get_harness(validator_count: usize) -> BeaconChainHarness> { let harness = BeaconChainHarness::builder(MinimalEthSpec) .default_spec() + .chain_config(ChainConfig { + reconstruct_historic_states: true, + ..ChainConfig::default() + }) .keypairs(KEYPAIRS[0..validator_count].to_vec()) .fresh_ephemeral_store() .mock_execution_layer() diff --git a/beacon_node/client/Cargo.toml b/beacon_node/client/Cargo.toml index 72b6a6c7d..0b517930f 100644 --- a/beacon_node/client/Cargo.toml +++ b/beacon_node/client/Cargo.toml @@ -6,11 +6,11 @@ edition = "2021" [dev-dependencies] serde_yaml = "0.8.13" -state_processing = { path = "../../consensus/state_processing" } operation_pool = { path = "../operation_pool" } tokio = "1.14.0" [dependencies] +state_processing = { path = "../../consensus/state_processing" } beacon_chain = { path = "../beacon_chain" } store = { path = "../store" } network = { path = "../network" } diff --git a/beacon_node/client/src/builder.rs b/beacon_node/client/src/builder.rs index bd2946bb7..b09cf9cca 100644 --- a/beacon_node/client/src/builder.rs +++ b/beacon_node/client/src/builder.rs @@ -309,7 +309,6 @@ where config.chain.checkpoint_sync_url_timeout, )), ); - let slots_per_epoch = TEthSpec::slots_per_epoch(); let deposit_snapshot = if config.sync_eth1_chain { // We want to fetch deposit snapshot before fetching the finalized beacon state to @@ -356,10 +355,23 @@ where None }; - debug!(context.log(), "Downloading finalized block"); - // Find a suitable finalized block on an epoch boundary. - let mut block = remote - .get_beacon_blocks_ssz::(BlockId::Finalized, &spec) + debug!( + context.log(), + "Downloading finalized state"; + ); + let state = remote + .get_debug_beacon_states_ssz::(StateId::Finalized, &spec) + .await + .map_err(|e| format!("Error loading checkpoint state from remote: {:?}", e))? + .ok_or_else(|| "Checkpoint state missing from remote".to_string())?; + + debug!(context.log(), "Downloaded finalized state"; "slot" => ?state.slot()); + + let finalized_block_slot = state.latest_block_header().slot; + + debug!(context.log(), "Downloading finalized block"; "block_slot" => ?finalized_block_slot); + let block = remote + .get_beacon_blocks_ssz::(BlockId::Slot(finalized_block_slot), &spec) .await .map_err(|e| match e { ApiError::InvalidSsz(e) => format!( @@ -373,65 +385,15 @@ where debug!(context.log(), "Downloaded finalized block"); - let mut block_slot = block.slot(); - - while block.slot() % slots_per_epoch != 0 { - block_slot = (block_slot / slots_per_epoch - 1) * slots_per_epoch; - - debug!( - context.log(), - "Searching for aligned checkpoint block"; - "block_slot" => block_slot - ); - - if let Some(found_block) = remote - .get_beacon_blocks_ssz::(BlockId::Slot(block_slot), &spec) - .await - .map_err(|e| { - format!("Error fetching block at slot {}: {:?}", block_slot, e) - })? - { - block = found_block; - } - } - - debug!( - context.log(), - "Downloaded aligned finalized block"; - "block_root" => ?block.canonical_root(), - "block_slot" => block.slot(), - ); - - let state_root = block.state_root(); - debug!( - context.log(), - "Downloading finalized state"; - "state_root" => ?state_root - ); - let state = remote - .get_debug_beacon_states_ssz::(StateId::Root(state_root), &spec) - .await - .map_err(|e| { - format!( - "Error loading checkpoint state from remote {:?}: {:?}", - state_root, e - ) - })? - .ok_or_else(|| { - format!("Checkpoint state missing from remote: {:?}", state_root) - })?; - - debug!(context.log(), "Downloaded finalized state"); - let genesis_state = BeaconState::from_ssz_bytes(&genesis_state_bytes, &spec) .map_err(|e| format!("Unable to parse genesis state SSZ: {:?}", e))?; info!( context.log(), "Loaded checkpoint block and state"; - "slot" => block.slot(), + "block_slot" => block.slot(), + "state_slot" => state.slot(), "block_root" => ?block.canonical_root(), - "state_root" => ?state_root, ); let service = diff --git a/beacon_node/http_api/tests/tests.rs b/beacon_node/http_api/tests/tests.rs index 3ae495378..3c72441c0 100644 --- a/beacon_node/http_api/tests/tests.rs +++ b/beacon_node/http_api/tests/tests.rs @@ -1,7 +1,7 @@ use beacon_chain::test_utils::RelativeSyncCommittee; use beacon_chain::{ test_utils::{AttestationStrategy, BeaconChainHarness, BlockStrategy, EphemeralHarnessType}, - BeaconChain, StateSkipConfig, WhenSlotSkipped, + BeaconChain, ChainConfig, StateSkipConfig, WhenSlotSkipped, }; use environment::null_logger; use eth2::{ @@ -77,6 +77,7 @@ struct ApiTester { struct ApiTesterConfig { spec: ChainSpec, + retain_historic_states: bool, builder_threshold: Option, } @@ -86,11 +87,19 @@ impl Default for ApiTesterConfig { spec.shard_committee_period = 2; Self { spec, + retain_historic_states: false, builder_threshold: None, } } } +impl ApiTesterConfig { + fn retain_historic_states(mut self) -> Self { + self.retain_historic_states = true; + self + } +} + impl ApiTester { pub async fn new() -> Self { // This allows for testing voluntary exits without building out a massive chain. @@ -118,6 +127,10 @@ impl ApiTester { let harness = Arc::new( BeaconChainHarness::builder(MainnetEthSpec) .spec(spec.clone()) + .chain_config(ChainConfig { + reconstruct_historic_states: config.retain_historic_states, + ..ChainConfig::default() + }) .logger(logging::test_logger()) .deterministic_keypairs(VALIDATOR_COUNT) .fresh_ephemeral_store() @@ -375,6 +388,7 @@ impl ApiTester { pub async fn new_mev_tester_no_builder_threshold() -> Self { let mut config = ApiTesterConfig { builder_threshold: Some(0), + retain_historic_states: false, spec: E::default_spec(), }; config.spec.altair_fork_epoch = Some(Epoch::new(0)); @@ -4705,7 +4719,7 @@ async fn get_validator_duties_attester_with_skip_slots() { #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn get_validator_duties_proposer() { - ApiTester::new() + ApiTester::new_from_config(ApiTesterConfig::default().retain_historic_states()) .await .test_get_validator_duties_proposer() .await; @@ -4713,7 +4727,7 @@ async fn get_validator_duties_proposer() { #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn get_validator_duties_proposer_with_skip_slots() { - ApiTester::new() + ApiTester::new_from_config(ApiTesterConfig::default().retain_historic_states()) .await .skip_slots(E::slots_per_epoch() * 2) .test_get_validator_duties_proposer() @@ -5045,6 +5059,7 @@ async fn builder_payload_chosen_by_profit() { async fn builder_works_post_capella() { let mut config = ApiTesterConfig { builder_threshold: Some(0), + retain_historic_states: false, spec: E::default_spec(), }; config.spec.altair_fork_epoch = Some(Epoch::new(0)); diff --git a/beacon_node/network/src/network_beacon_processor/gossip_methods.rs b/beacon_node/network/src/network_beacon_processor/gossip_methods.rs index cb4d6f9c2..ac7479db0 100644 --- a/beacon_node/network/src/network_beacon_processor/gossip_methods.rs +++ b/beacon_node/network/src/network_beacon_processor/gossip_methods.rs @@ -2062,7 +2062,7 @@ impl NetworkBeaconProcessor { ); } AttnError::BeaconChainError(BeaconChainError::DBError(Error::HotColdDBError( - HotColdDBError::AttestationStateIsFinalized { .. }, + HotColdDBError::FinalizedStateNotInHotDatabase { .. }, ))) => { debug!(self.log, "Attestation for finalized state"; "peer_id" => % peer_id); self.propagate_validation_result(message_id, peer_id, MessageAcceptance::Ignore); diff --git a/beacon_node/store/src/hot_cold_store.rs b/beacon_node/store/src/hot_cold_store.rs index 7695ea520..47839ed3e 100644 --- a/beacon_node/store/src/hot_cold_store.rs +++ b/beacon_node/store/src/hot_cold_store.rs @@ -14,7 +14,7 @@ use crate::memory_store::MemoryStore; use crate::metadata::{ AnchorInfo, CompactionTimestamp, PruningCheckpoint, SchemaVersion, ANCHOR_INFO_KEY, COMPACTION_TIMESTAMP_KEY, CONFIG_KEY, CURRENT_SCHEMA_VERSION, PRUNING_CHECKPOINT_KEY, - SCHEMA_VERSION_KEY, SPLIT_KEY, + SCHEMA_VERSION_KEY, SPLIT_KEY, STATE_UPPER_LIMIT_NO_RETAIN, }; use crate::metrics; use crate::{ @@ -110,10 +110,10 @@ pub enum HotColdDBError { IterationError { unexpected_key: BytesKey, }, - AttestationStateIsFinalized { + FinalizedStateNotInHotDatabase { split_slot: Slot, - request_slot: Option, - state_root: Hash256, + request_slot: Slot, + block_root: Hash256, }, } @@ -545,7 +545,7 @@ impl, Cold: ItemStore> HotColdDB /// upon that state (e.g., state roots). Additionally, only states from the hot store are /// returned. /// - /// See `Self::get_state` for information about `slot`. + /// See `Self::get_advanced_hot_state` for information about `max_slot`. /// /// ## Warning /// @@ -557,23 +557,78 @@ impl, Cold: ItemStore> HotColdDB /// - `state.block_roots` pub fn get_inconsistent_state_for_attestation_verification_only( &self, - state_root: &Hash256, - slot: Option, - ) -> Result>, Error> { + block_root: &Hash256, + max_slot: Slot, + state_root: Hash256, + ) -> Result)>, Error> { metrics::inc_counter(&metrics::BEACON_STATE_GET_COUNT); + self.get_advanced_hot_state_with_strategy( + *block_root, + max_slot, + state_root, + StateProcessingStrategy::Inconsistent, + ) + } - let split_slot = self.get_split_slot(); + /// Get a state with `latest_block_root == block_root` advanced through to at most `max_slot`. + /// + /// The `state_root` argument is used to look up the block's un-advanced state in case an + /// advanced state is not found. + /// + /// Return the `(result_state_root, state)` satisfying: + /// + /// - `result_state_root == state.canonical_root()` + /// - `state.slot() <= max_slot` + /// - `state.get_latest_block_root(result_state_root) == block_root` + /// + /// Presently this is only used to avoid loading the un-advanced split state, but in future will + /// be expanded to return states from an in-memory cache. + pub fn get_advanced_hot_state( + &self, + block_root: Hash256, + max_slot: Slot, + state_root: Hash256, + ) -> Result)>, Error> { + self.get_advanced_hot_state_with_strategy( + block_root, + max_slot, + state_root, + StateProcessingStrategy::Accurate, + ) + } - if slot.map_or(false, |slot| slot < split_slot) { - Err(HotColdDBError::AttestationStateIsFinalized { - split_slot, - request_slot: slot, - state_root: *state_root, + /// Same as `get_advanced_hot_state` but taking a `StateProcessingStrategy`. + pub fn get_advanced_hot_state_with_strategy( + &self, + block_root: Hash256, + max_slot: Slot, + state_root: Hash256, + state_processing_strategy: StateProcessingStrategy, + ) -> Result)>, Error> { + // Hold a read lock on the split point so it can't move while we're trying to load the + // state. + let split = self.split.read_recursive(); + + // Sanity check max-slot against the split slot. + if max_slot < split.slot { + return Err(HotColdDBError::FinalizedStateNotInHotDatabase { + split_slot: split.slot, + request_slot: max_slot, + block_root, } - .into()) - } else { - self.load_hot_state(state_root, StateProcessingStrategy::Inconsistent) + .into()); } + + let state_root = if block_root == split.block_root && split.slot <= max_slot { + split.state_root + } else { + state_root + }; + let state = self + .load_hot_state(&state_root, state_processing_strategy)? + .map(|state| (state_root, state)); + drop(split); + Ok(state) } /// Delete a state, ensuring it is removed from the LRU cache, as well as from on-disk. @@ -1180,8 +1235,12 @@ impl, Cold: ItemStore> HotColdDB *self.split.read_recursive() } - pub fn set_split(&self, slot: Slot, state_root: Hash256) { - *self.split.write() = Split { slot, state_root }; + pub fn set_split(&self, slot: Slot, state_root: Hash256, block_root: Hash256) { + *self.split.write() = Split { + slot, + state_root, + block_root, + }; } /// Fetch the slot of the most recently stored restore point. @@ -1216,25 +1275,36 @@ impl, Cold: ItemStore> HotColdDB } /// Initialise the anchor info for checkpoint sync starting from `block`. - pub fn init_anchor_info(&self, block: BeaconBlockRef<'_, E>) -> Result { + pub fn init_anchor_info( + &self, + block: BeaconBlockRef<'_, E>, + retain_historic_states: bool, + ) -> Result { let anchor_slot = block.slot(); let slots_per_restore_point = self.config.slots_per_restore_point; - // Set the `state_upper_limit` to the slot of the *next* restore point. - // See `get_state_upper_limit` for rationale. - let next_restore_point_slot = if anchor_slot % slots_per_restore_point == 0 { + let state_upper_limit = if !retain_historic_states { + STATE_UPPER_LIMIT_NO_RETAIN + } else if anchor_slot % slots_per_restore_point == 0 { anchor_slot } else { + // Set the `state_upper_limit` to the slot of the *next* restore point. + // See `get_state_upper_limit` for rationale. (anchor_slot / slots_per_restore_point + 1) * slots_per_restore_point }; - let anchor_info = AnchorInfo { - anchor_slot, - oldest_block_slot: anchor_slot, - oldest_block_parent: block.parent_root(), - state_upper_limit: next_restore_point_slot, - state_lower_limit: self.spec.genesis_slot, + let anchor_info = if state_upper_limit == 0 && anchor_slot == 0 { + // Genesis archive node: no anchor because we *will* store all states. + None + } else { + Some(AnchorInfo { + anchor_slot, + oldest_block_slot: anchor_slot, + oldest_block_parent: block.parent_root(), + state_upper_limit, + state_lower_limit: self.spec.genesis_slot, + }) }; - self.compare_and_set_anchor_info(None, Some(anchor_info)) + self.compare_and_set_anchor_info(None, anchor_info) } /// Get a clone of the store's anchor info. @@ -1361,11 +1431,26 @@ impl, Cold: ItemStore> HotColdDB self.hot_db.put(&CONFIG_KEY, &self.config.as_disk_config()) } - /// Load the split point from disk. - fn load_split(&self) -> Result, Error> { + /// Load the split point from disk, sans block root. + fn load_split_partial(&self) -> Result, Error> { self.hot_db.get(&SPLIT_KEY) } + /// Load the split point from disk, including block root. + fn load_split(&self) -> Result, Error> { + match self.load_split_partial()? { + Some(mut split) => { + // Load the hot state summary to get the block root. + let summary = self.load_hot_state_summary(&split.state_root)?.ok_or( + HotColdDBError::MissingSplitState(split.state_root, split.slot), + )?; + split.block_root = summary.latest_block_root; + Ok(Some(split)) + } + None => Ok(None), + } + } + /// Stage the split for storage to disk. pub fn store_split_in_batch(&self) -> KeyValueStoreOp { self.split.read_recursive().as_kv_store_op(SPLIT_KEY) @@ -1611,42 +1696,40 @@ impl, Cold: ItemStore> HotColdDB /// Advance the split point of the store, moving new finalized states to the freezer. pub fn migrate_database, Cold: ItemStore>( store: Arc>, - frozen_head_root: Hash256, - frozen_head: &BeaconState, + finalized_state_root: Hash256, + finalized_block_root: Hash256, + finalized_state: &BeaconState, ) -> Result<(), Error> { debug!( store.log, "Freezer migration started"; - "slot" => frozen_head.slot() + "slot" => finalized_state.slot() ); // 0. Check that the migration is sensible. - // The new frozen head must increase the current split slot, and lie on an epoch + // The new finalized state must increase the current split slot, and lie on an epoch // boundary (in order for the hot state summary scheme to work). let current_split_slot = store.split.read_recursive().slot; - let anchor_slot = store - .anchor_info - .read_recursive() - .as_ref() - .map(|a| a.anchor_slot); + let anchor_info = store.anchor_info.read_recursive().clone(); + let anchor_slot = anchor_info.as_ref().map(|a| a.anchor_slot); - if frozen_head.slot() < current_split_slot { + if finalized_state.slot() < current_split_slot { return Err(HotColdDBError::FreezeSlotError { current_split_slot, - proposed_split_slot: frozen_head.slot(), + proposed_split_slot: finalized_state.slot(), } .into()); } - if frozen_head.slot() % E::slots_per_epoch() != 0 { - return Err(HotColdDBError::FreezeSlotUnaligned(frozen_head.slot()).into()); + if finalized_state.slot() % E::slots_per_epoch() != 0 { + return Err(HotColdDBError::FreezeSlotUnaligned(finalized_state.slot()).into()); } let mut hot_db_ops: Vec> = Vec::new(); - // 1. Copy all of the states between the head and the split slot, from the hot DB + // 1. Copy all of the states between the new finalized state and the split slot, from the hot DB // to the cold DB. Delete the execution payloads of these now-finalized blocks. - let state_root_iter = RootsIterator::new(&store, frozen_head); + let state_root_iter = RootsIterator::new(&store, finalized_state); for maybe_tuple in state_root_iter.take_while(|result| match result { Ok((_, _, slot)) => { slot >= ¤t_split_slot @@ -1656,6 +1739,29 @@ pub fn migrate_database, Cold: ItemStore>( }) { let (block_root, state_root, slot) = maybe_tuple?; + // Delete the execution payload if payload pruning is enabled. At a skipped slot we may + // delete the payload for the finalized block itself, but that's OK as we only guarantee + // that payloads are present for slots >= the split slot. The payload fetching code is also + // forgiving of missing payloads. + if store.config.prune_payloads { + hot_db_ops.push(StoreOp::DeleteExecutionPayload(block_root)); + } + + // Delete the old summary, and the full state if we lie on an epoch boundary. + hot_db_ops.push(StoreOp::DeleteState(state_root, Some(slot))); + + // Do not try to store states if a restore point is yet to be stored, or will never be + // stored (see `STATE_UPPER_LIMIT_NO_RETAIN`). Make an exception for the genesis state + // which always needs to be copied from the hot DB to the freezer and should not be deleted. + if slot != 0 + && anchor_info + .as_ref() + .map_or(false, |anchor| slot < anchor.state_upper_limit) + { + debug!(store.log, "Pruning finalized state"; "slot" => slot); + continue; + } + let mut cold_db_ops: Vec = Vec::new(); if slot % store.config.slots_per_restore_point == 0 { @@ -1674,17 +1780,6 @@ pub fn migrate_database, Cold: ItemStore>( // There are data dependencies between calls to `store_cold_state()` that prevent us from // doing one big call to `store.cold_db.do_atomically()` at end of the loop. store.cold_db.do_atomically(cold_db_ops)?; - - // Delete the old summary, and the full state if we lie on an epoch boundary. - hot_db_ops.push(StoreOp::DeleteState(state_root, Some(slot))); - - // Delete the execution payload if payload pruning is enabled. At a skipped slot we may - // delete the payload for the finalized block itself, but that's OK as we only guarantee - // that payloads are present for slots >= the split slot. The payload fetching code is also - // forgiving of missing payloads. - if store.config.prune_payloads { - hot_db_ops.push(StoreOp::DeleteExecutionPayload(block_root)); - } } // Warning: Critical section. We have to take care not to put any of the two databases in an @@ -1724,8 +1819,9 @@ pub fn migrate_database, Cold: ItemStore>( // Before updating the in-memory split value, we flush it to disk first, so that should the // OS process die at this point, we pick up from the right place after a restart. let split = Split { - slot: frozen_head.slot(), - state_root: frozen_head_root, + slot: finalized_state.slot(), + state_root: finalized_state_root, + block_root: finalized_block_root, }; store.hot_db.put_sync(&SPLIT_KEY, &split)?; @@ -1741,7 +1837,7 @@ pub fn migrate_database, Cold: ItemStore>( debug!( store.log, "Freezer migration complete"; - "slot" => frozen_head.slot() + "slot" => finalized_state.slot() ); Ok(()) @@ -1750,8 +1846,16 @@ pub fn migrate_database, Cold: ItemStore>( /// Struct for storing the split slot and state root in the database. #[derive(Debug, Clone, Copy, PartialEq, Default, Encode, Decode, Deserialize, Serialize)] pub struct Split { - pub(crate) slot: Slot, - pub(crate) state_root: Hash256, + pub slot: Slot, + pub state_root: Hash256, + /// The block root of the split state. + /// + /// This is used to provide special handling for the split state in the case where there are + /// skipped slots. The split state will *always* be the advanced state, so callers + /// who only have the finalized block root should use `get_advanced_hot_state` to get this state, + /// rather than fetching `block.state_root()` (the unaligned state) which will have been pruned. + #[ssz(skip_serializing, skip_deserializing)] + pub block_root: Hash256, } impl StoreItem for Split { diff --git a/beacon_node/store/src/metadata.rs b/beacon_node/store/src/metadata.rs index 6f50d7038..ccfddcf8f 100644 --- a/beacon_node/store/src/metadata.rs +++ b/beacon_node/store/src/metadata.rs @@ -16,6 +16,9 @@ pub const PRUNING_CHECKPOINT_KEY: Hash256 = Hash256::repeat_byte(3); pub const COMPACTION_TIMESTAMP_KEY: Hash256 = Hash256::repeat_byte(4); pub const ANCHOR_INFO_KEY: Hash256 = Hash256::repeat_byte(5); +/// State upper limit value used to indicate that a node is not storing historic states. +pub const STATE_UPPER_LIMIT_NO_RETAIN: Slot = Slot::new(u64::MAX); + #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub struct SchemaVersion(pub u64); diff --git a/book/src/checkpoint-sync.md b/book/src/checkpoint-sync.md index 578838289..0c375a5f0 100644 --- a/book/src/checkpoint-sync.md +++ b/book/src/checkpoint-sync.md @@ -75,7 +75,7 @@ Once backfill is complete, a `INFO Historical block download complete` log will > Note: Since [v4.1.0](https://github.com/sigp/lighthouse/releases/tag/v4.1.0), Lighthouse implements rate-limited backfilling to mitigate validator performance issues after a recent checkpoint sync. This means that the speed at which historical blocks are downloaded is limited, typically to less than 20 slots/sec. This will not affect validator performance. However, if you would still prefer to sync the chain as fast as possible, you can add the flag `--disable-backfill-rate-limiting` to the beacon node. -> Note: Since [v4.2.0](https://github.com/sigp/lighthouse/releases/tag/v4.2.0), Lighthouse limits the backfill sync to only sync backwards to the weak subjectivity point (approximately 5 months). This will help to save disk space. However, if you would like to sync back to the genesis, you can add the flag `--genesis-backfill` to the beacon node. +> Note: Since [v4.2.0](https://github.com/sigp/lighthouse/releases/tag/v4.2.0), Lighthouse limits the backfill sync to only sync backwards to the weak subjectivity point (approximately 5 months). This will help to save disk space. However, if you would like to sync back to the genesis, you can add the flag `--genesis-backfill` to the beacon node. ## FAQ @@ -116,8 +116,9 @@ states: database. Additionally, the genesis block is always available. * `state_lower_limit`: All states with slots _less than or equal to_ this value are available in the database. The minimum value is 0, indicating that the genesis state is always available. -* `state_upper_limit`: All states with slots _greater than or equal to_ this value are available - in the database. +* `state_upper_limit`: All states with slots _greater than or equal to_ `min(split.slot, + state_upper_limit)` are available in the database. In the case where the `state_upper_limit` is + higher than the `split.slot`, this means states are not being written to the freezer database. Reconstruction runs from the state lower limit to the upper limit, narrowing the window of unavailable states as it goes. It will log messages like the following to show its progress: @@ -153,18 +154,8 @@ To manually specify a checkpoint use the following two flags: * `--checkpoint-state`: accepts an SSZ-encoded `BeaconState` blob * `--checkpoint-block`: accepts an SSZ-encoded `SignedBeaconBlock` blob -_Both_ the state and block must be provided and **must** adhere to the [Alignment -Requirements](#alignment-requirements) described below. - -### Alignment Requirements - -* The block must be a finalized block from an epoch boundary, i.e. `block.slot() % 32 == 0`. -* The state must be the state corresponding to `block` with `state.slot() == block.slot()` - and `state.hash_tree_root() == block.state_root()`. - -These requirements are imposed to align with Lighthouse's database schema, and notably exclude -finalized blocks from skipped slots. You can avoid alignment issues by using -[Automatic Checkpoint Sync](#automatic-checkpoint-sync), which will search for a suitable block -and state pair. +_Both_ the state and block must be provided and the state **must** match the block. The +state may be from the same slot as the block (unadvanced), or advanced to an epoch boundary, +in which case it will be assumed to be finalized at that epoch. [weak-subj]: https://blog.ethereum.org/2014/11/25/proof-stake-learned-love-weak-subjectivity/ diff --git a/consensus/fork_choice/src/fork_choice.rs b/consensus/fork_choice/src/fork_choice.rs index 4f563f863..b3749ea9d 100644 --- a/consensus/fork_choice/src/fork_choice.rs +++ b/consensus/fork_choice/src/fork_choice.rs @@ -355,7 +355,7 @@ where spec: &ChainSpec, ) -> Result> { // Sanity check: the anchor must lie on an epoch boundary. - if anchor_block.slot() % E::slots_per_epoch() != 0 { + if anchor_state.slot() % E::slots_per_epoch() != 0 { return Err(Error::InvalidAnchor { block_slot: anchor_block.slot(), state_slot: anchor_state.slot(), @@ -391,6 +391,7 @@ where let current_slot = current_slot.unwrap_or_else(|| fc_store.get_current_slot()); let proto_array = ProtoArrayForkChoice::new::( + current_slot, finalized_block_slot, finalized_block_state_root, *fc_store.justified_checkpoint(), diff --git a/consensus/proto_array/src/fork_choice_test_definition.rs b/consensus/proto_array/src/fork_choice_test_definition.rs index 157f072ad..98d43e485 100644 --- a/consensus/proto_array/src/fork_choice_test_definition.rs +++ b/consensus/proto_array/src/fork_choice_test_definition.rs @@ -80,6 +80,7 @@ impl ForkChoiceTestDefinition { let junk_shuffling_id = AttestationShufflingId::from_components(Epoch::new(0), Hash256::zero()); let mut fork_choice = ProtoArrayForkChoice::new::( + self.finalized_block_slot, self.finalized_block_slot, Hash256::zero(), self.justified_checkpoint, diff --git a/consensus/proto_array/src/proto_array_fork_choice.rs b/consensus/proto_array/src/proto_array_fork_choice.rs index fe831b3c3..5911e50fc 100644 --- a/consensus/proto_array/src/proto_array_fork_choice.rs +++ b/consensus/proto_array/src/proto_array_fork_choice.rs @@ -345,6 +345,7 @@ pub struct ProtoArrayForkChoice { impl ProtoArrayForkChoice { #[allow(clippy::too_many_arguments)] pub fn new( + current_slot: Slot, finalized_block_slot: Slot, finalized_block_state_root: Hash256, justified_checkpoint: Checkpoint, @@ -380,7 +381,7 @@ impl ProtoArrayForkChoice { }; proto_array - .on_block::(block, finalized_block_slot) + .on_block::(block, current_slot) .map_err(|e| format!("Failed to add finalized block to proto_array: {:?}", e))?; Ok(Self { @@ -983,6 +984,7 @@ mod test_compute_deltas { }; let mut fc = ProtoArrayForkChoice::new::( + genesis_slot, genesis_slot, state_root, genesis_checkpoint, @@ -1108,6 +1110,7 @@ mod test_compute_deltas { }; let mut fc = ProtoArrayForkChoice::new::( + genesis_slot, genesis_slot, junk_state_root, genesis_checkpoint, diff --git a/consensus/state_processing/src/per_slot_processing.rs b/consensus/state_processing/src/per_slot_processing.rs index ead06edbf..e16fb4a7b 100644 --- a/consensus/state_processing/src/per_slot_processing.rs +++ b/consensus/state_processing/src/per_slot_processing.rs @@ -21,7 +21,7 @@ impl From for Error { /// /// If the root of the supplied `state` is known, then it can be passed as `state_root`. If /// `state_root` is `None`, the root of `state` will be computed using a cached tree hash. -/// Providing the `state_root` makes this function several orders of magniude faster. +/// Providing the `state_root` makes this function several orders of magnitude faster. pub fn per_slot_processing( state: &mut BeaconState, state_root: Option, diff --git a/testing/ef_tests/src/cases/fork_choice.rs b/testing/ef_tests/src/cases/fork_choice.rs index 9627d2cde..c4f288a8a 100644 --- a/testing/ef_tests/src/cases/fork_choice.rs +++ b/testing/ef_tests/src/cases/fork_choice.rs @@ -7,7 +7,7 @@ use beacon_chain::{ obtain_indexed_attestation_and_committees_per_slot, VerifiedAttestation, }, test_utils::{BeaconChainHarness, EphemeralHarnessType}, - BeaconChainTypes, CachedHead, NotifyExecutionLayer, + BeaconChainTypes, CachedHead, ChainConfig, NotifyExecutionLayer, }; use execution_layer::{json_structures::JsonPayloadStatusV1Status, PayloadStatusV1}; use serde::Deserialize; @@ -303,6 +303,10 @@ impl Tester { let harness = BeaconChainHarness::builder(E::default()) .spec(spec.clone()) .keypairs(vec![]) + .chain_config(ChainConfig { + reconstruct_historic_states: true, + ..ChainConfig::default() + }) .genesis_state_ephemeral_store(case.anchor_state.clone()) .mock_execution_layer() .recalculate_fork_times_with_genesis(0) diff --git a/testing/node_test_rig/src/lib.rs b/testing/node_test_rig/src/lib.rs index 394f8558f..3cd8205eb 100644 --- a/testing/node_test_rig/src/lib.rs +++ b/testing/node_test_rig/src/lib.rs @@ -115,6 +115,9 @@ pub fn testing_client_config() -> ClientConfig { genesis_time: now, }; + // Simulator tests expect historic states to be available for post-run checks. + client_config.chain.reconstruct_historic_states = true; + // Specify a constant count of beacon processor workers. Having this number // too low can cause annoying HTTP timeouts, especially on Github runners // with 2 logical CPUs. diff --git a/watch/tests/tests.rs b/watch/tests/tests.rs index af1cde26b..9032b124a 100644 --- a/watch/tests/tests.rs +++ b/watch/tests/tests.rs @@ -1,8 +1,9 @@ #![recursion_limit = "256"] #![cfg(unix)] -use beacon_chain::test_utils::{ - AttestationStrategy, BeaconChainHarness, BlockStrategy, EphemeralHarnessType, +use beacon_chain::{ + test_utils::{AttestationStrategy, BeaconChainHarness, BlockStrategy, EphemeralHarnessType}, + ChainConfig, }; use eth2::{types::BlockId, BeaconNodeHttpClient, SensitiveUrl, Timeouts}; use http_api::test_utils::{create_api_server, ApiServer}; @@ -91,6 +92,10 @@ impl TesterBuilder { pub async fn new() -> TesterBuilder { let harness = BeaconChainHarness::builder(E::default()) .default_spec() + .chain_config(ChainConfig { + reconstruct_historic_states: true, + ..ChainConfig::default() + }) .deterministic_keypairs(VALIDATOR_COUNT) .fresh_ephemeral_store() .build(); From b3e1c297c8e0ab2e62b3a5068576d94f0e0585ab Mon Sep 17 00:00:00 2001 From: zhiqiangxu <652732310@qq.com> Date: Mon, 21 Aug 2023 05:02:33 +0000 Subject: [PATCH 07/10] `ForkChoice`: remove an impossible case for `parent_checkpoints` (#4626) `parent_finalized.epoch + 1 > block_epoch` will never be `true` since as the comment says: ``` A block in epoch `N` cannot contain attestations which would finalize an epoch higher than `N - 1`. ``` --- consensus/fork_choice/src/fork_choice.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/consensus/fork_choice/src/fork_choice.rs b/consensus/fork_choice/src/fork_choice.rs index b3749ea9d..ea3a58127 100644 --- a/consensus/fork_choice/src/fork_choice.rs +++ b/consensus/fork_choice/src/fork_choice.rs @@ -750,7 +750,7 @@ where .unrealized_justified_checkpoint .zip(parent_block.unrealized_finalized_checkpoint) .filter(|(parent_justified, parent_finalized)| { - parent_justified.epoch == block_epoch && parent_finalized.epoch + 1 >= block_epoch + parent_justified.epoch == block_epoch && parent_finalized.epoch + 1 == block_epoch }); let (unrealized_justified_checkpoint, unrealized_finalized_checkpoint) = if let Some(( From 524d9af2884a53eee1e3c5c07db85ac4f6a6df8d Mon Sep 17 00:00:00 2001 From: Michael Sproul Date: Mon, 21 Aug 2023 05:02:34 +0000 Subject: [PATCH 08/10] Fix beacon-processor-max-workers (#4636) ## Issue Addressed Fixes a bug in the handling of `--beacon-process-max-workers` which caused it to have no effect. ## Proposed Changes For this PR I channeled @ethDreamer and saw deep into the faulty CLI config -- this bug is almost identical to the one Mark found and fixed in #4622. --- Cargo.lock | 2 -- beacon_node/beacon_processor/src/lib.rs | 5 ++--- beacon_node/client/Cargo.toml | 1 - beacon_node/client/src/builder.rs | 2 -- beacon_node/http_api/src/test_utils.rs | 14 ++++++++------ beacon_node/network/Cargo.toml | 1 - .../network/src/network_beacon_processor/tests.rs | 2 -- 7 files changed, 10 insertions(+), 17 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 116f8081f..9a8cf4833 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1053,7 +1053,6 @@ dependencies = [ "logging", "monitoring_api", "network", - "num_cpus", "operation_pool", "parking_lot 0.12.1", "sensitive_url", @@ -5037,7 +5036,6 @@ dependencies = [ "logging", "lru_cache", "matches", - "num_cpus", "operation_pool", "parking_lot 0.12.1", "rand 0.8.5", diff --git a/beacon_node/beacon_processor/src/lib.rs b/beacon_node/beacon_processor/src/lib.rs index bf5d8bced..4c1da85fa 100644 --- a/beacon_node/beacon_processor/src/lib.rs +++ b/beacon_node/beacon_processor/src/lib.rs @@ -708,7 +708,6 @@ impl Stream for InboundEvents { pub struct BeaconProcessor { pub network_globals: Arc>, pub executor: TaskExecutor, - pub max_workers: usize, pub current_workers: usize, pub config: BeaconProcessorConfig, pub log: Logger, @@ -721,7 +720,7 @@ impl BeaconProcessor { /// - Performed immediately, if a worker is available. /// - Queued for later processing, if no worker is currently available. /// - /// Only `self.max_workers` will ever be spawned at one time. Each worker is a `tokio` task + /// Only `self.config.max_workers` will ever be spawned at one time. Each worker is a `tokio` task /// started with `spawn_blocking`. /// /// The optional `work_journal_tx` allows for an outside process to receive a log of all work @@ -896,7 +895,7 @@ impl BeaconProcessor { let _ = work_journal_tx.try_send(id); } - let can_spawn = self.current_workers < self.max_workers; + let can_spawn = self.current_workers < self.config.max_workers; let drop_during_sync = work_event .as_ref() .map_or(false, |event| event.drop_during_sync); diff --git a/beacon_node/client/Cargo.toml b/beacon_node/client/Cargo.toml index 0b517930f..87e165090 100644 --- a/beacon_node/client/Cargo.toml +++ b/beacon_node/client/Cargo.toml @@ -44,4 +44,3 @@ slasher_service = { path = "../../slasher/service" } monitoring_api = {path = "../../common/monitoring_api"} execution_layer = { path = "../execution_layer" } beacon_processor = { path = "../beacon_processor" } -num_cpus = "1.13.0" diff --git a/beacon_node/client/src/builder.rs b/beacon_node/client/src/builder.rs index b09cf9cca..4de6d1262 100644 --- a/beacon_node/client/src/builder.rs +++ b/beacon_node/client/src/builder.rs @@ -29,7 +29,6 @@ use network::{NetworkConfig, NetworkSenders, NetworkService}; use slasher::Slasher; use slasher_service::SlasherService; use slog::{debug, info, warn, Logger}; -use std::cmp; use std::net::TcpListener; use std::path::{Path, PathBuf}; use std::sync::Arc; @@ -757,7 +756,6 @@ where BeaconProcessor { network_globals: network_globals.clone(), executor: beacon_processor_context.executor.clone(), - max_workers: cmp::max(1, num_cpus::get()), current_workers: 0, config: beacon_processor_config, log: beacon_processor_context.log().clone(), diff --git a/beacon_node/http_api/src/test_utils.rs b/beacon_node/http_api/src/test_utils.rs index dcc253222..b1478f3f2 100644 --- a/beacon_node/http_api/src/test_utils.rs +++ b/beacon_node/http_api/src/test_utils.rs @@ -184,7 +184,14 @@ pub async fn create_api_server_on_port( let eth1_service = eth1::Service::new(eth1::Config::default(), log.clone(), chain.spec.clone()).unwrap(); - let beacon_processor_config = BeaconProcessorConfig::default(); + let beacon_processor_config = BeaconProcessorConfig { + // The number of workers must be greater than one. Tests which use the + // builder workflow sometimes require an internal HTTP request in order + // to fulfill an already in-flight HTTP request, therefore having only + // one worker will result in a deadlock. + max_workers: 2, + ..BeaconProcessorConfig::default() + }; let BeaconProcessorChannels { beacon_processor_tx, beacon_processor_rx, @@ -196,11 +203,6 @@ pub async fn create_api_server_on_port( BeaconProcessor { network_globals: network_globals.clone(), executor: test_runtime.task_executor.clone(), - // The number of workers must be greater than one. Tests which use the - // builder workflow sometimes require an internal HTTP request in order - // to fulfill an already in-flight HTTP request, therefore having only - // one worker will result in a deadlock. - max_workers: 2, current_workers: 0, config: beacon_processor_config, log: log.clone(), diff --git a/beacon_node/network/Cargo.toml b/beacon_node/network/Cargo.toml index c37b0fa45..715e77bca 100644 --- a/beacon_node/network/Cargo.toml +++ b/beacon_node/network/Cargo.toml @@ -36,7 +36,6 @@ logging = { path = "../../common/logging" } task_executor = { path = "../../common/task_executor" } igd = "0.12.1" itertools = "0.10.0" -num_cpus = "1.13.0" lru_cache = { path = "../../common/lru_cache" } if-addrs = "0.6.4" strum = "0.24.0" diff --git a/beacon_node/network/src/network_beacon_processor/tests.rs b/beacon_node/network/src/network_beacon_processor/tests.rs index ce5b91411..a678edbf1 100644 --- a/beacon_node/network/src/network_beacon_processor/tests.rs +++ b/beacon_node/network/src/network_beacon_processor/tests.rs @@ -20,7 +20,6 @@ use lighthouse_network::{ Client, MessageId, NetworkGlobals, PeerId, }; use slot_clock::SlotClock; -use std::cmp; use std::iter::Iterator; use std::sync::Arc; use std::time::Duration; @@ -228,7 +227,6 @@ impl TestRig { let beacon_processor = BeaconProcessor { network_globals, executor, - max_workers: cmp::max(1, num_cpus::get()), current_workers: 0, config: beacon_processor_config, log: log.clone(), From 91f3bc274b063921e41c7a37386e86680697e875 Mon Sep 17 00:00:00 2001 From: Aoi Kurokawa Date: Mon, 21 Aug 2023 05:02:35 +0000 Subject: [PATCH 09/10] Fix the link of anvil in lighthouse book (#4641) ## Issue Addressed Wrong link for anvil ## Proposed Changes Fix the link to correct one. --- book/src/setup.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/book/src/setup.md b/book/src/setup.md index 533e1d463..1ae6e6354 100644 --- a/book/src/setup.md +++ b/book/src/setup.md @@ -9,7 +9,7 @@ particularly useful for development but still a good way to ensure you have the base dependencies. The additional requirements for developers are: -- [`anvil`](https://github.com/foundry-rs/foundry/tree/master/anvil). This is used to +- [`anvil`](https://github.com/foundry-rs/foundry/tree/master/crates/anvil). This is used to simulate the execution chain during tests. You'll get failures during tests if you don't have `anvil` available on your `PATH`. - [`cmake`](https://cmake.org/cmake/help/latest/command/install.html). Used by From f92b856cd1b25b7e51a35747e613a5f22e6973d3 Mon Sep 17 00:00:00 2001 From: Jimmy Chen Date: Mon, 21 Aug 2023 05:02:36 +0000 Subject: [PATCH 10/10] Remove Antithesis docker build workflow (#4642) ## Issue Addressed This PR remove Antithesis docker build CI workflow. Confirmed with Antithesis team that this is no longer used. --- .github/workflows/docker-antithesis.yml | 35 ------------------ testing/antithesis/Dockerfile.libvoidstar | 25 ------------- testing/antithesis/libvoidstar/libvoidstar.so | Bin 348192 -> 0 bytes 3 files changed, 60 deletions(-) delete mode 100644 .github/workflows/docker-antithesis.yml delete mode 100644 testing/antithesis/Dockerfile.libvoidstar delete mode 100644 testing/antithesis/libvoidstar/libvoidstar.so diff --git a/.github/workflows/docker-antithesis.yml b/.github/workflows/docker-antithesis.yml deleted file mode 100644 index a96431faf..000000000 --- a/.github/workflows/docker-antithesis.yml +++ /dev/null @@ -1,35 +0,0 @@ -name: docker antithesis - -on: - push: - branches: - - unstable - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - -env: - ANTITHESIS_PASSWORD: ${{ secrets.ANTITHESIS_PASSWORD }} - ANTITHESIS_USERNAME: ${{ secrets.ANTITHESIS_USERNAME }} - ANTITHESIS_SERVER: ${{ secrets.ANTITHESIS_SERVER }} - REPOSITORY: ${{ secrets.ANTITHESIS_REPOSITORY }} - IMAGE_NAME: lighthouse - TAG: libvoidstar - -jobs: - build-docker: - runs-on: ubuntu-22.04 - steps: - - uses: actions/checkout@v3 - - name: Update Rust - run: rustup update stable - - name: Dockerhub login - run: | - echo "${ANTITHESIS_PASSWORD}" | docker login --username ${ANTITHESIS_USERNAME} https://${ANTITHESIS_SERVER} --password-stdin - - name: Build AMD64 dockerfile (with push) - run: | - docker build \ - --tag ${ANTITHESIS_SERVER}/${REPOSITORY}/${IMAGE_NAME}:${TAG} \ - --file ./testing/antithesis/Dockerfile.libvoidstar . - docker push ${ANTITHESIS_SERVER}/${REPOSITORY}/${IMAGE_NAME}:${TAG} diff --git a/testing/antithesis/Dockerfile.libvoidstar b/testing/antithesis/Dockerfile.libvoidstar deleted file mode 100644 index c790e248d..000000000 --- a/testing/antithesis/Dockerfile.libvoidstar +++ /dev/null @@ -1,25 +0,0 @@ -FROM rust:1.68.2-bullseye AS builder -RUN apt-get update && apt-get -y upgrade && apt-get install -y cmake libclang-dev -COPY . lighthouse - -# Build lighthouse directly with a cargo build command, bypassing the Makefile. -RUN cd lighthouse && LD_LIBRARY_PATH=/lighthouse/testing/antithesis/libvoidstar/ RUSTFLAGS="-Cpasses=sancov-module -Cllvm-args=-sanitizer-coverage-level=3 -Cllvm-args=-sanitizer-coverage-trace-pc-guard -Ccodegen-units=1 -Cdebuginfo=2 -L/lighthouse/testing/antithesis/libvoidstar/ -lvoidstar" cargo build --release --manifest-path lighthouse/Cargo.toml --target x86_64-unknown-linux-gnu --features modern --verbose --bin lighthouse -# build lcli binary directly with cargo install command, bypassing the makefile -RUN cargo install --path /lighthouse/lcli --force --locked - -FROM ubuntu:latest -RUN apt-get update && apt-get -y upgrade && apt-get install -y --no-install-recommends \ - libssl-dev \ - ca-certificates \ - && apt-get clean \ - && rm -rf /var/lib/apt/lists/* - -# create and move the libvoidstar file -RUN mkdir libvoidstar -COPY --from=builder /lighthouse/testing/antithesis/libvoidstar/libvoidstar.so /usr/lib/libvoidstar.so - -# set the env variable to avoid having to always set it -ENV LD_LIBRARY_PATH=/usr/lib -# move the lighthouse binary and lcli binary -COPY --from=builder /lighthouse/target/x86_64-unknown-linux-gnu/release/lighthouse /usr/local/bin/lighthouse -COPY --from=builder /lighthouse/target/release/lcli /usr/local/bin/lcli \ No newline at end of file diff --git a/testing/antithesis/libvoidstar/libvoidstar.so b/testing/antithesis/libvoidstar/libvoidstar.so deleted file mode 100644 index 0f8a0f23c3fb7a349788bc8d5532dc71bb821c68..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 348192 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

-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