Skip to content
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions beacon_node/beacon_chain/src/beacon_chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6804,17 +6804,18 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
.enr_fork_id::<T::EthSpec>(slot, self.genesis_validators_root)
}

/// Calculates the `Duration` to the next fork if it exists and returns it
/// with it's corresponding `ForkName`.
pub fn duration_to_next_fork(&self) -> Option<(ForkName, Duration)> {
pub fn duration_to_next_digest(&self) -> Option<(Epoch, Duration)> {
// If we are unable to read the slot clock we assume that it is prior to genesis and
// therefore use the genesis slot.
let slot = self.slot().unwrap_or(self.spec.genesis_slot);
let epoch = slot.epoch(T::EthSpec::slots_per_epoch());

let next_digest_epoch = self.spec.next_digest_epoch(epoch)?;
let next_digest_slot = next_digest_epoch.start_slot(T::EthSpec::slots_per_epoch());

let (fork_name, epoch) = self.spec.next_fork_epoch::<T::EthSpec>(slot)?;
self.slot_clock
.duration_to_slot(epoch.start_slot(T::EthSpec::slots_per_epoch()))
.map(|duration| (fork_name, duration))
.duration_to_slot(next_digest_slot)
.map(|duration| (next_digest_epoch, duration))
}

/// This method serves to get a sense of the current chain health. It is used in block proposal
Expand Down
14 changes: 6 additions & 8 deletions beacon_node/http_api/src/light_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ use crate::version::{
};
use beacon_chain::{BeaconChain, BeaconChainError, BeaconChainTypes};
use eth2::types::{
self as api_types, ChainSpec, LightClientUpdate, LightClientUpdateResponseChunk,
self as api_types, LightClientUpdate, LightClientUpdateResponseChunk,
LightClientUpdateResponseChunkInner, LightClientUpdatesQuery,
};
use ssz::Encode;
use std::sync::Arc;
use types::{BeaconResponse, ForkName, Hash256, LightClientBootstrap};
use types::{BeaconResponse, EthSpec, ForkName, Hash256, LightClientBootstrap};
use warp::{
hyper::{Body, Response},
reply::Reply,
Expand Down Expand Up @@ -150,13 +150,11 @@ fn map_light_client_update_to_ssz_chunk<T: BeaconChainTypes>(
chain: &BeaconChain<T>,
light_client_update: &LightClientUpdate<T::EthSpec>,
) -> LightClientUpdateResponseChunk {
let fork_name = chain
.spec
.fork_name_at_slot::<T::EthSpec>(light_client_update.attested_header_slot());

let fork_digest = ChainSpec::compute_fork_digest(
chain.spec.fork_version_for_name(fork_name),
let fork_digest = chain.spec.compute_fork_digest(
chain.genesis_validators_root,
light_client_update
.attested_header_slot()
.epoch(T::EthSpec::slots_per_epoch()),
);

let payload = light_client_update.as_ssz_bytes();
Expand Down
24 changes: 22 additions & 2 deletions beacon_node/lighthouse_network/src/discovery/enr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ use super::enr_ext::{EnrExt, QUIC6_ENR_KEY, QUIC_ENR_KEY};

/// The ENR field specifying the fork id.
pub const ETH2_ENR_KEY: &str = "eth2";
/// The ENR field specifying the next fork digest.
pub const NEXT_FORK_DIGEST_ENR_KEY: &str = "nfd";
/// The ENR field specifying the attestation subnet bitfield.
pub const ATTESTATION_BITFIELD_ENR_KEY: &str = "attnets";
/// The ENR field specifying the sync committee subnet bitfield.
Expand All @@ -42,6 +44,9 @@ pub trait Eth2Enr {
/// The peerdas custody group count associated with the ENR.
fn custody_group_count<E: EthSpec>(&self, spec: &ChainSpec) -> Result<u64, &'static str>;

/// The next fork digest associated with the ENR.
fn next_fork_digest(&self) -> Result<[u8; 4], &'static str>;

fn eth2(&self) -> Result<EnrForkId, &'static str>;
}

Expand Down Expand Up @@ -81,6 +86,13 @@ impl Eth2Enr for Enr {
}
}

fn next_fork_digest(&self) -> Result<[u8; 4], &'static str> {
self
.get_decodable::<[u8; 4]>(NEXT_FORK_DIGEST_ENR_KEY)
.ok_or("ENR next fork digest non-existent")?
.map_err(|_| "Could not decode the ENR next fork digest")
}

fn eth2(&self) -> Result<EnrForkId, &'static str> {
let eth2_bytes: Bytes = self
.get_decodable(ETH2_ENR_KEY)
Expand Down Expand Up @@ -150,12 +162,13 @@ pub fn build_or_load_enr<E: EthSpec>(
config: &NetworkConfig,
enr_fork_id: &EnrForkId,
spec: &ChainSpec,
nfd: [u8; 4],
) -> Result<Enr, String> {
// Build the local ENR.
// Note: Discovery should update the ENR record's IP to the external IP as seen by the
// majority of our peers, if the CLI doesn't expressly forbid it.
let enr_key = CombinedKey::from_libp2p(local_key)?;
let mut local_enr = build_enr::<E>(&enr_key, config, enr_fork_id, spec)?;
let mut local_enr = build_enr::<E>(&enr_key, config, enr_fork_id, spec, nfd)?;

use_or_load_enr(&enr_key, &mut local_enr, config)?;
Ok(local_enr)
Expand All @@ -167,6 +180,7 @@ pub fn build_enr<E: EthSpec>(
config: &NetworkConfig,
enr_fork_id: &EnrForkId,
spec: &ChainSpec,
nfd: [u8; 4],
) -> Result<Enr, String> {
let mut builder = discv5::enr::Enr::builder();
let (maybe_ipv4_address, maybe_ipv6_address) = &config.enr_address;
Expand Down Expand Up @@ -270,6 +284,11 @@ pub fn build_enr<E: EthSpec>(
builder.add_value(PEERDAS_CUSTODY_GROUP_COUNT_ENR_KEY, &custody_group_count);
}

// only set `nfd` if peer das is scheduled
if spec.is_peer_das_scheduled() {
builder.add_value(NEXT_FORK_DIGEST_ENR_KEY, &nfd);
}

builder
.build(enr_key)
.map_err(|e| format!("Could not build Local ENR: {:?}", e))
Expand Down Expand Up @@ -351,7 +370,8 @@ mod test {
let keypair = libp2p::identity::secp256k1::Keypair::generate();
let enr_key = CombinedKey::from_secp256k1(&keypair);
let enr_fork_id = EnrForkId::default();
let enr = build_enr::<E>(&enr_key, &config, &enr_fork_id, spec).unwrap();
let nfd = [0; 4]; // placeholder
let enr = build_enr::<E>(&enr_key, &config, &enr_fork_id, spec, nfd).unwrap();
(enr, enr_key)
}

Expand Down
19 changes: 17 additions & 2 deletions beacon_node/lighthouse_network/src/discovery/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ use tracing::{debug, error, info, trace, warn};
use types::{ChainSpec, EnrForkId, EthSpec};

mod subnet_predicate;
use crate::discovery::enr::PEERDAS_CUSTODY_GROUP_COUNT_ENR_KEY;
use crate::discovery::enr::{NEXT_FORK_DIGEST_ENR_KEY, PEERDAS_CUSTODY_GROUP_COUNT_ENR_KEY};
pub use subnet_predicate::subnet_predicate;
use types::non_zero_usize::new_non_zero_usize;

Expand Down Expand Up @@ -570,6 +570,19 @@ impl<E: EthSpec> Discovery<E> {
Ok(())
}

pub fn update_enr_nfd(&mut self, nfd: [u8; 4]) -> Result<(), String> {
self.discv5
.enr_insert::<Bytes>(NEXT_FORK_DIGEST_ENR_KEY, &nfd.as_ssz_bytes().into())
.map_err(|e| format!("{:?}", e))?;
info!(
next_fork_digest = ?nfd,
"Updating the ENR nfd"
);
enr::save_enr_to_disk(Path::new(&self.enr_dir), &self.local_enr());
*self.network_globals.local_enr.write() = self.discv5.local_enr();
Ok(())
}

/// Updates the `eth2` field of our local ENR.
pub fn update_eth2_enr(&mut self, enr_fork_id: EnrForkId) {
// to avoid having a reference to the spec constant, for the logging we assume
Expand Down Expand Up @@ -1217,7 +1230,9 @@ mod tests {
config.set_listening_addr(crate::ListenAddress::unused_v4_ports());
let config = Arc::new(config);
let enr_key: CombinedKey = CombinedKey::from_secp256k1(&keypair);
let enr: Enr = build_enr::<E>(&enr_key, &config, &EnrForkId::default(), &spec).unwrap();
let nfd = [0; 4]; // placeholder
let enr: Enr =
build_enr::<E>(&enr_key, &config, &EnrForkId::default(), &spec, nfd).unwrap();
let globals = NetworkGlobals::new(
enr,
MetaData::V2(MetaDataV2 {
Expand Down
62 changes: 3 additions & 59 deletions beacon_node/lighthouse_network/src/rpc/codec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -469,65 +469,9 @@ fn context_bytes<E: EthSpec>(
// Add the context bytes if required
if protocol.has_context_bytes() {
if let RpcResponse::Success(rpc_variant) = resp {
match rpc_variant {
RpcSuccessResponse::BlocksByRange(ref_box_block)
| RpcSuccessResponse::BlocksByRoot(ref_box_block) => {
return match **ref_box_block {
// NOTE: If you are adding another fork type here, be sure to modify the
// `fork_context.to_context_bytes()` function to support it as well!
SignedBeaconBlock::Fulu { .. } => {
fork_context.to_context_bytes(ForkName::Fulu)
}
SignedBeaconBlock::Electra { .. } => {
fork_context.to_context_bytes(ForkName::Electra)
}
SignedBeaconBlock::Deneb { .. } => {
fork_context.to_context_bytes(ForkName::Deneb)
}
SignedBeaconBlock::Capella { .. } => {
fork_context.to_context_bytes(ForkName::Capella)
}
SignedBeaconBlock::Bellatrix { .. } => {
fork_context.to_context_bytes(ForkName::Bellatrix)
}
SignedBeaconBlock::Altair { .. } => {
fork_context.to_context_bytes(ForkName::Altair)
}
SignedBeaconBlock::Base { .. } => {
Some(fork_context.genesis_context_bytes())
}
};
}
RpcSuccessResponse::BlobsByRange(_) | RpcSuccessResponse::BlobsByRoot(_) => {
return fork_context.to_context_bytes(ForkName::Deneb);
}
RpcSuccessResponse::DataColumnsByRoot(_)
| RpcSuccessResponse::DataColumnsByRange(_) => {
return fork_context.to_context_bytes(ForkName::Fulu);
}
RpcSuccessResponse::LightClientBootstrap(lc_bootstrap) => {
return lc_bootstrap
.map_with_fork_name(|fork_name| fork_context.to_context_bytes(fork_name));
}
RpcSuccessResponse::LightClientOptimisticUpdate(lc_optimistic_update) => {
return lc_optimistic_update
.map_with_fork_name(|fork_name| fork_context.to_context_bytes(fork_name));
}
RpcSuccessResponse::LightClientFinalityUpdate(lc_finality_update) => {
return lc_finality_update
.map_with_fork_name(|fork_name| fork_context.to_context_bytes(fork_name));
}
RpcSuccessResponse::LightClientUpdatesByRange(lc_update) => {
return lc_update
.map_with_fork_name(|fork_name| fork_context.to_context_bytes(fork_name));
}
// These will not pass the has_context_bytes() check
RpcSuccessResponse::Status(_)
| RpcSuccessResponse::Pong(_)
| RpcSuccessResponse::MetaData(_) => {
return None;
}
}
return rpc_variant
.slot()
.map(|slot| fork_context.context_bytes(slot.epoch(E::slots_per_epoch())));
}
}
None
Expand Down
4 changes: 2 additions & 2 deletions beacon_node/lighthouse_network/src/rpc/handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -951,7 +951,7 @@ where
};

let max_responses =
req.max_responses(self.fork_context.current_fork(), &self.fork_context.spec);
req.max_responses(self.fork_context.digest_epoch(), &self.fork_context.spec);

// store requests that expect responses
if max_responses > 0 {
Expand Down Expand Up @@ -1022,7 +1022,7 @@ where

// add the stream to substreams if we expect a response, otherwise drop the stream.
let max_responses =
request.max_responses(self.fork_context.current_fork(), &self.fork_context.spec);
request.max_responses(self.fork_context.digest_epoch(), &self.fork_context.spec);
if max_responses > 0 {
let max_remaining_chunks = if request.expect_exactly_one_response() {
// Currently enforced only for multiple responses
Expand Down
17 changes: 17 additions & 0 deletions beacon_node/lighthouse_network/src/rpc/methods.rs
Original file line number Diff line number Diff line change
Expand Up @@ -749,6 +749,23 @@ impl<E: EthSpec> RpcSuccessResponse<E> {
RpcSuccessResponse::LightClientUpdatesByRange(_) => Protocol::LightClientUpdatesByRange,
}
}

pub fn slot(&self) -> Option<Slot> {
match self {
Self::BlocksByRange(r) | Self::BlocksByRoot(r) => Some(r.slot()),
Self::BlobsByRange(r) | Self::BlobsByRoot(r) => {
Some(r.signed_block_header.message.slot)
}
Self::DataColumnsByRange(r) | Self::DataColumnsByRoot(r) => {
Some(r.signed_block_header.message.slot)
}
Self::LightClientBootstrap(r) => Some(r.get_slot()),
Self::LightClientFinalityUpdate(r) => Some(r.get_attested_header_slot()),
Self::LightClientOptimisticUpdate(r) => Some(r.get_slot()),
Self::LightClientUpdatesByRange(r) => Some(r.attested_header_slot()),
Self::MetaData(_) | Self::Status(_) | Self::Pong(_) => None,
}
}
}

impl std::fmt::Display for RpcErrorResponse {
Expand Down
23 changes: 11 additions & 12 deletions beacon_node/lighthouse_network/src/rpc/protocol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ use tokio_util::{
};
use types::{
BeaconBlock, BeaconBlockAltair, BeaconBlockBase, BlobSidecar, ChainSpec, DataColumnSidecar,
EmptyBlock, EthSpec, EthSpecId, ForkContext, ForkName, LightClientBootstrap,
EmptyBlock, Epoch, EthSpec, EthSpecId, ForkContext, ForkName, LightClientBootstrap,
LightClientBootstrapAltair, LightClientFinalityUpdate, LightClientFinalityUpdateAltair,
LightClientOptimisticUpdate, LightClientOptimisticUpdateAltair, LightClientUpdate,
MainnetEthSpec, MinimalEthSpec, Signature, SignedBeaconBlock, Slot,
MainnetEthSpec, MinimalEthSpec, Signature, SignedBeaconBlock,
};

// Note: Hardcoding the `EthSpec` type for `SignedBeaconBlock` as min/max values is
Expand Down Expand Up @@ -550,10 +550,10 @@ impl ProtocolId {
Protocol::BlobsByRange => rpc_blob_limits::<E>(),
Protocol::BlobsByRoot => rpc_blob_limits::<E>(),
Protocol::DataColumnsByRoot => {
rpc_data_column_limits::<E>(fork_context.current_fork(), &fork_context.spec)
rpc_data_column_limits::<E>(fork_context.digest_epoch(), &fork_context.spec)
}
Protocol::DataColumnsByRange => {
rpc_data_column_limits::<E>(fork_context.current_fork(), &fork_context.spec)
rpc_data_column_limits::<E>(fork_context.digest_epoch(), &fork_context.spec)
}
Protocol::Ping => RpcLimits::new(
<Ping as Encode>::ssz_fixed_len(),
Expand Down Expand Up @@ -635,11 +635,13 @@ pub fn rpc_blob_limits<E: EthSpec>() -> RpcLimits {
}
}

pub fn rpc_data_column_limits<E: EthSpec>(fork_name: ForkName, spec: &ChainSpec) -> RpcLimits {
pub fn rpc_data_column_limits<E: EthSpec>(
current_digest_epoch: Epoch,
spec: &ChainSpec,
) -> RpcLimits {
RpcLimits::new(
DataColumnSidecar::<E>::min_size(),
// TODO(EIP-7892): fix this once we change fork-version on BPO forks
DataColumnSidecar::<E>::max_size(spec.max_blobs_per_block_within_fork(fork_name) as usize),
DataColumnSidecar::<E>::max_size(spec.max_blobs_per_block(current_digest_epoch) as usize),
)
}

Expand Down Expand Up @@ -738,16 +740,13 @@ impl<E: EthSpec> RequestType<E> {
/* These functions are used in the handler for stream management */

/// Maximum number of responses expected for this request.
/// TODO(EIP-7892): refactor this to remove `_current_fork`
pub fn max_responses(&self, _current_fork: ForkName, spec: &ChainSpec) -> u64 {
pub fn max_responses(&self, digest_epoch: Epoch, spec: &ChainSpec) -> u64 {
match self {
RequestType::Status(_) => 1,
RequestType::Goodbye(_) => 0,
RequestType::BlocksByRange(req) => *req.count(),
RequestType::BlocksByRoot(req) => req.block_roots().len() as u64,
RequestType::BlobsByRange(req) => {
req.max_blobs_requested(Slot::new(req.start_slot).epoch(E::slots_per_epoch()), spec)
}
RequestType::BlobsByRange(req) => req.max_blobs_requested(digest_epoch, spec),
RequestType::BlobsByRoot(req) => req.blob_ids.len() as u64,
RequestType::DataColumnsByRoot(req) => req.max_requested() as u64,
RequestType::DataColumnsByRange(req) => req.max_requested::<E>(),
Expand Down
12 changes: 6 additions & 6 deletions beacon_node/lighthouse_network/src/rpc/rate_limiter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use std::sync::Arc;
use std::task::{Context, Poll};
use std::time::{Duration, Instant};
use tokio::time::Interval;
use types::{ChainSpec, EthSpec, ForkContext, ForkName};
use types::{ChainSpec, Epoch, EthSpec, ForkContext};

/// Nanoseconds since a given time.
// Maintained as u64 to reduce footprint
Expand Down Expand Up @@ -267,16 +267,16 @@ impl RPCRateLimiterBuilder {

pub trait RateLimiterItem {
fn protocol(&self) -> Protocol;
fn max_responses(&self, current_fork: ForkName, spec: &ChainSpec) -> u64;
fn max_responses(&self, digest_epoch: Epoch, spec: &ChainSpec) -> u64;
}

impl<E: EthSpec> RateLimiterItem for super::RequestType<E> {
fn protocol(&self) -> Protocol {
self.versioned_protocol().protocol()
}

fn max_responses(&self, current_fork: ForkName, spec: &ChainSpec) -> u64 {
self.max_responses(current_fork, spec)
fn max_responses(&self, digest_epoch: Epoch, spec: &ChainSpec) -> u64 {
self.max_responses(digest_epoch, spec)
}
}

Expand All @@ -285,7 +285,7 @@ impl<E: EthSpec> RateLimiterItem for (super::RpcResponse<E>, Protocol) {
self.1
}

fn max_responses(&self, _current_fork: ForkName, _spec: &ChainSpec) -> u64 {
fn max_responses(&self, _digest_epoch: Epoch, _spec: &ChainSpec) -> u64 {
// A response chunk consumes one token of the rate limiter.
1
}
Expand Down Expand Up @@ -353,7 +353,7 @@ impl RPCRateLimiter {
) -> Result<(), RateLimitedErr> {
let time_since_start = self.init_time.elapsed();
let tokens = request
.max_responses(self.fork_context.current_fork(), &self.fork_context.spec)
.max_responses(self.fork_context.digest_epoch(), &self.fork_context.spec)
.max(1);

let check =
Expand Down
Loading
Loading