diff --git a/Cargo.lock b/Cargo.lock index d1d7d3bf773..d041c005187 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3732,6 +3732,7 @@ dependencies = [ "operation_pool", "parking_lot 0.12.2", "proto_array", + "rand", "safe_arith", "sensitive_url", "serde", diff --git a/beacon_node/beacon_chain/src/chain_config.rs b/beacon_node/beacon_chain/src/chain_config.rs index 255b8f00497..b6b42c8dd9b 100644 --- a/beacon_node/beacon_chain/src/chain_config.rs +++ b/beacon_node/beacon_chain/src/chain_config.rs @@ -86,6 +86,8 @@ pub struct ChainConfig { pub epochs_per_migration: u64, /// When set to true Light client server computes and caches state proofs for serving updates pub enable_light_client_server: bool, + /// Enable malicious PeerDAS mode where node withholds data columns when publishing a block + pub malicious_withhold_count: usize, } impl Default for ChainConfig { @@ -118,6 +120,7 @@ impl Default for ChainConfig { always_prepare_payload: false, epochs_per_migration: crate::migrate::DEFAULT_EPOCHS_PER_MIGRATION, enable_light_client_server: false, + malicious_withhold_count: 0, } } } diff --git a/beacon_node/http_api/Cargo.toml b/beacon_node/http_api/Cargo.toml index b58e0442f7c..37f6222a480 100644 --- a/beacon_node/http_api/Cargo.toml +++ b/beacon_node/http_api/Cargo.toml @@ -43,6 +43,7 @@ sensitive_url = { workspace = true } store = { workspace = true } bytes = { workspace = true } beacon_processor = { workspace = true } +rand = { workspace = true } [dev-dependencies] environment = { workspace = true } diff --git a/beacon_node/http_api/src/publish_blocks.rs b/beacon_node/http_api/src/publish_blocks.rs index 8219f97b2a5..29f28c3ba2c 100644 --- a/beacon_node/http_api/src/publish_blocks.rs +++ b/beacon_node/http_api/src/publish_blocks.rs @@ -11,6 +11,7 @@ use eth2::types::{FullPayloadContents, PublishBlockRequest}; use execution_layer::ProvenancedPayload; use lighthouse_network::{NetworkGlobals, PubsubMessage}; use network::NetworkMessage; +use rand::seq::SliceRandom; use slog::{debug, error, info, warn, Logger}; use slot_clock::SlotClock; use std::marker::PhantomData; @@ -71,6 +72,7 @@ pub async fn publish_block block.slot()); + let malicious_withhold_count = chain.config.malicious_withhold_count; /* actually publish a block */ let publish_block = move |block: Arc>, @@ -117,6 +119,19 @@ pub async fn publish_block 0 { + let columns_to_keep = data_col_sidecars + .len() + .saturating_sub(malicious_withhold_count); + // Randomize columns before dropping the last malicious_withhold_count items + data_col_sidecars.shuffle(&mut rand::thread_rng()); + data_col_sidecars = data_col_sidecars + .into_iter() + .take(columns_to_keep) + .collect::>(); + } + for data_col in data_col_sidecars { let subnet = DataColumnSubnetId::from_column_index::( data_col.index as usize, diff --git a/beacon_node/src/cli.rs b/beacon_node/src/cli.rs index 9c0972d4bbd..d4a733f8ef9 100644 --- a/beacon_node/src/cli.rs +++ b/beacon_node/src/cli.rs @@ -46,6 +46,12 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> { subscribed to all data column subnets.") .takes_value(false), ) + .arg( + Arg::with_name("malicious-withhold-count") + .long("malicious-withhold-count") + .help("TESTING ONLY do not use this") + .takes_value(true), + ) .arg( Arg::with_name("subscribe-all-subnets") .long("subscribe-all-subnets") diff --git a/beacon_node/src/config.rs b/beacon_node/src/config.rs index 32c279601d2..3211c26d76d 100644 --- a/beacon_node/src/config.rs +++ b/beacon_node/src/config.rs @@ -443,10 +443,10 @@ pub fn get_config( client_config.store.epochs_per_blob_prune = epochs_per_blob_prune; } - if let Some(blob_prune_margin_epochs) = - clap_utils::parse_optional(cli_args, "blob-prune-margin-epochs")? + if let Some(malicious_withhold_count) = + clap_utils::parse_optional(cli_args, "malicious-withhold-count")? { - client_config.store.blob_prune_margin_epochs = blob_prune_margin_epochs; + client_config.chain.malicious_withhold_count = malicious_withhold_count; } /* diff --git a/book/src/help_bn.md b/book/src/help_bn.md index 894369ca9f6..89d037d48ae 100644 --- a/book/src/help_bn.md +++ b/book/src/help_bn.md @@ -259,7 +259,7 @@ OPTIONS: --graffiti Specify your custom graffiti to be included in blocks. Defaults to the current version and commit, truncated - to fit in 32 bytes. + to fit in 32 bytes. --historic-state-cache-size Specifies how many states from the freezer database should cache in memory [default: 1] @@ -324,6 +324,9 @@ OPTIONS: --logfile-max-size The maximum size (in MB) each log file can grow to before rotating. If set to 0, background file logging is disabled. [default: 200] + --malicious-withhold-count + TESTING ONLY do not use this + --max-skip-slots Refuse to skip more than this many slots when processing an attestation. This prevents nodes on minority forks from wasting our time and disk space, but could also cause unnecessary consensus failures, so is diff --git a/lighthouse/tests/beacon_node.rs b/lighthouse/tests/beacon_node.rs index f589da439a6..e814ef77db7 100644 --- a/lighthouse/tests/beacon_node.rs +++ b/lighthouse/tests/beacon_node.rs @@ -1987,6 +1987,13 @@ fn epochs_per_migration_override() { .run_with_zero_port() .with_config(|config| assert_eq!(config.chain.epochs_per_migration, 128)); } +#[test] +fn malicious_withhold_count_flag() { + CommandLineTest::new() + .flag("malicious-withhold-count", Some("128")) + .run_with_zero_port() + .with_config(|config| assert_eq!(config.chain.malicious_withhold_count, 128)); +} // Tests for Slasher flags. // Using `--slasher-max-db-size` to work around https://github.com/sigp/lighthouse/issues/2342