diff --git a/Cargo.lock b/Cargo.lock index e324e48ce05..3d664151d13 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -528,7 +528,7 @@ checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" [[package]] name = "beacon-api-client" version = "0.1.0" -source = "git+https://github.com/ralexstokes/beacon-api-client?rev=56a290c#56a290ca9d2c67086917a0929cdf2fe35e5f917f" +source = "git+https://github.com/ralexstokes/beacon-api-client?rev=7f28993615fde52d563dd601a0511c34fe9b7c38#7f28993615fde52d563dd601a0511c34fe9b7c38" dependencies = [ "clap 4.3.21", "ethereum-consensus", @@ -2413,7 +2413,7 @@ dependencies = [ [[package]] name = "ethereum-consensus" version = "0.1.1" -source = "git+https://github.com/jimmygchen/ethereum-consensus?rev=2354493#2354493fd631b736c189868b7dc1b415a160f0f7" +source = "git+https://github.com/ralexstokes/ethereum-consensus?rev=12508c1f9b0c8f4bf4c5e9b6d441e840c1b37fd9#12508c1f9b0c8f4bf4c5e9b6d441e840c1b37fd9" dependencies = [ "async-stream", "blst", @@ -4906,7 +4906,7 @@ dependencies = [ [[package]] name = "mev-rs" version = "0.3.0" -source = "git+https://github.com/ralexstokes/mev-rs?rev=9d88a2386b58c2948fa850f0dd4b3dfe18bd4962#9d88a2386b58c2948fa850f0dd4b3dfe18bd4962" +source = "git+https://github.com/jimmygchen/mev-rs?rev=dedc77a#dedc77a796986603fb3376c5f353863d09e0dbf2" dependencies = [ "anvil-rpc", "async-trait", diff --git a/Cargo.toml b/Cargo.toml index 2450212c426..02f0becbbd6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -94,10 +94,6 @@ resolver = "2" [patch.crates-io] warp = { git = "https://github.com/macladson/warp", rev="7e75acc368229a46a236a8c991bf251fe7fe50ef" } -# PR: https://github.com/ralexstokes/ethereum-consensus/pull/213 -[patch."https://github.com/ralexstokes/ethereum-consensus"] -ethereum-consensus = { git = "https://github.com/jimmygchen/ethereum-consensus", rev = "2354493" } - [profile.maxperf] inherits = "release" lto = "fat" diff --git a/beacon_node/beacon_chain/src/beacon_chain.rs b/beacon_node/beacon_chain/src/beacon_chain.rs index 8e1ae3de2ef..fb2fc582200 100644 --- a/beacon_node/beacon_chain/src/beacon_chain.rs +++ b/beacon_node/beacon_chain/src/beacon_chain.rs @@ -118,7 +118,6 @@ use store::{ use task_executor::{ShutdownReason, TaskExecutor}; use tokio_stream::Stream; use tree_hash::TreeHash; -use types::beacon_block_body::from_block_kzg_commitments; use types::beacon_state::CloneConfig; use types::blob_sidecar::{BlobSidecarList, FixedBlobSidecarList}; use types::sidecar::BlobItems; @@ -4994,11 +4993,8 @@ impl BeaconChain { metrics::start_timer(&metrics::BLOCK_PRODUCTION_BLOBS_VERIFICATION_TIMES); let maybe_sidecar_list = match (blobs_opt, proofs_opt) { (Some(blobs_or_blobs_roots), Some(proofs)) => { - let expected_kzg_commitments = block - .body() - .blob_kzg_commitments() - .map(from_block_kzg_commitments::) - .map_err(|_| { + let expected_kzg_commitments = + block.body().blob_kzg_commitments().map_err(|_| { BlockProductionError::InvalidBlockVariant( "deneb block does not contain kzg commitments".to_string(), ) @@ -5022,7 +5018,7 @@ impl BeaconChain { .ok_or(BlockProductionError::TrustedSetupNotInitialized)?; kzg_utils::validate_blobs::( kzg, - &expected_kzg_commitments, + expected_kzg_commitments, blobs, &kzg_proofs, ) @@ -5033,7 +5029,7 @@ impl BeaconChain { Sidecar::build_sidecar( blobs_or_blobs_roots, &block, - &expected_kzg_commitments, + expected_kzg_commitments, kzg_proofs, ) .map_err(BlockProductionError::FailedToBuildBlobSidecars)?, diff --git a/beacon_node/execution_layer/Cargo.toml b/beacon_node/execution_layer/Cargo.toml index 89ad9915ffb..7dd1951866e 100644 --- a/beacon_node/execution_layer/Cargo.toml +++ b/beacon_node/execution_layer/Cargo.toml @@ -42,8 +42,9 @@ lazy_static = "1.4.0" ethers-core = "1.0.2" builder_client = { path = "../builder_client" } fork_choice = { path = "../../consensus/fork_choice" } -mev-rs = { git = "https://github.com/ralexstokes/mev-rs", rev = "9d88a2386b58c2948fa850f0dd4b3dfe18bd4962" } -ethereum-consensus = { git = "https://github.com/ralexstokes/ethereum-consensus", rev = "56418ea" } +#PR: https://github.com/ralexstokes/mev-rs/pull/124 +mev-rs = { git = "https://github.com/jimmygchen/mev-rs", rev = "dedc77a" } +ethereum-consensus = { git = "https://github.com/ralexstokes/ethereum-consensus", rev = "12508c1f9b0c8f4bf4c5e9b6d441e840c1b37fd9" } ssz_rs = "0.9.0" tokio-stream = { version = "0.1.9", features = [ "sync" ] } strum = "0.24.0" diff --git a/beacon_node/execution_layer/src/engine_api/json_structures.rs b/beacon_node/execution_layer/src/engine_api/json_structures.rs index f35cc7dc572..eee413cd583 100644 --- a/beacon_node/execution_layer/src/engine_api/json_structures.rs +++ b/beacon_node/execution_layer/src/engine_api/json_structures.rs @@ -2,7 +2,7 @@ use super::*; use serde::{Deserialize, Serialize}; use strum::EnumString; use superstruct::superstruct; -use types::beacon_block_body::BuilderKzgCommitments; +use types::beacon_block_body::KzgCommitments; use types::blob_sidecar::BlobsList; use types::{ EthSpec, ExecutionBlockHash, ExecutionPayload, ExecutionPayloadCapella, ExecutionPayloadDeneb, @@ -438,7 +438,7 @@ impl From for PayloadAttributes { #[derive(Debug, PartialEq, Serialize, Deserialize)] #[serde(bound = "E: EthSpec", rename_all = "camelCase")] pub struct JsonBlobsBundleV1 { - pub commitments: BuilderKzgCommitments, + pub commitments: KzgCommitments, pub proofs: KzgProofs, #[serde(with = "ssz_types::serde_utils::list_of_hex_fixed_vec")] pub blobs: BlobsList, diff --git a/beacon_node/execution_layer/src/lib.rs b/beacon_node/execution_layer/src/lib.rs index f5c77a332e6..aa2bc7feabc 100644 --- a/beacon_node/execution_layer/src/lib.rs +++ b/beacon_node/execution_layer/src/lib.rs @@ -39,7 +39,7 @@ use tokio::{ }; use tokio_stream::wrappers::WatchStream; use tree_hash::TreeHash; -use types::beacon_block_body::{to_block_kzg_commitments, BlockBodyKzgCommitments}; +use types::beacon_block_body::KzgCommitments; use types::builder_bid::BuilderBid; use types::sidecar::{BlobItems, Sidecar}; use types::KzgProofs; @@ -110,9 +110,7 @@ impl> TryFrom> .try_into() .map_err(|_| Error::InvalidPayloadConversion)?, block_value: builder_bid.value, - kzg_commitments: to_block_kzg_commitments::( - builder_bid.blinded_blobs_bundle.commitments, - ), + kzg_commitments: builder_bid.blinded_blobs_bundle.commitments, blobs: BlobItems::try_from_blob_roots(builder_bid.blinded_blobs_bundle.blob_roots) .map_err(Error::InvalidBlobConversion)?, proofs: builder_bid.blinded_blobs_bundle.proofs, @@ -168,7 +166,7 @@ pub enum BlockProposalContents> { PayloadAndBlobs { payload: Payload, block_value: Uint256, - kzg_commitments: BlockBodyKzgCommitments, + kzg_commitments: KzgCommitments, blobs: >::BlobItems, proofs: KzgProofs, }, @@ -185,7 +183,7 @@ impl> TryFrom> Some(bundle) => Ok(Self::PayloadAndBlobs { payload: execution_payload.into(), block_value, - kzg_commitments: to_block_kzg_commitments::(bundle.commitments), + kzg_commitments: bundle.commitments, blobs: BlobItems::try_from_blobs(bundle.blobs) .map_err(Error::InvalidBlobConversion)?, proofs: bundle.proofs, @@ -204,7 +202,7 @@ impl> BlockProposalContents ( Payload, - Option>, + Option>, Option<>::BlobItems>, Option>, ) { diff --git a/beacon_node/execution_layer/src/test_utils/mock_builder.rs b/beacon_node/execution_layer/src/test_utils/mock_builder.rs index ccf6fecf283..7af0d26627f 100644 --- a/beacon_node/execution_layer/src/test_utils/mock_builder.rs +++ b/beacon_node/execution_layer/src/test_utils/mock_builder.rs @@ -39,7 +39,7 @@ use tree_hash::TreeHash; use types::builder_bid::BlindedBlobsBundle; use types::{ Address, BeaconState, ChainSpec, EthSpec, ExecPayload, ExecutionPayload, - ExecutionPayloadHeader, ForkName, Hash256, Slot, Uint256, + ExecutionPayloadHeader, ForkName, ForkVersionedResponse, Hash256, Slot, Uint256, }; #[derive(Clone)] @@ -533,7 +533,13 @@ impl mev_rs::BlindedBlockProvider for MockBuilder { .get_payload_by_root(&from_ssz_rs(&node)?) .ok_or_else(|| convert_err("missing payload for tx root"))?; - let json_payload = serde_json::to_string(&payload).map_err(convert_err)?; + let fork = payload.payload_ref().fork_name(); + let resp = ForkVersionedResponse { + version: Some(fork), + data: payload, + }; + + let json_payload = serde_json::to_string(&resp).map_err(convert_err)?; serde_json::from_str(json_payload.as_str()).map_err(convert_err) } } diff --git a/beacon_node/http_api/src/publish_blocks.rs b/beacon_node/http_api/src/publish_blocks.rs index caf1b2cc990..8666a18dd8b 100644 --- a/beacon_node/http_api/src/publish_blocks.rs +++ b/beacon_node/http_api/src/publish_blocks.rs @@ -20,7 +20,7 @@ use tokio::sync::mpsc::UnboundedSender; use tree_hash::TreeHash; use types::{ AbstractExecPayload, BeaconBlockRef, BlindedPayload, EthSpec, ExecPayload, ExecutionBlockHash, - FullPayload, Hash256, SignedBeaconBlock, SignedBlobSidecarList, + ForkName, FullPayload, FullPayloadMerge, Hash256, SignedBeaconBlock, SignedBlobSidecarList, }; use warp::Rejection; @@ -308,18 +308,17 @@ pub async fn reconstruct_block( // If the execution block hash is zero, use an empty payload. let full_payload_contents = if payload_header.block_hash() == ExecutionBlockHash::zero() { - let payload = FullPayload::default_at_fork( - chain - .spec - .fork_name_at_epoch(block.slot().epoch(T::EthSpec::slots_per_epoch())), - ) - .map_err(|e| { - warp_utils::reject::custom_server_error(format!( - "Default payload construction error: {e:?}" - )) - })? - .into(); - ProvenancedPayload::Local(FullPayloadContents::Payload(payload)) + let fork_name = chain + .spec + .fork_name_at_epoch(block.slot().epoch(T::EthSpec::slots_per_epoch())); + if fork_name == ForkName::Merge { + let payload: FullPayload = FullPayloadMerge::default().into(); + ProvenancedPayload::Local(FullPayloadContents::Payload(payload.into())) + } else { + Err(warp_utils::reject::custom_server_error( + "Failed to construct full payload - block hash must be non-zero after Bellatrix.".to_string() + ))? + } // If we already have an execution payload with this transactions root cached, use it. } else if let Some(cached_payload) = el.get_payload_by_root(&payload_header.tree_hash_root()) diff --git a/beacon_node/network/src/sync/block_lookups/tests.rs b/beacon_node/network/src/sync/block_lookups/tests.rs index ec88ffb1623..422de8e0c5b 100644 --- a/beacon_node/network/src/sync/block_lookups/tests.rs +++ b/beacon_node/network/src/sync/block_lookups/tests.rs @@ -17,7 +17,6 @@ use lighthouse_network::{NetworkGlobals, Request}; use slot_clock::{ManualSlotClock, SlotClock, TestingSlotClock}; use store::MemoryStore; use tokio::sync::mpsc; -use types::beacon_block_body::to_block_kzg_commitments; use types::{ map_fork_name, map_fork_name_with, test_utils::{SeedableRng, TestRandom, XorShiftRng}, @@ -124,8 +123,7 @@ impl TestRig { for tx in Vec::from(transactions) { payload.execution_payload.transactions.push(tx).unwrap(); } - message.body.blob_kzg_commitments = - to_block_kzg_commitments::(bundle.commitments.clone()); + message.body.blob_kzg_commitments = bundle.commitments.clone(); let eth2::types::BlobsBundle { commitments, diff --git a/common/eth2/src/types.rs b/common/eth2/src/types.rs index e37e3cdcac5..efb85341b75 100644 --- a/common/eth2/src/types.rs +++ b/common/eth2/src/types.rs @@ -12,7 +12,7 @@ use std::fmt::{self, Display}; use std::str::{from_utf8, FromStr}; use std::time::Duration; use tree_hash::TreeHash; -use types::beacon_block_body::BuilderKzgCommitments; +use types::beacon_block_body::KzgCommitments; use types::builder_bid::BlindedBlobsBundle; pub use types::*; @@ -1793,7 +1793,7 @@ pub struct ExecutionPayloadAndBlobs { #[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize, Encode)] #[serde(bound = "E: EthSpec")] pub struct BlobsBundle { - pub commitments: BuilderKzgCommitments, + pub commitments: KzgCommitments, pub proofs: KzgProofs, #[serde(with = "ssz_types::serde_utils::list_of_hex_fixed_vec")] pub blobs: BlobsList, diff --git a/consensus/types/src/beacon_block_body.rs b/consensus/types/src/beacon_block_body.rs index decccb1fbfb..61400a8b4b7 100644 --- a/consensus/types/src/beacon_block_body.rs +++ b/consensus/types/src/beacon_block_body.rs @@ -9,24 +9,9 @@ use superstruct::superstruct; use test_random_derive::TestRandom; use tree_hash_derive::TreeHash; -//TODO: Remove this type and use `BlockBodyKzgCommitments` everywhere when this PR is merged: -// https://github.com/ethereum/builder-specs/pull/87 -pub type BuilderKzgCommitments = VariableList::MaxBlobsPerBlock>; -pub type BlockBodyKzgCommitments = +pub type KzgCommitments = VariableList::MaxBlobCommitmentsPerBlock>; -pub fn to_block_kzg_commitments( - commitments: BuilderKzgCommitments, -) -> BlockBodyKzgCommitments { - commitments.to_vec().into() -} - -pub fn from_block_kzg_commitments( - commitments: &BlockBodyKzgCommitments, -) -> BuilderKzgCommitments { - commitments.to_vec().into() -} - /// The body of a `BeaconChain` block, containing operations. /// /// This *superstruct* abstracts over the hard-fork. @@ -87,7 +72,7 @@ pub struct BeaconBlockBody = FullPay pub bls_to_execution_changes: VariableList, #[superstruct(only(Deneb))] - pub blob_kzg_commitments: BlockBodyKzgCommitments, + pub blob_kzg_commitments: KzgCommitments, #[superstruct(only(Base, Altair))] #[ssz(skip_serializing, skip_deserializing)] #[tree_hash(skip_hashing)] diff --git a/consensus/types/src/blob_sidecar.rs b/consensus/types/src/blob_sidecar.rs index 043c3b6ee6d..a48c38421fa 100644 --- a/consensus/types/src/blob_sidecar.rs +++ b/consensus/types/src/blob_sidecar.rs @@ -233,5 +233,5 @@ pub type BlindedBlobSidecarList = SidecarList; pub type FixedBlobSidecarList = FixedVector>>, ::MaxBlobsPerBlock>; -pub type BlobsList = VariableList, ::MaxBlobsPerBlock>; -pub type BlobRootsList = VariableList::MaxBlobsPerBlock>; +pub type BlobsList = VariableList, ::MaxBlobCommitmentsPerBlock>; +pub type BlobRootsList = VariableList::MaxBlobCommitmentsPerBlock>; diff --git a/consensus/types/src/builder_bid.rs b/consensus/types/src/builder_bid.rs index cdd240716d4..4c266a9a3c0 100644 --- a/consensus/types/src/builder_bid.rs +++ b/consensus/types/src/builder_bid.rs @@ -1,4 +1,4 @@ -use crate::beacon_block_body::BuilderKzgCommitments; +use crate::beacon_block_body::KzgCommitments; use crate::{ BlobRootsList, ChainSpec, EthSpec, ExecutionPayloadHeaderCapella, ExecutionPayloadHeaderDeneb, ExecutionPayloadHeaderMerge, ExecutionPayloadHeaderRef, ForkName, ForkVersionDeserialize, @@ -15,7 +15,7 @@ use tree_hash_derive::TreeHash; #[derive(PartialEq, Debug, Default, Serialize, Deserialize, TreeHash, Clone, Encode)] #[serde(bound = "E: EthSpec")] pub struct BlindedBlobsBundle { - pub commitments: BuilderKzgCommitments, + pub commitments: KzgCommitments, pub proofs: KzgProofs, pub blob_roots: BlobRootsList, } diff --git a/consensus/types/src/lib.rs b/consensus/types/src/lib.rs index 9352c0b282a..26541a188c6 100644 --- a/consensus/types/src/lib.rs +++ b/consensus/types/src/lib.rs @@ -208,7 +208,7 @@ pub type Address = H160; pub type ForkVersion = [u8; 4]; pub type BLSFieldElement = Uint256; pub type Blob = FixedVector::BytesPerBlob>; -pub type KzgProofs = VariableList::MaxBlobsPerBlock>; +pub type KzgProofs = VariableList::MaxBlobCommitmentsPerBlock>; pub type VersionedHash = Hash256; pub type Hash64 = ethereum_types::H64; diff --git a/consensus/types/src/payload.rs b/consensus/types/src/payload.rs index f89e3259868..ff7caffcf3a 100644 --- a/consensus/types/src/payload.rs +++ b/consensus/types/src/payload.rs @@ -398,8 +398,13 @@ impl AbstractExecPayload for FullPayload { ForkName::Deneb => Ok(FullPayloadDeneb::default().into()), } } - fn default_blobs_at_fork(_fork_name: ForkName) -> Result, Error> { - Ok(VariableList::default()) + fn default_blobs_at_fork(fork_name: ForkName) -> Result, Error> { + match fork_name { + ForkName::Base | ForkName::Altair | ForkName::Merge | ForkName::Capella => { + Err(Error::IncorrectStateVariant) + } + ForkName::Deneb => Ok(VariableList::default()), + } } } @@ -916,8 +921,13 @@ impl AbstractExecPayload for BlindedPayload { ForkName::Deneb => Ok(BlindedPayloadDeneb::default().into()), } } - fn default_blobs_at_fork(_fork_name: ForkName) -> Result, Error> { - Ok(VariableList::default()) + fn default_blobs_at_fork(fork_name: ForkName) -> Result, Error> { + match fork_name { + ForkName::Base | ForkName::Altair | ForkName::Merge | ForkName::Capella => { + Err(Error::IncorrectStateVariant) + } + ForkName::Deneb => Ok(VariableList::default()), + } } } diff --git a/consensus/types/src/sidecar.rs b/consensus/types/src/sidecar.rs index 7feb85ce8fe..89e5e612873 100644 --- a/consensus/types/src/sidecar.rs +++ b/consensus/types/src/sidecar.rs @@ -1,4 +1,4 @@ -use crate::beacon_block_body::BuilderKzgCommitments; +use crate::beacon_block_body::KzgCommitments; use crate::test_utils::TestRandom; use crate::{ AbstractExecPayload, BeaconBlock, BlindedBlobSidecar, BlindedBlobSidecarList, BlobRootsList, @@ -33,7 +33,7 @@ pub trait Sidecar: fn build_sidecar>( blob_items: Self::BlobItems, block: &BeaconBlock, - expected_kzg_commitments: &BuilderKzgCommitments, + expected_kzg_commitments: &KzgCommitments, kzg_proofs: Vec, ) -> Result, String>; } @@ -106,7 +106,7 @@ impl Sidecar for BlobSidecar { fn build_sidecar>( blobs: BlobsList, block: &BeaconBlock, - expected_kzg_commitments: &BuilderKzgCommitments, + expected_kzg_commitments: &KzgCommitments, kzg_proofs: Vec, ) -> Result, String> { let beacon_block_root = block.canonical_root(); @@ -152,7 +152,7 @@ impl Sidecar for BlindedBlobSidecar { fn build_sidecar>( blob_roots: BlobRootsList, block: &BeaconBlock, - expected_kzg_commitments: &BuilderKzgCommitments, + expected_kzg_commitments: &KzgCommitments, kzg_proofs: Vec, ) -> Result, String> { let beacon_block_root = block.canonical_root(); diff --git a/scripts/local_testnet/README.md b/scripts/local_testnet/README.md index f261ea67fda..4f54154d1d2 100644 --- a/scripts/local_testnet/README.md +++ b/scripts/local_testnet/README.md @@ -128,3 +128,16 @@ Update the genesis time to now using: > Note: you probably want to just rerun `./start_local_testnet.sh` to start over > but this is another option. + +### Testing builder flow + +1. Add builder URL to `BN_ARGS` in `./var.env`, e.g. `--builder http://localhost:8650`. Some mock builder server options: + - [`mock-relay`](https://github.com/realbigsean/mock-relay) + - [`dummy-builder`](https://github.com/michaelsproul/dummy_builder) +2. (Optional) Add `--always-prefer-builder-payload` to `BN_ARGS`. +3. The above mock builders do not support non-mainnet presets as of now, and will require setting `SECONDS_PER_SLOT` and `SECONDS_PER_ETH1_BLOCK` to `12` in `./vars.env`. +4. Start the testnet with the following command (the `-p` flag enables the validator client `--builder-proposals` flag: + ```bash + ./start_local_testnet.sh -p genesis.json + ``` +5. Block production using builder flow will start at epoch 4. diff --git a/scripts/local_testnet/beacon_node.sh b/scripts/local_testnet/beacon_node.sh index 1a04d12d4a0..bbd52ae32d6 100755 --- a/scripts/local_testnet/beacon_node.sh +++ b/scripts/local_testnet/beacon_node.sh @@ -63,4 +63,5 @@ exec $lighthouse_binary \ --disable-packet-filter \ --target-peers $((BN_COUNT - 1)) \ --execution-endpoint $execution_endpoint \ - --execution-jwt $execution_jwt + --execution-jwt $execution_jwt \ + $BN_ARGS diff --git a/scripts/local_testnet/setup.sh b/scripts/local_testnet/setup.sh index 60a5c98bd03..7e000251a29 100755 --- a/scripts/local_testnet/setup.sh +++ b/scripts/local_testnet/setup.sh @@ -47,6 +47,6 @@ lcli \ insecure-validators \ --count $VALIDATOR_COUNT \ --base-dir $DATADIR \ - --node-count $BN_COUNT + --node-count $VC_COUNT echo Validators generated with keystore passwords at $DATADIR. diff --git a/scripts/local_testnet/vars.env b/scripts/local_testnet/vars.env index 9daf7d236a7..d04a2354979 100644 --- a/scripts/local_testnet/vars.env +++ b/scripts/local_testnet/vars.env @@ -61,5 +61,8 @@ SECONDS_PER_ETH1_BLOCK=1 # Proposer score boost percentage PROPOSER_SCORE_BOOST=40 +# Command line arguments for beacon node client +BN_ARGS="" + # Command line arguments for validator client VC_ARGS="" diff --git a/scripts/tests/vars.env b/scripts/tests/vars.env index 14707283c29..98ae08f0747 100644 --- a/scripts/tests/vars.env +++ b/scripts/tests/vars.env @@ -58,5 +58,8 @@ SECONDS_PER_ETH1_BLOCK=1 # Proposer score boost percentage PROPOSER_SCORE_BOOST=70 +# Command line arguments for beacon node client +BN_ARGS="" + # Enable doppelganger detection VC_ARGS=" --enable-doppelganger-protection " \ No newline at end of file