From 076f3f09843c52347bb04d5b3dc4364d1018c2e3 Mon Sep 17 00:00:00 2001 From: Pawan Dhananjay Date: Tue, 8 Apr 2025 19:50:45 -0700 Subject: [PATCH] Clarify network limits (#7175) Resolves #6811 Rename `GOSSIP_MAX_SIZE` to `MAX_PAYLOAD_SIZE` and remove `MAX_CHUNK_SIZE` in accordance with the spec. The spec also "clarifies" the message size limits at different levels. The rpc limits are equivalent to what we had before imo. The gossip limits have additional checks. I have gotten rid of the `is_bellatrix_enabled` checks that used a lower limit (1mb) pre-merge. Since all networks we run start from the merge, I don't think this will break any setups. --- beacon_node/lighthouse_network/src/config.rs | 19 +---- beacon_node/lighthouse_network/src/lib.rs | 1 - .../lighthouse_network/src/rpc/codec.rs | 34 ++++----- beacon_node/lighthouse_network/src/rpc/mod.rs | 8 +- .../lighthouse_network/src/rpc/protocol.rs | 11 +-- .../lighthouse_network/src/service/mod.rs | 8 +- .../lighthouse_network/src/types/pubsub.rs | 28 ++++--- .../lighthouse_network/tests/rpc_tests.rs | 18 ++--- beacon_node/src/config.rs | 5 +- .../chiado/config.yaml | 4 +- .../gnosis/config.yaml | 3 +- .../holesky/config.yaml | 4 +- .../hoodi/config.yaml | 4 +- .../mainnet/config.yaml | 4 +- .../sepolia/config.yaml | 4 +- consensus/types/src/chain_spec.rs | 76 +++++++++++++------ .../environment/tests/testnet_dir/config.yaml | 3 +- 17 files changed, 114 insertions(+), 120 deletions(-) diff --git a/beacon_node/lighthouse_network/src/config.rs b/beacon_node/lighthouse_network/src/config.rs index 5a6628439e..89d260569a 100644 --- a/beacon_node/lighthouse_network/src/config.rs +++ b/beacon_node/lighthouse_network/src/config.rs @@ -14,7 +14,7 @@ use std::num::NonZeroU16; use std::path::PathBuf; use std::sync::Arc; use std::time::Duration; -use types::{ForkContext, ForkName}; +use types::ForkContext; pub const DEFAULT_IPV4_ADDRESS: Ipv4Addr = Ipv4Addr::UNSPECIFIED; pub const DEFAULT_TCP_PORT: u16 = 9000u16; @@ -22,18 +22,9 @@ pub const DEFAULT_DISC_PORT: u16 = 9000u16; pub const DEFAULT_QUIC_PORT: u16 = 9001u16; pub const DEFAULT_IDONTWANT_MESSAGE_SIZE_THRESHOLD: usize = 1000usize; -/// The maximum size of gossip messages. -pub fn gossip_max_size(is_merge_enabled: bool, gossip_max_size: usize) -> usize { - if is_merge_enabled { - gossip_max_size - } else { - gossip_max_size / 10 - } -} - pub struct GossipsubConfigParams { pub message_domain_valid_snappy: [u8; 4], - pub gossip_max_size: usize, + pub gossipsub_max_transmit_size: usize, } #[derive(Clone, Debug, Serialize, Deserialize)] @@ -480,7 +471,6 @@ pub fn gossipsub_config( } } let message_domain_valid_snappy = gossipsub_config_params.message_domain_valid_snappy; - let is_bellatrix_enabled = fork_context.fork_exists(ForkName::Bellatrix); let gossip_message_id = move |message: &gossipsub::Message| { gossipsub::MessageId::from( &Sha256::digest( @@ -499,10 +489,7 @@ pub fn gossipsub_config( let duplicate_cache_time = Duration::from_secs(slots_per_epoch * seconds_per_slot * 2); gossipsub::ConfigBuilder::default() - .max_transmit_size(gossip_max_size( - is_bellatrix_enabled, - gossipsub_config_params.gossip_max_size, - )) + .max_transmit_size(gossipsub_config_params.gossipsub_max_transmit_size) .heartbeat_interval(load.heartbeat_interval) .mesh_n(load.mesh_n) .mesh_n_low(load.mesh_n_low) diff --git a/beacon_node/lighthouse_network/src/lib.rs b/beacon_node/lighthouse_network/src/lib.rs index 2f8fd82c51..98c61bd068 100644 --- a/beacon_node/lighthouse_network/src/lib.rs +++ b/beacon_node/lighthouse_network/src/lib.rs @@ -12,7 +12,6 @@ pub mod peer_manager; pub mod rpc; pub mod types; -pub use config::gossip_max_size; use libp2p::swarm::DialError; pub use listen_addr::*; diff --git a/beacon_node/lighthouse_network/src/rpc/codec.rs b/beacon_node/lighthouse_network/src/rpc/codec.rs index 838f1b8a16..b3239fa6cb 100644 --- a/beacon_node/lighthouse_network/src/rpc/codec.rs +++ b/beacon_node/lighthouse_network/src/rpc/codec.rs @@ -1002,10 +1002,7 @@ mod tests { } /// Bellatrix block with length < max_rpc_size. - fn bellatrix_block_small( - fork_context: &ForkContext, - spec: &ChainSpec, - ) -> SignedBeaconBlock { + fn bellatrix_block_small(spec: &ChainSpec) -> SignedBeaconBlock { let mut block: BeaconBlockBellatrix<_, FullPayload> = BeaconBlockBellatrix::empty(&Spec::default_spec()); let tx = VariableList::from(vec![0; 1024]); @@ -1014,17 +1011,14 @@ mod tests { block.body.execution_payload.execution_payload.transactions = txs; let block = BeaconBlock::Bellatrix(block); - assert!(block.ssz_bytes_len() <= max_rpc_size(fork_context, spec.max_chunk_size as usize)); + assert!(block.ssz_bytes_len() <= spec.max_payload_size as usize); SignedBeaconBlock::from_block(block, Signature::empty()) } /// Bellatrix block with length > MAX_RPC_SIZE. /// The max limit for a Bellatrix block is in the order of ~16GiB which wouldn't fit in memory. /// Hence, we generate a Bellatrix block just greater than `MAX_RPC_SIZE` to test rejection on the rpc layer. - fn bellatrix_block_large( - fork_context: &ForkContext, - spec: &ChainSpec, - ) -> SignedBeaconBlock { + fn bellatrix_block_large(spec: &ChainSpec) -> SignedBeaconBlock { let mut block: BeaconBlockBellatrix<_, FullPayload> = BeaconBlockBellatrix::empty(&Spec::default_spec()); let tx = VariableList::from(vec![0; 1024]); @@ -1033,7 +1027,7 @@ mod tests { block.body.execution_payload.execution_payload.transactions = txs; let block = BeaconBlock::Bellatrix(block); - assert!(block.ssz_bytes_len() > max_rpc_size(fork_context, spec.max_chunk_size as usize)); + assert!(block.ssz_bytes_len() > spec.max_payload_size as usize); SignedBeaconBlock::from_block(block, Signature::empty()) } @@ -1138,7 +1132,7 @@ mod tests { ) -> Result { let snappy_protocol_id = ProtocolId::new(protocol, Encoding::SSZSnappy); let fork_context = Arc::new(fork_context(fork_name)); - let max_packet_size = max_rpc_size(&fork_context, spec.max_chunk_size as usize); + let max_packet_size = spec.max_payload_size as usize; let mut buf = BytesMut::new(); let mut snappy_inbound_codec = @@ -1185,7 +1179,7 @@ mod tests { ) -> Result>, RPCError> { let snappy_protocol_id = ProtocolId::new(protocol, Encoding::SSZSnappy); let fork_context = Arc::new(fork_context(fork_name)); - let max_packet_size = max_rpc_size(&fork_context, spec.max_chunk_size as usize); + let max_packet_size = spec.max_payload_size as usize; let mut snappy_outbound_codec = SSZSnappyOutboundCodec::::new(snappy_protocol_id, max_packet_size, fork_context); // decode message just as snappy message @@ -1206,7 +1200,7 @@ mod tests { /// Verifies that requests we send are encoded in a way that we would correctly decode too. fn encode_then_decode_request(req: RequestType, fork_name: ForkName, spec: &ChainSpec) { let fork_context = Arc::new(fork_context(fork_name)); - let max_packet_size = max_rpc_size(&fork_context, spec.max_chunk_size as usize); + let max_packet_size = spec.max_payload_size as usize; let protocol = ProtocolId::new(req.versioned_protocol(), Encoding::SSZSnappy); // Encode a request we send let mut buf = BytesMut::new(); @@ -1583,10 +1577,8 @@ mod tests { )))) ); - let bellatrix_block_small = - bellatrix_block_small(&fork_context(ForkName::Bellatrix), &chain_spec); - let bellatrix_block_large = - bellatrix_block_large(&fork_context(ForkName::Bellatrix), &chain_spec); + let bellatrix_block_small = bellatrix_block_small(&chain_spec); + let bellatrix_block_large = bellatrix_block_large(&chain_spec); assert_eq!( encode_then_decode_response( @@ -2086,7 +2078,7 @@ mod tests { // Insert length-prefix uvi_codec - .encode(chain_spec.max_chunk_size as usize + 1, &mut dst) + .encode(chain_spec.max_payload_size as usize + 1, &mut dst) .unwrap(); // Insert snappy stream identifier @@ -2124,7 +2116,7 @@ mod tests { let mut snappy_outbound_codec = SSZSnappyOutboundCodec::::new( snappy_protocol_id, - max_rpc_size(&fork_context, chain_spec.max_chunk_size as usize), + chain_spec.max_payload_size as usize, fork_context, ); @@ -2160,7 +2152,7 @@ mod tests { let mut snappy_outbound_codec = SSZSnappyOutboundCodec::::new( snappy_protocol_id, - max_rpc_size(&fork_context, chain_spec.max_chunk_size as usize), + chain_spec.max_payload_size as usize, fork_context, ); @@ -2189,7 +2181,7 @@ mod tests { let chain_spec = Spec::default_spec(); - let max_rpc_size = max_rpc_size(&fork_context, chain_spec.max_chunk_size as usize); + let max_rpc_size = chain_spec.max_payload_size as usize; let limit = protocol_id.rpc_response_limits::(&fork_context); let mut max = encode_len(limit.max + 1); let mut codec = SSZSnappyOutboundCodec::::new( diff --git a/beacon_node/lighthouse_network/src/rpc/mod.rs b/beacon_node/lighthouse_network/src/rpc/mod.rs index 03f1395b8b..0e7686175a 100644 --- a/beacon_node/lighthouse_network/src/rpc/mod.rs +++ b/beacon_node/lighthouse_network/src/rpc/mod.rs @@ -33,7 +33,7 @@ pub use methods::{ BlocksByRangeRequest, BlocksByRootRequest, GoodbyeReason, LightClientBootstrapRequest, ResponseTermination, RpcErrorResponse, StatusMessage, }; -pub use protocol::{max_rpc_size, Protocol, RPCError}; +pub use protocol::{Protocol, RPCError}; use self::config::{InboundRateLimiterConfig, OutboundRateLimiterConfig}; use self::protocol::RPCProtocol; @@ -143,7 +143,7 @@ pub struct RPCMessage { type BehaviourAction = ToSwarm, RPCSend>; pub struct NetworkParams { - pub max_chunk_size: usize, + pub max_payload_size: usize, pub ttfb_timeout: Duration, pub resp_timeout: Duration, } @@ -284,7 +284,7 @@ where let protocol = SubstreamProtocol::new( RPCProtocol { fork_context: self.fork_context.clone(), - max_rpc_size: max_rpc_size(&self.fork_context, self.network_params.max_chunk_size), + max_rpc_size: self.fork_context.spec.max_payload_size as usize, enable_light_client_server: self.enable_light_client_server, phantom: PhantomData, ttfb_timeout: self.network_params.ttfb_timeout, @@ -315,7 +315,7 @@ where let protocol = SubstreamProtocol::new( RPCProtocol { fork_context: self.fork_context.clone(), - max_rpc_size: max_rpc_size(&self.fork_context, self.network_params.max_chunk_size), + max_rpc_size: self.fork_context.spec.max_payload_size as usize, enable_light_client_server: self.enable_light_client_server, phantom: PhantomData, ttfb_timeout: self.network_params.ttfb_timeout, diff --git a/beacon_node/lighthouse_network/src/rpc/protocol.rs b/beacon_node/lighthouse_network/src/rpc/protocol.rs index eac7d67490..8fc1e9a5f4 100644 --- a/beacon_node/lighthouse_network/src/rpc/protocol.rs +++ b/beacon_node/lighthouse_network/src/rpc/protocol.rs @@ -57,7 +57,7 @@ pub static SIGNED_BEACON_BLOCK_ALTAIR_MAX: LazyLock = LazyLock::new(|| { /// The `BeaconBlockBellatrix` block has an `ExecutionPayload` field which has a max size ~16 GiB for future proofing. /// We calculate the value from its fields instead of constructing the block and checking the length. /// Note: This is only the theoretical upper bound. We further bound the max size we receive over the network -/// with `max_chunk_size`. +/// with `max_payload_size`. pub static SIGNED_BEACON_BLOCK_BELLATRIX_MAX: LazyLock = LazyLock::new(|| // Size of a full altair block *SIGNED_BEACON_BLOCK_ALTAIR_MAX @@ -122,15 +122,6 @@ const PROTOCOL_PREFIX: &str = "/eth2/beacon_chain/req"; /// established before the stream is terminated. const REQUEST_TIMEOUT: u64 = 15; -/// Returns the maximum bytes that can be sent across the RPC. -pub fn max_rpc_size(fork_context: &ForkContext, max_chunk_size: usize) -> usize { - if fork_context.current_fork().bellatrix_enabled() { - max_chunk_size - } else { - max_chunk_size / 10 - } -} - /// Returns the rpc limits for beacon_block_by_range and beacon_block_by_root responses. /// /// Note: This function should take care to return the min/max limits accounting for all diff --git a/beacon_node/lighthouse_network/src/service/mod.rs b/beacon_node/lighthouse_network/src/service/mod.rs index 06d806ce0b..7fc7de3edd 100644 --- a/beacon_node/lighthouse_network/src/service/mod.rs +++ b/beacon_node/lighthouse_network/src/service/mod.rs @@ -224,7 +224,7 @@ impl Network { let gossipsub_config_params = GossipsubConfigParams { message_domain_valid_snappy: ctx.chain_spec.message_domain_valid_snappy, - gossip_max_size: ctx.chain_spec.gossip_max_size as usize, + gossipsub_max_transmit_size: ctx.chain_spec.max_message_size(), }; let gs_config = gossipsub_config( config.network_load, @@ -310,7 +310,9 @@ impl Network { ) }); - let snappy_transform = SnappyTransform::new(gs_config.max_transmit_size()); + let spec = &ctx.chain_spec; + let snappy_transform = + SnappyTransform::new(spec.max_payload_size as usize, spec.max_compressed_len()); let mut gossipsub = Gossipsub::new_with_subscription_filter_and_transform( MessageAuthenticity::Anonymous, gs_config.clone(), @@ -349,7 +351,7 @@ impl Network { }; let network_params = NetworkParams { - max_chunk_size: ctx.chain_spec.max_chunk_size as usize, + max_payload_size: ctx.chain_spec.max_payload_size as usize, ttfb_timeout: ctx.chain_spec.ttfb_timeout(), resp_timeout: ctx.chain_spec.resp_timeout(), }; diff --git a/beacon_node/lighthouse_network/src/types/pubsub.rs b/beacon_node/lighthouse_network/src/types/pubsub.rs index c199d2312b..880b387250 100644 --- a/beacon_node/lighthouse_network/src/types/pubsub.rs +++ b/beacon_node/lighthouse_network/src/types/pubsub.rs @@ -52,13 +52,16 @@ pub enum PubsubMessage { // Implements the `DataTransform` trait of gossipsub to employ snappy compression pub struct SnappyTransform { /// Sets the maximum size we allow gossipsub messages to decompress to. - max_size_per_message: usize, + max_uncompressed_len: usize, + /// Sets the maximum size we allow for compressed gossipsub message data. + max_compressed_len: usize, } impl SnappyTransform { - pub fn new(max_size_per_message: usize) -> Self { + pub fn new(max_uncompressed_len: usize, max_compressed_len: usize) -> Self { SnappyTransform { - max_size_per_message, + max_uncompressed_len, + max_compressed_len, } } } @@ -69,12 +72,19 @@ impl gossipsub::DataTransform for SnappyTransform { &self, raw_message: gossipsub::RawMessage, ) -> Result { - // check the length of the raw bytes - let len = decompress_len(&raw_message.data)?; - if len > self.max_size_per_message { + // first check the size of the compressed payload + if raw_message.data.len() > self.max_compressed_len { return Err(Error::new( ErrorKind::InvalidData, - "ssz_snappy decoded data > GOSSIP_MAX_SIZE", + "ssz_snappy encoded data > max_compressed_len", + )); + } + // check the length of the uncompressed bytes + let len = decompress_len(&raw_message.data)?; + if len > self.max_uncompressed_len { + return Err(Error::new( + ErrorKind::InvalidData, + "ssz_snappy decoded data > MAX_PAYLOAD_SIZE", )); } @@ -98,10 +108,10 @@ impl gossipsub::DataTransform for SnappyTransform { ) -> Result, std::io::Error> { // Currently we are not employing topic-based compression. Everything is expected to be // snappy compressed. - if data.len() > self.max_size_per_message { + if data.len() > self.max_uncompressed_len { return Err(Error::new( ErrorKind::InvalidData, - "ssz_snappy Encoded data > GOSSIP_MAX_SIZE", + "ssz_snappy Encoded data > MAX_PAYLOAD_SIZE", )); } let mut encoder = Encoder::new(); diff --git a/beacon_node/lighthouse_network/tests/rpc_tests.rs b/beacon_node/lighthouse_network/tests/rpc_tests.rs index 80364753d7..0d83c4f74e 100644 --- a/beacon_node/lighthouse_network/tests/rpc_tests.rs +++ b/beacon_node/lighthouse_network/tests/rpc_tests.rs @@ -5,7 +5,7 @@ mod common; use common::Protocol; use lighthouse_network::rpc::{methods::*, RequestType}; use lighthouse_network::service::api_types::AppRequestId; -use lighthouse_network::{rpc::max_rpc_size, NetworkEvent, ReportSource, Response}; +use lighthouse_network::{NetworkEvent, ReportSource, Response}; use slog::{debug, warn, Level}; use ssz::Encode; use ssz_types::VariableList; @@ -15,14 +15,14 @@ use tokio::runtime::Runtime; use tokio::time::sleep; use types::{ BeaconBlock, BeaconBlockAltair, BeaconBlockBase, BeaconBlockBellatrix, BlobSidecar, ChainSpec, - EmptyBlock, Epoch, EthSpec, FixedBytesExtended, ForkContext, ForkName, Hash256, MinimalEthSpec, + EmptyBlock, Epoch, EthSpec, FixedBytesExtended, ForkName, Hash256, MinimalEthSpec, RuntimeVariableList, Signature, SignedBeaconBlock, Slot, }; type E = MinimalEthSpec; /// Bellatrix block with length < max_rpc_size. -fn bellatrix_block_small(fork_context: &ForkContext, spec: &ChainSpec) -> BeaconBlock { +fn bellatrix_block_small(spec: &ChainSpec) -> BeaconBlock { let mut block = BeaconBlockBellatrix::::empty(spec); let tx = VariableList::from(vec![0; 1024]); let txs = VariableList::from(std::iter::repeat_n(tx, 5000).collect::>()); @@ -30,14 +30,14 @@ fn bellatrix_block_small(fork_context: &ForkContext, spec: &ChainSpec) -> Beacon block.body.execution_payload.execution_payload.transactions = txs; let block = BeaconBlock::Bellatrix(block); - assert!(block.ssz_bytes_len() <= max_rpc_size(fork_context, spec.max_chunk_size as usize)); + assert!(block.ssz_bytes_len() <= spec.max_payload_size as usize); block } /// Bellatrix block with length > MAX_RPC_SIZE. /// The max limit for a bellatrix block is in the order of ~16GiB which wouldn't fit in memory. /// Hence, we generate a bellatrix block just greater than `MAX_RPC_SIZE` to test rejection on the rpc layer. -fn bellatrix_block_large(fork_context: &ForkContext, spec: &ChainSpec) -> BeaconBlock { +fn bellatrix_block_large(spec: &ChainSpec) -> BeaconBlock { let mut block = BeaconBlockBellatrix::::empty(spec); let tx = VariableList::from(vec![0; 1024]); let txs = VariableList::from(std::iter::repeat_n(tx, 100000).collect::>()); @@ -45,7 +45,7 @@ fn bellatrix_block_large(fork_context: &ForkContext, spec: &ChainSpec) -> Beacon block.body.execution_payload.execution_payload.transactions = txs; let block = BeaconBlock::Bellatrix(block); - assert!(block.ssz_bytes_len() > max_rpc_size(fork_context, spec.max_chunk_size as usize)); + assert!(block.ssz_bytes_len() > spec.max_payload_size as usize); block } @@ -193,7 +193,7 @@ fn test_tcp_blocks_by_range_chunked_rpc() { let signed_full_block = SignedBeaconBlock::from_block(full_block, Signature::empty()); let rpc_response_altair = Response::BlocksByRange(Some(Arc::new(signed_full_block))); - let full_block = bellatrix_block_small(&common::fork_context(ForkName::Bellatrix), &spec); + let full_block = bellatrix_block_small(&spec); let signed_full_block = SignedBeaconBlock::from_block(full_block, Signature::empty()); let rpc_response_bellatrix_small = Response::BlocksByRange(Some(Arc::new(signed_full_block))); @@ -455,7 +455,7 @@ fn test_tcp_blocks_by_range_over_limit() { })); // BlocksByRange Response - let full_block = bellatrix_block_large(&common::fork_context(ForkName::Bellatrix), &spec); + let full_block = bellatrix_block_large(&spec); let signed_full_block = SignedBeaconBlock::from_block(full_block, Signature::empty()); let rpc_response_bellatrix_large = Response::BlocksByRange(Some(Arc::new(signed_full_block))); @@ -834,7 +834,7 @@ fn test_tcp_blocks_by_root_chunked_rpc() { let signed_full_block = SignedBeaconBlock::from_block(full_block, Signature::empty()); let rpc_response_altair = Response::BlocksByRoot(Some(Arc::new(signed_full_block))); - let full_block = bellatrix_block_small(&common::fork_context(ForkName::Bellatrix), &spec); + let full_block = bellatrix_block_small(&spec); let signed_full_block = SignedBeaconBlock::from_block(full_block, Signature::empty()); let rpc_response_bellatrix_small = Response::BlocksByRoot(Some(Arc::new(signed_full_block))); diff --git a/beacon_node/src/config.rs b/beacon_node/src/config.rs index cd92ee8fad..686843b000 100644 --- a/beacon_node/src/config.rs +++ b/beacon_node/src/config.rs @@ -675,10 +675,7 @@ pub fn get_config( }; } - client_config.chain.max_network_size = lighthouse_network::gossip_max_size( - spec.bellatrix_fork_epoch.is_some(), - spec.gossip_max_size as usize, - ); + client_config.chain.max_network_size = spec.max_payload_size as usize; if cli_args.get_flag("slasher") { let slasher_dir = if let Some(slasher_dir) = cli_args.get_one::("slasher-dir") { diff --git a/common/eth2_network_config/built_in_network_configs/chiado/config.yaml b/common/eth2_network_config/built_in_network_configs/chiado/config.yaml index 1455ec5f63..dbfe2707d7 100644 --- a/common/eth2_network_config/built_in_network_configs/chiado/config.yaml +++ b/common/eth2_network_config/built_in_network_configs/chiado/config.yaml @@ -100,15 +100,13 @@ DEPOSIT_CONTRACT_ADDRESS: 0xb97036A26259B7147018913bD58a774cf91acf25 # Networking # --------------------------------------------------------------- # `10 * 2**20` (= 10485760, 10 MiB) -GOSSIP_MAX_SIZE: 10485760 +MAX_PAYLOAD_SIZE: 10485760 # `2**10` (= 1024) MAX_REQUEST_BLOCKS: 1024 # `2**8` (= 256) EPOCHS_PER_SUBNET_SUBSCRIPTION: 256 # 33024, ~31 days MIN_EPOCHS_FOR_BLOCK_REQUESTS: 33024 -# `10 * 2**20` (=10485760, 10 MiB) -MAX_CHUNK_SIZE: 10485760 # 5s TTFB_TIMEOUT: 5 # 10s diff --git a/common/eth2_network_config/built_in_network_configs/gnosis/config.yaml b/common/eth2_network_config/built_in_network_configs/gnosis/config.yaml index 9ff5a16198..359d57b0a5 100644 --- a/common/eth2_network_config/built_in_network_configs/gnosis/config.yaml +++ b/common/eth2_network_config/built_in_network_configs/gnosis/config.yaml @@ -97,9 +97,8 @@ DEPOSIT_CONTRACT_ADDRESS: 0x0B98057eA310F4d31F2a452B414647007d1645d9 # Network # --------------------------------------------------------------- SUBNETS_PER_NODE: 4 -GOSSIP_MAX_SIZE: 10485760 +MAX_PAYLOAD_SIZE: 10485760 MIN_EPOCHS_FOR_BLOCK_REQUESTS: 33024 -MAX_CHUNK_SIZE: 10485760 TTFB_TIMEOUT: 5 RESP_TIMEOUT: 10 MESSAGE_DOMAIN_INVALID_SNAPPY: 0x00000000 diff --git a/common/eth2_network_config/built_in_network_configs/holesky/config.yaml b/common/eth2_network_config/built_in_network_configs/holesky/config.yaml index e5f38b8c9b..58010991bf 100644 --- a/common/eth2_network_config/built_in_network_configs/holesky/config.yaml +++ b/common/eth2_network_config/built_in_network_configs/holesky/config.yaml @@ -88,15 +88,13 @@ DEPOSIT_CONTRACT_ADDRESS: 0x4242424242424242424242424242424242424242 # Networking # --------------------------------------------------------------- # `10 * 2**20` (= 10485760, 10 MiB) -GOSSIP_MAX_SIZE: 10485760 +MAX_PAYLOAD_SIZE: 10485760 # `2**10` (= 1024) MAX_REQUEST_BLOCKS: 1024 # `2**8` (= 256) EPOCHS_PER_SUBNET_SUBSCRIPTION: 256 # `MIN_VALIDATOR_WITHDRAWABILITY_DELAY + CHURN_LIMIT_QUOTIENT // 2` (= 33024, ~5 months) MIN_EPOCHS_FOR_BLOCK_REQUESTS: 33024 -# `10 * 2**20` (=10485760, 10 MiB) -MAX_CHUNK_SIZE: 10485760 # 5s TTFB_TIMEOUT: 5 # 10s diff --git a/common/eth2_network_config/built_in_network_configs/hoodi/config.yaml b/common/eth2_network_config/built_in_network_configs/hoodi/config.yaml index 19d7797424..5cca1cd037 100644 --- a/common/eth2_network_config/built_in_network_configs/hoodi/config.yaml +++ b/common/eth2_network_config/built_in_network_configs/hoodi/config.yaml @@ -93,15 +93,13 @@ DEPOSIT_CONTRACT_ADDRESS: 0x00000000219ab540356cBB839Cbe05303d7705Fa # Networking # --------------------------------------------------------------- # `10 * 2**20` (= 10485760, 10 MiB) -GOSSIP_MAX_SIZE: 10485760 +MAX_PAYLOAD_SIZE: 10485760 # `2**10` (= 1024) MAX_REQUEST_BLOCKS: 1024 # `2**8` (= 256) EPOCHS_PER_SUBNET_SUBSCRIPTION: 256 # `MIN_VALIDATOR_WITHDRAWABILITY_DELAY + CHURN_LIMIT_QUOTIENT // 2` (= 33024, ~5 months) MIN_EPOCHS_FOR_BLOCK_REQUESTS: 33024 -# `10 * 2**20` (=10485760, 10 MiB) -MAX_CHUNK_SIZE: 10485760 # 5s TTFB_TIMEOUT: 5 # 10s diff --git a/common/eth2_network_config/built_in_network_configs/mainnet/config.yaml b/common/eth2_network_config/built_in_network_configs/mainnet/config.yaml index 3ff99b7171..375441e504 100644 --- a/common/eth2_network_config/built_in_network_configs/mainnet/config.yaml +++ b/common/eth2_network_config/built_in_network_configs/mainnet/config.yaml @@ -103,15 +103,13 @@ DEPOSIT_CONTRACT_ADDRESS: 0x00000000219ab540356cBB839Cbe05303d7705Fa # Networking # --------------------------------------------------------------- # `10 * 2**20` (= 10485760, 10 MiB) -GOSSIP_MAX_SIZE: 10485760 +MAX_PAYLOAD_SIZE: 10485760 # `2**10` (= 1024) MAX_REQUEST_BLOCKS: 1024 # `2**8` (= 256) EPOCHS_PER_SUBNET_SUBSCRIPTION: 256 # `MIN_VALIDATOR_WITHDRAWABILITY_DELAY + CHURN_LIMIT_QUOTIENT // 2` (= 33024, ~5 months) MIN_EPOCHS_FOR_BLOCK_REQUESTS: 33024 -# `10 * 2**20` (=10485760, 10 MiB) -MAX_CHUNK_SIZE: 10485760 # 5s TTFB_TIMEOUT: 5 # 10s diff --git a/common/eth2_network_config/built_in_network_configs/sepolia/config.yaml b/common/eth2_network_config/built_in_network_configs/sepolia/config.yaml index af78332205..e9e8a3ab14 100644 --- a/common/eth2_network_config/built_in_network_configs/sepolia/config.yaml +++ b/common/eth2_network_config/built_in_network_configs/sepolia/config.yaml @@ -89,15 +89,13 @@ DEPOSIT_CONTRACT_ADDRESS: 0x7f02C3E3c98b133055B8B348B2Ac625669Ed295D # Networking # --------------------------------------------------------------- # `10 * 2**20` (= 10485760, 10 MiB) -GOSSIP_MAX_SIZE: 10485760 +MAX_PAYLOAD_SIZE: 10485760 # `2**10` (= 1024) MAX_REQUEST_BLOCKS: 1024 # `2**8` (= 256) EPOCHS_PER_SUBNET_SUBSCRIPTION: 256 # `MIN_VALIDATOR_WITHDRAWABILITY_DELAY + CHURN_LIMIT_QUOTIENT // 2` (= 33024, ~5 months) MIN_EPOCHS_FOR_BLOCK_REQUESTS: 33024 -# `10 * 2**20` (=10485760, 10 MiB) -MAX_CHUNK_SIZE: 10485760 # 5s TTFB_TIMEOUT: 5 # 10s diff --git a/consensus/types/src/chain_spec.rs b/consensus/types/src/chain_spec.rs index 006c40a205..12602026e5 100644 --- a/consensus/types/src/chain_spec.rs +++ b/consensus/types/src/chain_spec.rs @@ -210,10 +210,9 @@ pub struct ChainSpec { pub boot_nodes: Vec, pub network_id: u8, pub target_aggregators_per_committee: u64, - pub gossip_max_size: u64, + pub max_payload_size: u64, max_request_blocks: u64, pub min_epochs_for_block_requests: u64, - pub max_chunk_size: u64, pub ttfb_timeout: u64, pub resp_timeout: u64, pub attestation_propagation_slot_range: u64, @@ -712,6 +711,35 @@ impl ChainSpec { } } + /// Worst-case compressed length for a given payload of size n when using snappy. + /// + /// https://github.com/google/snappy/blob/32ded457c0b1fe78ceb8397632c416568d6714a0/snappy.cc#L218C1-L218C47 + /// https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/p2p-interface.md#max_compressed_len + fn max_compressed_len_snappy(n: usize) -> Option { + 32_usize.checked_add(n)?.checked_add(n / 6) + } + + /// Max compressed length of a message that we receive over gossip. + pub fn max_compressed_len(&self) -> usize { + Self::max_compressed_len_snappy(self.max_payload_size as usize) + .expect("should not overflow") + } + + /// Max allowed size of a raw, compressed message received over the network. + /// + /// https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/p2p-interface.md#max_compressed_len + pub fn max_message_size(&self) -> usize { + std::cmp::max( + // 1024 to account for framing + encoding overhead + Self::max_compressed_len_snappy(self.max_payload_size as usize) + .expect("should not overflow") + .safe_add(1024) + .expect("should not overflow"), + //1MB + 1024 * 1024, + ) + } + /// Returns a `ChainSpec` compatible with the Ethereum Foundation specification. pub fn mainnet() -> Self { Self { @@ -926,9 +954,8 @@ impl ChainSpec { subnets_per_node: 2, maximum_gossip_clock_disparity_millis: default_maximum_gossip_clock_disparity_millis(), target_aggregators_per_committee: 16, - gossip_max_size: default_gossip_max_size(), + max_payload_size: default_max_payload_size(), min_epochs_for_block_requests: default_min_epochs_for_block_requests(), - max_chunk_size: default_max_chunk_size(), ttfb_timeout: default_ttfb_timeout(), resp_timeout: default_resp_timeout(), message_domain_invalid_snappy: default_message_domain_invalid_snappy(), @@ -1256,9 +1283,8 @@ impl ChainSpec { subnets_per_node: 4, // Make this larger than usual to avoid network damage maximum_gossip_clock_disparity_millis: default_maximum_gossip_clock_disparity_millis(), target_aggregators_per_committee: 16, - gossip_max_size: default_gossip_max_size(), + max_payload_size: default_max_payload_size(), min_epochs_for_block_requests: 33024, - max_chunk_size: default_max_chunk_size(), ttfb_timeout: default_ttfb_timeout(), resp_timeout: default_resp_timeout(), message_domain_invalid_snappy: default_message_domain_invalid_snappy(), @@ -1430,18 +1456,15 @@ pub struct Config { #[serde(with = "serde_utils::quoted_u64")] gas_limit_adjustment_factor: u64, - #[serde(default = "default_gossip_max_size")] + #[serde(default = "default_max_payload_size")] #[serde(with = "serde_utils::quoted_u64")] - gossip_max_size: u64, + max_payload_size: u64, #[serde(default = "default_max_request_blocks")] #[serde(with = "serde_utils::quoted_u64")] max_request_blocks: u64, #[serde(default = "default_min_epochs_for_block_requests")] #[serde(with = "serde_utils::quoted_u64")] min_epochs_for_block_requests: u64, - #[serde(default = "default_max_chunk_size")] - #[serde(with = "serde_utils::quoted_u64")] - max_chunk_size: u64, #[serde(default = "default_ttfb_timeout")] #[serde(with = "serde_utils::quoted_u64")] ttfb_timeout: u64, @@ -1576,7 +1599,7 @@ const fn default_gas_limit_adjustment_factor() -> u64 { 1024 } -const fn default_gossip_max_size() -> u64 { +const fn default_max_payload_size() -> u64 { 10485760 } @@ -1584,10 +1607,6 @@ const fn default_min_epochs_for_block_requests() -> u64 { 33024 } -const fn default_max_chunk_size() -> u64 { - 10485760 -} - const fn default_ttfb_timeout() -> u64 { 5 } @@ -1853,10 +1872,9 @@ impl Config { gas_limit_adjustment_factor: spec.gas_limit_adjustment_factor, - gossip_max_size: spec.gossip_max_size, + max_payload_size: spec.max_payload_size, max_request_blocks: spec.max_request_blocks, min_epochs_for_block_requests: spec.min_epochs_for_block_requests, - max_chunk_size: spec.max_chunk_size, ttfb_timeout: spec.ttfb_timeout, resp_timeout: spec.resp_timeout, attestation_propagation_slot_range: spec.attestation_propagation_slot_range, @@ -1934,9 +1952,8 @@ impl Config { deposit_network_id, deposit_contract_address, gas_limit_adjustment_factor, - gossip_max_size, + max_payload_size, min_epochs_for_block_requests, - max_chunk_size, ttfb_timeout, resp_timeout, message_domain_invalid_snappy, @@ -2005,9 +2022,8 @@ impl Config { terminal_total_difficulty, terminal_block_hash, terminal_block_hash_activation_epoch, - gossip_max_size, + max_payload_size, min_epochs_for_block_requests, - max_chunk_size, ttfb_timeout, resp_timeout, message_domain_invalid_snappy, @@ -2307,9 +2323,8 @@ mod yaml_tests { check_default!(terminal_block_hash); check_default!(terminal_block_hash_activation_epoch); check_default!(bellatrix_fork_version); - check_default!(gossip_max_size); + check_default!(max_payload_size); check_default!(min_epochs_for_block_requests); - check_default!(max_chunk_size); check_default!(ttfb_timeout); check_default!(resp_timeout); check_default!(message_domain_invalid_snappy); @@ -2335,4 +2350,17 @@ mod yaml_tests { [0, 0, 0, 1] ); } + + #[test] + fn test_max_network_limits_overflow() { + let mut spec = MainnetEthSpec::default_spec(); + // Should not overflow + let _ = spec.max_message_size(); + let _ = spec.max_compressed_len(); + + spec.max_payload_size *= 10; + // Should not overflow even with a 10x increase in max + let _ = spec.max_message_size(); + let _ = spec.max_compressed_len(); + } } diff --git a/lighthouse/environment/tests/testnet_dir/config.yaml b/lighthouse/environment/tests/testnet_dir/config.yaml index 34e42a61f6..3f72e2ea6c 100644 --- a/lighthouse/environment/tests/testnet_dir/config.yaml +++ b/lighthouse/environment/tests/testnet_dir/config.yaml @@ -87,9 +87,8 @@ DEPOSIT_CONTRACT_ADDRESS: 0x00000000219ab540356cBB839Cbe05303d7705Fa # Network # --------------------------------------------------------------- SUBNETS_PER_NODE: 2 -GOSSIP_MAX_SIZE: 10485760 +MAX_PAYLOAD_SIZE: 10485760 MIN_EPOCHS_FOR_BLOCK_REQUESTS: 33024 -MAX_CHUNK_SIZE: 10485760 TTFB_TIMEOUT: 5 RESP_TIMEOUT: 10 MESSAGE_DOMAIN_INVALID_SNAPPY: 0x00000000