mirror of
https://github.com/sigp/lighthouse.git
synced 2026-05-31 13:17:09 +00:00
Resolve merge conflicts
This commit is contained in:
@@ -1,8 +1,9 @@
|
||||
use crate::rpc::methods::{ResponseTermination, RpcResponse, RpcSuccessResponse, StatusMessage};
|
||||
use libp2p::PeerId;
|
||||
use std::fmt::{Display, Formatter};
|
||||
use std::sync::Arc;
|
||||
use types::{
|
||||
BlobSidecar, DataColumnSidecar, Epoch, EthSpec, Hash256, LightClientBootstrap,
|
||||
BlobSidecar, DataColumnSidecar, Epoch, EthSpec, LightClientBootstrap,
|
||||
LightClientFinalityUpdate, LightClientOptimisticUpdate, LightClientUpdate, SignedBeaconBlock,
|
||||
};
|
||||
|
||||
@@ -59,8 +60,19 @@ pub struct BlobsByRangeRequestId {
|
||||
pub struct DataColumnsByRangeRequestId {
|
||||
/// Id to identify this attempt at a data_columns_by_range request for `parent_request_id`
|
||||
pub id: Id,
|
||||
/// The Id of the overall By Range request for block components.
|
||||
pub parent_request_id: ComponentsByRangeRequestId,
|
||||
/// The Id of the overall By Range request for either a components by range request or a custody backfill request.
|
||||
pub parent_request_id: DataColumnsByRangeRequester,
|
||||
/// The peer id associated with the request.
|
||||
///
|
||||
/// This is useful to penalize the peer at a later point if it returned data columns that
|
||||
/// did not match with the verified block.
|
||||
pub peer: PeerId,
|
||||
}
|
||||
|
||||
#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
|
||||
pub enum DataColumnsByRangeRequester {
|
||||
ComponentsByRange(ComponentsByRangeRequestId),
|
||||
CustodyBackfillSync(CustodyBackFillBatchRequestId),
|
||||
}
|
||||
|
||||
/// Block components by range request for range sync. Includes an ID for downstream consumers to
|
||||
@@ -74,6 +86,24 @@ pub struct ComponentsByRangeRequestId {
|
||||
pub requester: RangeRequestId,
|
||||
}
|
||||
|
||||
/// A batch of data columns by range request for custody sync. Includes an ID for downstream consumers to
|
||||
/// handle retries and tie all the range requests for the given epoch together.
|
||||
#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
|
||||
pub struct CustodyBackFillBatchRequestId {
|
||||
/// For each `epoch` we may request the same data in a later retry. This Id identifies the
|
||||
/// current attempt.
|
||||
pub id: Id,
|
||||
pub batch_id: CustodyBackfillBatchId,
|
||||
}
|
||||
|
||||
/// Custody backfill may be restarted and sync each epoch multiple times in different runs. Identify
|
||||
/// each batch by epoch and run_id for uniqueness.
|
||||
#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
|
||||
pub struct CustodyBackfillBatchId {
|
||||
pub epoch: Epoch,
|
||||
pub run_id: u64,
|
||||
}
|
||||
|
||||
/// Range sync chain or backfill batch
|
||||
#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
|
||||
pub enum RangeRequestId {
|
||||
@@ -81,9 +111,10 @@ pub enum RangeRequestId {
|
||||
BackfillSync { batch_id: Epoch },
|
||||
}
|
||||
|
||||
// TODO(das) refactor in a separate PR. We might be able to remove this and replace
|
||||
// [`DataColumnsByRootRequestId`] with a [`SingleLookupReqId`].
|
||||
#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
|
||||
pub enum DataColumnsByRootRequester {
|
||||
Sampling(SamplingId),
|
||||
Custody(CustodyId),
|
||||
}
|
||||
|
||||
@@ -93,21 +124,6 @@ pub enum RangeRequester {
|
||||
BackfillSync { batch_id: Epoch },
|
||||
}
|
||||
|
||||
#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
|
||||
pub struct SamplingId {
|
||||
pub id: SamplingRequester,
|
||||
pub sampling_request_id: SamplingRequestId,
|
||||
}
|
||||
|
||||
#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
|
||||
pub enum SamplingRequester {
|
||||
ImportedBlock(Hash256),
|
||||
}
|
||||
|
||||
/// Identifier of sampling requests.
|
||||
#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
|
||||
pub struct SamplingRequestId(pub usize);
|
||||
|
||||
#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
|
||||
pub struct CustodyId {
|
||||
pub requester: CustodyRequester,
|
||||
@@ -225,13 +241,13 @@ impl_display!(ComponentsByRangeRequestId, "{}/{}", id, requester);
|
||||
impl_display!(DataColumnsByRootRequestId, "{}/{}", id, requester);
|
||||
impl_display!(SingleLookupReqId, "{}/Lookup/{}", req_id, lookup_id);
|
||||
impl_display!(CustodyId, "{}", requester);
|
||||
impl_display!(SamplingId, "{}/{}", sampling_request_id, id);
|
||||
impl_display!(CustodyBackFillBatchRequestId, "{}/{}", id, batch_id);
|
||||
impl_display!(CustodyBackfillBatchId, "{}/{}", epoch, run_id);
|
||||
|
||||
impl Display for DataColumnsByRootRequester {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::Custody(id) => write!(f, "Custody/{id}"),
|
||||
Self::Sampling(id) => write!(f, "Sampling/{id}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -251,16 +267,11 @@ impl Display for RangeRequestId {
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for SamplingRequestId {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for SamplingRequester {
|
||||
impl Display for DataColumnsByRangeRequester {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::ImportedBlock(block) => write!(f, "ImportedBlock/{block}"),
|
||||
Self::ComponentsByRange(id) => write!(f, "ByRange/{id}"),
|
||||
Self::CustodyBackfillSync(id) => write!(f, "CustodyBackfill/{id}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -283,30 +294,21 @@ mod tests {
|
||||
assert_eq!(format!("{id}"), "123/Custody/121/Lookup/101");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn display_id_data_columns_by_root_sampling() {
|
||||
let id = DataColumnsByRootRequestId {
|
||||
id: 123,
|
||||
requester: DataColumnsByRootRequester::Sampling(SamplingId {
|
||||
id: SamplingRequester::ImportedBlock(Hash256::ZERO),
|
||||
sampling_request_id: SamplingRequestId(101),
|
||||
}),
|
||||
};
|
||||
assert_eq!(format!("{id}"), "123/Sampling/101/ImportedBlock/0x0000000000000000000000000000000000000000000000000000000000000000");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn display_id_data_columns_by_range() {
|
||||
let id = DataColumnsByRangeRequestId {
|
||||
id: 123,
|
||||
parent_request_id: ComponentsByRangeRequestId {
|
||||
id: 122,
|
||||
requester: RangeRequestId::RangeSync {
|
||||
chain_id: 54,
|
||||
batch_id: Epoch::new(0),
|
||||
parent_request_id: DataColumnsByRangeRequester::ComponentsByRange(
|
||||
ComponentsByRangeRequestId {
|
||||
id: 122,
|
||||
requester: RangeRequestId::RangeSync {
|
||||
chain_id: 54,
|
||||
batch_id: Epoch::new(0),
|
||||
},
|
||||
},
|
||||
},
|
||||
),
|
||||
peer: PeerId::random(),
|
||||
};
|
||||
assert_eq!(format!("{id}"), "123/122/RangeSync/0/54");
|
||||
assert_eq!(format!("{id}"), "123/ByRange/122/RangeSync/0/54");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::collections::HashMap;
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
use std::time::Duration;
|
||||
|
||||
use crate::types::GossipKind;
|
||||
use crate::GossipTopic;
|
||||
use crate::types::GossipKind;
|
||||
|
||||
use tokio_util::time::delay_queue::{DelayQueue, Key};
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::types::{GossipEncoding, GossipKind, GossipTopic};
|
||||
use crate::TopicHash;
|
||||
use crate::types::{GossipEncoding, GossipKind, GossipTopic};
|
||||
use gossipsub::{IdentTopic as Topic, PeerScoreParams, PeerScoreThresholds, TopicScoreParams};
|
||||
use std::cmp::max;
|
||||
use std::collections::HashMap;
|
||||
|
||||
@@ -1,50 +1,50 @@
|
||||
use self::gossip_cache::GossipCache;
|
||||
use crate::config::{gossipsub_config, GossipsubConfigParams, NetworkLoad};
|
||||
use crate::Eth2Enr;
|
||||
use crate::config::{GossipsubConfigParams, NetworkLoad, gossipsub_config};
|
||||
use crate::discovery::{
|
||||
subnet_predicate, DiscoveredPeers, Discovery, FIND_NODE_QUERY_CLOSEST_PEERS,
|
||||
DiscoveredPeers, Discovery, FIND_NODE_QUERY_CLOSEST_PEERS, subnet_predicate,
|
||||
};
|
||||
use crate::peer_manager::{
|
||||
config::Config as PeerManagerCfg, peerdb::score::PeerAction, peerdb::score::ReportSource,
|
||||
ConnectionDirection, PeerManager, PeerManagerEvent,
|
||||
ConnectionDirection, PeerManager, PeerManagerEvent, config::Config as PeerManagerCfg,
|
||||
peerdb::score::PeerAction, peerdb::score::ReportSource,
|
||||
};
|
||||
use crate::peer_manager::{MIN_OUTBOUND_ONLY_FACTOR, PEER_EXCESS_FACTOR, PRIORITY_PEER_EXCESS};
|
||||
use crate::rpc::methods::MetadataRequest;
|
||||
use crate::rpc::{
|
||||
GoodbyeReason, HandlerErr, InboundRequestId, NetworkParams, Protocol, RPCError, RPCMessage,
|
||||
RPCReceived, RequestType, ResponseTermination, RpcErrorResponse, RpcResponse,
|
||||
RpcSuccessResponse, RPC,
|
||||
GoodbyeReason, HandlerErr, InboundRequestId, Protocol, RPC, RPCError, RPCMessage, RPCReceived,
|
||||
RequestType, ResponseTermination, RpcResponse, RpcSuccessResponse,
|
||||
};
|
||||
use crate::types::{
|
||||
all_topics_at_fork, core_topics_to_subscribe, is_fork_non_core_topic, subnet_from_topic_hash,
|
||||
GossipEncoding, GossipKind, GossipTopic, SnappyTransform, Subnet, SubnetDiscovery,
|
||||
all_topics_at_fork, core_topics_to_subscribe, is_fork_non_core_topic, subnet_from_topic_hash,
|
||||
};
|
||||
use crate::EnrExt;
|
||||
use crate::Eth2Enr;
|
||||
use crate::{metrics, Enr, NetworkGlobals, PubsubMessage, TopicHash};
|
||||
use crate::{Enr, NetworkGlobals, PubsubMessage, TopicHash, metrics};
|
||||
use api_types::{AppRequestId, Response};
|
||||
use futures::stream::StreamExt;
|
||||
use gossipsub::{
|
||||
IdentTopic as Topic, MessageAcceptance, MessageAuthenticity, MessageId, PublishError,
|
||||
TopicScoreParams,
|
||||
};
|
||||
use gossipsub_scoring_parameters::{lighthouse_gossip_thresholds, PeerScoreSettings};
|
||||
use gossipsub_scoring_parameters::{PeerScoreSettings, lighthouse_gossip_thresholds};
|
||||
use libp2p::identity::Keypair;
|
||||
use libp2p::multiaddr::{self, Multiaddr, Protocol as MProtocol};
|
||||
use libp2p::swarm::behaviour::toggle::Toggle;
|
||||
use libp2p::swarm::{NetworkBehaviour, Swarm, SwarmEvent};
|
||||
use libp2p::upnp::tokio::Behaviour as Upnp;
|
||||
use libp2p::{identify, PeerId, SwarmBuilder};
|
||||
use libp2p::{PeerId, SwarmBuilder, identify};
|
||||
use logging::crit;
|
||||
use network_utils::enr_ext::EnrExt;
|
||||
use std::num::{NonZeroU8, NonZeroUsize};
|
||||
use std::path::PathBuf;
|
||||
use std::pin::Pin;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use tracing::{debug, info, instrument, trace, warn};
|
||||
use types::{
|
||||
consts::altair::SYNC_COMMITTEE_SUBNET_COUNT, EnrForkId, EthSpec, ForkContext, Slot, SubnetId,
|
||||
};
|
||||
use tracing::{debug, error, info, trace, warn};
|
||||
use types::{ChainSpec, ForkName};
|
||||
use utils::{build_transport, strip_peer_id, Context as ServiceContext};
|
||||
use types::{
|
||||
EnrForkId, EthSpec, ForkContext, Slot, SubnetId, consts::altair::SYNC_COMMITTEE_SUBNET_COUNT,
|
||||
};
|
||||
use utils::{Context as ServiceContext, build_transport, strip_peer_id};
|
||||
|
||||
pub mod api_types;
|
||||
mod gossip_cache;
|
||||
@@ -168,20 +168,14 @@ pub struct Network<E: EthSpec> {
|
||||
|
||||
/// Implements the combined behaviour for the libp2p service.
|
||||
impl<E: EthSpec> Network<E> {
|
||||
#[instrument(parent = None,
|
||||
level = "trace",
|
||||
fields(service = "libp2p"),
|
||||
name = "libp2p",
|
||||
skip_all
|
||||
)]
|
||||
pub async fn new(
|
||||
executor: task_executor::TaskExecutor,
|
||||
mut ctx: ServiceContext<'_>,
|
||||
custody_group_count: u64,
|
||||
local_keypair: Keypair,
|
||||
) -> Result<(Self, Arc<NetworkGlobals<E>>), String> {
|
||||
let config = ctx.config.clone();
|
||||
trace!("Libp2p Service starting");
|
||||
// initialise the node's ID
|
||||
let local_keypair = utils::load_private_key(&config);
|
||||
|
||||
// Trusted peers will also be marked as explicit in GossipSub.
|
||||
// Cfr. https://github.com/libp2p/specs/blob/master/pubsub/gossipsub/gossipsub-v1.1.md#explicit-peering-agreements
|
||||
@@ -193,19 +187,26 @@ impl<E: EthSpec> Network<E> {
|
||||
|
||||
// set up a collection of variables accessible outside of the network crate
|
||||
// Create an ENR or load from disk if appropriate
|
||||
let next_fork_digest = ctx
|
||||
.fork_context
|
||||
.next_fork_digest()
|
||||
.unwrap_or_else(|| ctx.fork_context.current_fork_digest());
|
||||
|
||||
let advertised_cgc = config
|
||||
.advertise_false_custody_group_count
|
||||
.unwrap_or(custody_group_count);
|
||||
let enr = crate::discovery::enr::build_or_load_enr::<E>(
|
||||
local_keypair.clone(),
|
||||
&config,
|
||||
&ctx.enr_fork_id,
|
||||
advertised_cgc,
|
||||
next_fork_digest,
|
||||
&ctx.chain_spec,
|
||||
)?;
|
||||
|
||||
// Construct the metadata
|
||||
let custody_group_count = ctx.chain_spec.is_peer_das_scheduled().then(|| {
|
||||
ctx.chain_spec
|
||||
.custody_group_count(config.subscribe_all_data_column_subnets)
|
||||
});
|
||||
let meta_data = utils::load_or_build_metadata(&config.network_dir, custody_group_count);
|
||||
|
||||
let meta_data = utils::load_or_build_metadata(&config.network_dir, advertised_cgc);
|
||||
let seq_number = *meta_data.seq_number();
|
||||
let globals = NetworkGlobals::new(
|
||||
enr,
|
||||
@@ -281,27 +282,26 @@ impl<E: EthSpec> Network<E> {
|
||||
// Set up a scoring update interval
|
||||
let update_gossipsub_scores = tokio::time::interval(params.decay_interval);
|
||||
|
||||
let current_and_future_forks = ForkName::list_all().into_iter().filter_map(|fork| {
|
||||
if fork >= ctx.fork_context.current_fork() {
|
||||
ctx.fork_context
|
||||
.to_context_bytes(fork)
|
||||
.map(|fork_digest| (fork, fork_digest))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
let current_digest_epoch = ctx.fork_context.current_fork_epoch();
|
||||
let current_and_future_digests =
|
||||
ctx.chain_spec
|
||||
.all_digest_epochs()
|
||||
.filter_map(|digest_epoch| {
|
||||
if digest_epoch >= current_digest_epoch {
|
||||
Some((digest_epoch, ctx.fork_context.context_bytes(digest_epoch)))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
|
||||
let all_topics_for_forks = current_and_future_forks
|
||||
.map(|(fork, fork_digest)| {
|
||||
let all_topics_for_digests = current_and_future_digests
|
||||
.map(|(epoch, digest)| {
|
||||
let fork = ctx.chain_spec.fork_name_at_epoch(epoch);
|
||||
all_topics_at_fork::<E>(fork, &ctx.chain_spec)
|
||||
.into_iter()
|
||||
.map(|topic| {
|
||||
Topic::new(GossipTopic::new(
|
||||
topic,
|
||||
GossipEncoding::default(),
|
||||
fork_digest,
|
||||
))
|
||||
.into()
|
||||
Topic::new(GossipTopic::new(topic, GossipEncoding::default(), digest))
|
||||
.into()
|
||||
})
|
||||
.collect::<Vec<TopicHash>>()
|
||||
})
|
||||
@@ -309,7 +309,7 @@ impl<E: EthSpec> Network<E> {
|
||||
|
||||
// For simplicity find the fork with the most individual topics and assume all forks
|
||||
// have the same topic count
|
||||
let max_topics_at_any_fork = all_topics_for_forks
|
||||
let max_topics_at_any_fork = all_topics_for_digests
|
||||
.iter()
|
||||
.map(|topics| topics.len())
|
||||
.max()
|
||||
@@ -328,26 +328,25 @@ impl<E: EthSpec> Network<E> {
|
||||
max_subscriptions_per_request: max_topics_at_any_fork * 2,
|
||||
};
|
||||
|
||||
// If metrics are enabled for libp2p build the configuration
|
||||
let gossipsub_metrics = ctx.libp2p_registry.as_mut().map(|registry| {
|
||||
(
|
||||
registry.sub_registry_with_prefix("gossipsub"),
|
||||
Default::default(),
|
||||
)
|
||||
});
|
||||
|
||||
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(),
|
||||
gossipsub_metrics,
|
||||
filter,
|
||||
snappy_transform,
|
||||
)
|
||||
.map_err(|e| format!("Could not construct gossipsub: {:?}", e))?;
|
||||
|
||||
// If metrics are enabled for libp2p build the configuration
|
||||
if let Some(ref mut registry) = ctx.libp2p_registry {
|
||||
gossipsub = gossipsub.with_metrics(
|
||||
registry.sub_registry_with_prefix("gossipsub"),
|
||||
Default::default(),
|
||||
);
|
||||
}
|
||||
|
||||
gossipsub
|
||||
.with_peer_score(params, thresholds)
|
||||
.expect("Valid score params and thresholds");
|
||||
@@ -360,7 +359,7 @@ impl<E: EthSpec> Network<E> {
|
||||
// If we are using metrics, then register which topics we want to make sure to keep
|
||||
// track of
|
||||
if ctx.libp2p_registry.is_some() {
|
||||
for topics in all_topics_for_forks {
|
||||
for topics in all_topics_for_digests {
|
||||
gossipsub.register_topics_for_metrics(topics);
|
||||
}
|
||||
}
|
||||
@@ -368,17 +367,11 @@ impl<E: EthSpec> Network<E> {
|
||||
(gossipsub, update_gossipsub_scores)
|
||||
};
|
||||
|
||||
let network_params = NetworkParams {
|
||||
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(),
|
||||
};
|
||||
let eth2_rpc = RPC::new(
|
||||
ctx.fork_context.clone(),
|
||||
config.enable_light_client_server,
|
||||
config.inbound_rate_limiter_config.clone(),
|
||||
config.outbound_rate_limiter_config.clone(),
|
||||
network_params,
|
||||
seq_number,
|
||||
);
|
||||
|
||||
@@ -529,12 +522,6 @@ impl<E: EthSpec> Network<E> {
|
||||
/// - Starts listening in the given ports.
|
||||
/// - Dials boot-nodes and libp2p peers.
|
||||
/// - Subscribes to starting gossipsub topics.
|
||||
#[instrument(parent = None,
|
||||
level = "trace",
|
||||
fields(service = "libp2p"),
|
||||
name = "libp2p",
|
||||
skip_all
|
||||
)]
|
||||
async fn start(&mut self, config: &crate::NetworkConfig) -> Result<(), String> {
|
||||
let enr = self.network_globals.local_enr();
|
||||
info!(
|
||||
@@ -658,114 +645,48 @@ impl<E: EthSpec> Network<E> {
|
||||
/* Public Accessible Functions to interact with the behaviour */
|
||||
|
||||
/// The routing pub-sub mechanism for eth2.
|
||||
#[instrument(parent = None,
|
||||
level = "trace",
|
||||
fields(service = "libp2p"),
|
||||
name = "libp2p",
|
||||
skip_all
|
||||
)]
|
||||
pub fn gossipsub_mut(&mut self) -> &mut Gossipsub {
|
||||
&mut self.swarm.behaviour_mut().gossipsub
|
||||
}
|
||||
/// The Eth2 RPC specified in the wire-0 protocol.
|
||||
#[instrument(parent = None,
|
||||
level = "trace",
|
||||
fields(service = "libp2p"),
|
||||
name = "libp2p",
|
||||
skip_all
|
||||
)]
|
||||
pub fn eth2_rpc_mut(&mut self) -> &mut RPC<AppRequestId, E> {
|
||||
&mut self.swarm.behaviour_mut().eth2_rpc
|
||||
}
|
||||
/// Discv5 Discovery protocol.
|
||||
#[instrument(parent = None,
|
||||
level = "trace",
|
||||
fields(service = "libp2p"),
|
||||
name = "libp2p",
|
||||
skip_all
|
||||
)]
|
||||
pub fn discovery_mut(&mut self) -> &mut Discovery<E> {
|
||||
&mut self.swarm.behaviour_mut().discovery
|
||||
}
|
||||
/// Provides IP addresses and peer information.
|
||||
#[instrument(parent = None,
|
||||
level = "trace",
|
||||
fields(service = "libp2p"),
|
||||
name = "libp2p",
|
||||
skip_all
|
||||
)]
|
||||
pub fn identify_mut(&mut self) -> &mut identify::Behaviour {
|
||||
&mut self.swarm.behaviour_mut().identify
|
||||
}
|
||||
/// The peer manager that keeps track of peer's reputation and status.
|
||||
#[instrument(parent = None,
|
||||
level = "trace",
|
||||
fields(service = "libp2p"),
|
||||
name = "libp2p",
|
||||
skip_all
|
||||
)]
|
||||
pub fn peer_manager_mut(&mut self) -> &mut PeerManager<E> {
|
||||
&mut self.swarm.behaviour_mut().peer_manager
|
||||
}
|
||||
|
||||
/// The routing pub-sub mechanism for eth2.
|
||||
#[instrument(parent = None,
|
||||
level = "trace",
|
||||
fields(service = "libp2p"),
|
||||
name = "libp2p",
|
||||
skip_all
|
||||
)]
|
||||
pub fn gossipsub(&self) -> &Gossipsub {
|
||||
&self.swarm.behaviour().gossipsub
|
||||
}
|
||||
/// The Eth2 RPC specified in the wire-0 protocol.
|
||||
#[instrument(parent = None,
|
||||
level = "trace",
|
||||
fields(service = "libp2p"),
|
||||
name = "libp2p",
|
||||
skip_all
|
||||
)]
|
||||
pub fn eth2_rpc(&self) -> &RPC<AppRequestId, E> {
|
||||
&self.swarm.behaviour().eth2_rpc
|
||||
}
|
||||
/// Discv5 Discovery protocol.
|
||||
#[instrument(parent = None,
|
||||
level = "trace",
|
||||
fields(service = "libp2p"),
|
||||
name = "libp2p",
|
||||
skip_all
|
||||
)]
|
||||
pub fn discovery(&self) -> &Discovery<E> {
|
||||
&self.swarm.behaviour().discovery
|
||||
}
|
||||
/// Provides IP addresses and peer information.
|
||||
#[instrument(parent = None,
|
||||
level = "trace",
|
||||
fields(service = "libp2p"),
|
||||
name = "libp2p",
|
||||
skip_all
|
||||
)]
|
||||
pub fn identify(&self) -> &identify::Behaviour {
|
||||
&self.swarm.behaviour().identify
|
||||
}
|
||||
/// The peer manager that keeps track of peer's reputation and status.
|
||||
#[instrument(parent = None,
|
||||
level = "trace",
|
||||
fields(service = "libp2p"),
|
||||
name = "libp2p",
|
||||
skip_all
|
||||
)]
|
||||
pub fn peer_manager(&self) -> &PeerManager<E> {
|
||||
&self.swarm.behaviour().peer_manager
|
||||
}
|
||||
|
||||
/// Returns the local ENR of the node.
|
||||
#[instrument(parent = None,
|
||||
level = "trace",
|
||||
fields(service = "libp2p"),
|
||||
name = "libp2p",
|
||||
skip_all
|
||||
)]
|
||||
pub fn local_enr(&self) -> Enr {
|
||||
self.network_globals.local_enr()
|
||||
}
|
||||
@@ -774,12 +695,6 @@ impl<E: EthSpec> Network<E> {
|
||||
|
||||
/// Subscribes to a gossipsub topic kind, letting the network service determine the
|
||||
/// encoding and fork version.
|
||||
#[instrument(parent = None,
|
||||
level = "trace",
|
||||
fields(service = "libp2p"),
|
||||
name = "libp2p",
|
||||
skip_all
|
||||
)]
|
||||
pub fn subscribe_kind(&mut self, kind: GossipKind) -> bool {
|
||||
let gossip_topic = GossipTopic::new(
|
||||
kind,
|
||||
@@ -792,12 +707,6 @@ impl<E: EthSpec> Network<E> {
|
||||
|
||||
/// Unsubscribes from a gossipsub topic kind, letting the network service determine the
|
||||
/// encoding and fork version.
|
||||
#[instrument(parent = None,
|
||||
level = "trace",
|
||||
fields(service = "libp2p"),
|
||||
name = "libp2p",
|
||||
skip_all
|
||||
)]
|
||||
pub fn unsubscribe_kind(&mut self, kind: GossipKind) -> bool {
|
||||
let gossip_topic = GossipTopic::new(
|
||||
kind,
|
||||
@@ -808,12 +717,6 @@ impl<E: EthSpec> Network<E> {
|
||||
}
|
||||
|
||||
/// Subscribe to all required topics for the `new_fork` with the given `new_fork_digest`.
|
||||
#[instrument(parent = None,
|
||||
level = "trace",
|
||||
fields(service = "libp2p"),
|
||||
name = "libp2p",
|
||||
skip_all
|
||||
)]
|
||||
pub fn subscribe_new_fork_topics(&mut self, new_fork: ForkName, new_fork_digest: [u8; 4]) {
|
||||
// Re-subscribe to non-core topics with the new fork digest
|
||||
let subscriptions = self.network_globals.gossipsub_subscriptions.read().clone();
|
||||
@@ -838,12 +741,6 @@ impl<E: EthSpec> Network<E> {
|
||||
}
|
||||
|
||||
/// Unsubscribe from all topics that doesn't have the given fork_digest
|
||||
#[instrument(parent = None,
|
||||
level = "trace",
|
||||
fields(service = "libp2p"),
|
||||
name = "libp2p",
|
||||
skip_all
|
||||
)]
|
||||
pub fn unsubscribe_from_fork_topics_except(&mut self, except: [u8; 4]) {
|
||||
let subscriptions = self.network_globals.gossipsub_subscriptions.read().clone();
|
||||
for topic in subscriptions
|
||||
@@ -856,12 +753,6 @@ impl<E: EthSpec> Network<E> {
|
||||
}
|
||||
|
||||
/// Remove topic weight from all topics that don't have the given fork digest.
|
||||
#[instrument(parent = None,
|
||||
level = "trace",
|
||||
fields(service = "libp2p"),
|
||||
name = "libp2p",
|
||||
skip_all
|
||||
)]
|
||||
pub fn remove_topic_weight_except(&mut self, except: [u8; 4]) {
|
||||
let new_param = TopicScoreParams {
|
||||
topic_weight: 0.0,
|
||||
@@ -885,13 +776,18 @@ impl<E: EthSpec> Network<E> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Subscribe to all data columns determined by the cgc.
|
||||
pub fn subscribe_new_data_column_subnets(&mut self, sampling_column_count: u64) {
|
||||
self.network_globals
|
||||
.update_data_column_subnets(sampling_column_count);
|
||||
|
||||
for column in self.network_globals.sampling_subnets() {
|
||||
let kind = GossipKind::DataColumnSidecar(column);
|
||||
self.subscribe_kind(kind);
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the scoring parameters for a topic if set.
|
||||
#[instrument(parent = None,
|
||||
level = "trace",
|
||||
fields(service = "libp2p"),
|
||||
name = "libp2p",
|
||||
skip_all
|
||||
)]
|
||||
pub fn get_topic_params(&self, topic: GossipTopic) -> Option<&TopicScoreParams> {
|
||||
self.swarm
|
||||
.behaviour()
|
||||
@@ -902,12 +798,6 @@ impl<E: EthSpec> Network<E> {
|
||||
/// Subscribes to a gossipsub topic.
|
||||
///
|
||||
/// Returns `true` if the subscription was successful and `false` otherwise.
|
||||
#[instrument(parent = None,
|
||||
level = "trace",
|
||||
fields(service = "libp2p"),
|
||||
name = "libp2p",
|
||||
skip_all
|
||||
)]
|
||||
pub fn subscribe(&mut self, topic: GossipTopic) -> bool {
|
||||
// update the network globals
|
||||
self.network_globals
|
||||
@@ -930,12 +820,6 @@ impl<E: EthSpec> Network<E> {
|
||||
}
|
||||
|
||||
/// Unsubscribe from a gossipsub topic.
|
||||
#[instrument(parent = None,
|
||||
level = "trace",
|
||||
fields(service = "libp2p"),
|
||||
name = "libp2p",
|
||||
skip_all
|
||||
)]
|
||||
pub fn unsubscribe(&mut self, topic: GossipTopic) -> bool {
|
||||
// update the network globals
|
||||
self.network_globals
|
||||
@@ -951,12 +835,6 @@ impl<E: EthSpec> Network<E> {
|
||||
}
|
||||
|
||||
/// Publishes a list of messages on the pubsub (gossipsub) behaviour, choosing the encoding.
|
||||
#[instrument(parent = None,
|
||||
level = "trace",
|
||||
fields(service = "libp2p"),
|
||||
name = "libp2p",
|
||||
skip_all
|
||||
)]
|
||||
pub fn publish(&mut self, messages: Vec<PubsubMessage<E>>) {
|
||||
for message in messages {
|
||||
for topic in message.topics(GossipEncoding::default(), self.enr_fork_id.fork_digest) {
|
||||
@@ -1011,12 +889,6 @@ impl<E: EthSpec> Network<E> {
|
||||
|
||||
/// Informs the gossipsub about the result of a message validation.
|
||||
/// If the message is valid it will get propagated by gossipsub.
|
||||
#[instrument(parent = None,
|
||||
level = "trace",
|
||||
fields(service = "libp2p"),
|
||||
name = "libp2p",
|
||||
skip_all
|
||||
)]
|
||||
pub fn report_message_validation_result(
|
||||
&mut self,
|
||||
propagation_source: &PeerId,
|
||||
@@ -1027,19 +899,17 @@ impl<E: EthSpec> Network<E> {
|
||||
MessageAcceptance::Accept => None,
|
||||
MessageAcceptance::Ignore => Some("ignore"),
|
||||
MessageAcceptance::Reject => Some("reject"),
|
||||
} {
|
||||
if let Some(client) = self
|
||||
.network_globals
|
||||
.peers
|
||||
.read()
|
||||
.peer_info(propagation_source)
|
||||
.map(|info| info.client().kind.as_ref())
|
||||
{
|
||||
metrics::inc_counter_vec(
|
||||
&metrics::GOSSIP_UNACCEPTED_MESSAGES_PER_CLIENT,
|
||||
&[client, result],
|
||||
)
|
||||
}
|
||||
} && let Some(client) = self
|
||||
.network_globals
|
||||
.peers
|
||||
.read()
|
||||
.peer_info(propagation_source)
|
||||
.map(|info| info.client().kind.as_ref())
|
||||
{
|
||||
metrics::inc_counter_vec(
|
||||
&metrics::GOSSIP_UNACCEPTED_MESSAGES_PER_CLIENT,
|
||||
&[client, result],
|
||||
)
|
||||
}
|
||||
|
||||
self.gossipsub_mut().report_message_validation_result(
|
||||
@@ -1051,12 +921,6 @@ impl<E: EthSpec> Network<E> {
|
||||
|
||||
/// Updates the current gossipsub scoring parameters based on the validator count and current
|
||||
/// slot.
|
||||
#[instrument(parent = None,
|
||||
level = "trace",
|
||||
fields(service = "libp2p"),
|
||||
name = "libp2p",
|
||||
skip_all
|
||||
)]
|
||||
pub fn update_gossipsub_parameters(
|
||||
&mut self,
|
||||
active_validators: usize,
|
||||
@@ -1100,12 +964,7 @@ impl<E: EthSpec> Network<E> {
|
||||
/* Eth2 RPC behaviour functions */
|
||||
|
||||
/// Send a request to a peer over RPC.
|
||||
#[instrument(parent = None,
|
||||
level = "trace",
|
||||
fields(service = "libp2p"),
|
||||
name = "libp2p",
|
||||
skip_all
|
||||
)]
|
||||
#[allow(clippy::result_large_err)]
|
||||
pub fn send_request(
|
||||
&mut self,
|
||||
peer_id: PeerId,
|
||||
@@ -1123,60 +982,28 @@ impl<E: EthSpec> Network<E> {
|
||||
}
|
||||
|
||||
/// Send a successful response to a peer over RPC.
|
||||
#[instrument(parent = None,
|
||||
level = "trace",
|
||||
fields(service = "libp2p"),
|
||||
name = "libp2p",
|
||||
skip_all
|
||||
)]
|
||||
pub fn send_response(
|
||||
pub fn send_response<T: Into<RpcResponse<E>>>(
|
||||
&mut self,
|
||||
peer_id: PeerId,
|
||||
inbound_request_id: InboundRequestId,
|
||||
response: Response<E>,
|
||||
response: T,
|
||||
) {
|
||||
self.eth2_rpc_mut()
|
||||
.send_response(peer_id, inbound_request_id, response.into())
|
||||
}
|
||||
|
||||
/// Inform the peer that their request produced an error.
|
||||
#[instrument(parent = None,
|
||||
level = "trace",
|
||||
fields(service = "libp2p"),
|
||||
name = "libp2p",
|
||||
skip_all
|
||||
)]
|
||||
pub fn send_error_response(
|
||||
&mut self,
|
||||
peer_id: PeerId,
|
||||
inbound_request_id: InboundRequestId,
|
||||
error: RpcErrorResponse,
|
||||
reason: String,
|
||||
) {
|
||||
self.eth2_rpc_mut().send_response(
|
||||
peer_id,
|
||||
inbound_request_id,
|
||||
RpcResponse::Error(error, reason.into()),
|
||||
)
|
||||
if let Err(response) = self
|
||||
.eth2_rpc_mut()
|
||||
.send_response(inbound_request_id, response.into())
|
||||
&& self.network_globals.peers.read().is_connected(&peer_id)
|
||||
{
|
||||
error!(%peer_id, ?inbound_request_id, %response,
|
||||
"Request not found in RPC active requests"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/* Peer management functions */
|
||||
#[instrument(parent = None,
|
||||
level = "trace",
|
||||
fields(service = "libp2p"),
|
||||
name = "libp2p",
|
||||
skip_all
|
||||
)]
|
||||
pub fn testing_dial(&mut self, addr: Multiaddr) -> Result<(), libp2p::swarm::DialError> {
|
||||
self.swarm.dial(addr)
|
||||
}
|
||||
|
||||
#[instrument(parent = None,
|
||||
level = "trace",
|
||||
fields(service = "libp2p"),
|
||||
name = "libp2p",
|
||||
skip_all
|
||||
)]
|
||||
pub fn report_peer(
|
||||
&mut self,
|
||||
peer_id: &PeerId,
|
||||
@@ -1192,12 +1019,6 @@ impl<E: EthSpec> Network<E> {
|
||||
///
|
||||
/// This will send a goodbye, disconnect and then ban the peer.
|
||||
/// This is fatal for a peer, and should be used in unrecoverable circumstances.
|
||||
#[instrument(parent = None,
|
||||
level = "trace",
|
||||
fields(service = "libp2p"),
|
||||
name = "libp2p",
|
||||
skip_all
|
||||
)]
|
||||
pub fn goodbye_peer(&mut self, peer_id: &PeerId, reason: GoodbyeReason, source: ReportSource) {
|
||||
self.peer_manager_mut()
|
||||
.goodbye_peer(peer_id, reason, source);
|
||||
@@ -1205,34 +1026,16 @@ impl<E: EthSpec> Network<E> {
|
||||
|
||||
/// Hard (ungraceful) disconnect for testing purposes only
|
||||
/// Use goodbye_peer for disconnections, do not use this function.
|
||||
#[instrument(parent = None,
|
||||
level = "trace",
|
||||
fields(service = "libp2p"),
|
||||
name = "libp2p",
|
||||
skip_all
|
||||
)]
|
||||
pub fn __hard_disconnect_testing_only(&mut self, peer_id: PeerId) {
|
||||
let _ = self.swarm.disconnect_peer_id(peer_id);
|
||||
}
|
||||
|
||||
/// Returns an iterator over all enr entries in the DHT.
|
||||
#[instrument(parent = None,
|
||||
level = "trace",
|
||||
fields(service = "libp2p"),
|
||||
name = "libp2p",
|
||||
skip_all
|
||||
)]
|
||||
pub fn enr_entries(&self) -> Vec<Enr> {
|
||||
self.discovery().table_entries_enr()
|
||||
}
|
||||
|
||||
/// Add an ENR to the routing table of the discovery mechanism.
|
||||
#[instrument(parent = None,
|
||||
level = "trace",
|
||||
fields(service = "libp2p"),
|
||||
name = "libp2p",
|
||||
skip_all
|
||||
)]
|
||||
pub fn add_enr(&mut self, enr: Enr) {
|
||||
self.discovery_mut().add_enr(enr);
|
||||
}
|
||||
@@ -1240,12 +1043,6 @@ impl<E: EthSpec> Network<E> {
|
||||
/// Updates a subnet value to the ENR attnets/syncnets bitfield.
|
||||
///
|
||||
/// The `value` is `true` if a subnet is being added and false otherwise.
|
||||
#[instrument(parent = None,
|
||||
level = "trace",
|
||||
fields(service = "libp2p"),
|
||||
name = "libp2p",
|
||||
skip_all
|
||||
)]
|
||||
pub fn update_enr_subnet(&mut self, subnet_id: Subnet, value: bool) {
|
||||
if let Err(e) = self.discovery_mut().update_enr_bitfield(subnet_id, value) {
|
||||
crit!(error = e, "Could not update ENR bitfield");
|
||||
@@ -1254,14 +1051,17 @@ impl<E: EthSpec> Network<E> {
|
||||
self.update_metadata_bitfields();
|
||||
}
|
||||
|
||||
/// Updates the cgc value in the ENR.
|
||||
pub fn update_enr_cgc(&mut self, new_custody_group_count: u64) {
|
||||
if let Err(e) = self.discovery_mut().update_enr_cgc(new_custody_group_count) {
|
||||
crit!(error = e, "Could not update cgc in ENR");
|
||||
}
|
||||
// update the local meta data which informs our peers of the update during PINGS
|
||||
self.update_metadata_cgc(new_custody_group_count);
|
||||
}
|
||||
|
||||
/// Attempts to discover new peers for a given subnet. The `min_ttl` gives the time at which we
|
||||
/// would like to retain the peers for.
|
||||
#[instrument(parent = None,
|
||||
level = "trace",
|
||||
fields(service = "libp2p"),
|
||||
name = "libp2p",
|
||||
skip_all
|
||||
)]
|
||||
pub fn discover_subnet_peers(&mut self, subnets_to_discover: Vec<SubnetDiscovery>) {
|
||||
// If discovery is not started or disabled, ignore the request
|
||||
if !self.discovery().started {
|
||||
@@ -1316,12 +1116,6 @@ impl<E: EthSpec> Network<E> {
|
||||
}
|
||||
|
||||
/// Updates the local ENR's "eth2" field with the latest EnrForkId.
|
||||
#[instrument(parent = None,
|
||||
level = "trace",
|
||||
fields(service = "libp2p"),
|
||||
name = "libp2p",
|
||||
skip_all
|
||||
)]
|
||||
pub fn update_fork_version(&mut self, enr_fork_id: EnrForkId) {
|
||||
self.discovery_mut().update_eth2_enr(enr_fork_id.clone());
|
||||
|
||||
@@ -1329,15 +1123,15 @@ impl<E: EthSpec> Network<E> {
|
||||
self.enr_fork_id = enr_fork_id;
|
||||
}
|
||||
|
||||
pub fn update_nfd(&mut self, nfd: [u8; 4]) {
|
||||
if let Err(e) = self.discovery_mut().update_enr_nfd(nfd) {
|
||||
crit!(error = e, "Could not update nfd in ENR");
|
||||
}
|
||||
}
|
||||
|
||||
/* Private internal functions */
|
||||
|
||||
/// Updates the current meta data of the node to match the local ENR.
|
||||
#[instrument(parent = None,
|
||||
level = "trace",
|
||||
fields(service = "libp2p"),
|
||||
name = "libp2p",
|
||||
skip_all
|
||||
)]
|
||||
fn update_metadata_bitfields(&mut self) {
|
||||
let local_attnets = self
|
||||
.discovery_mut()
|
||||
@@ -1368,24 +1162,28 @@ impl<E: EthSpec> Network<E> {
|
||||
utils::save_metadata_to_disk(&self.network_dir, meta_data);
|
||||
}
|
||||
|
||||
fn update_metadata_cgc(&mut self, custody_group_count: u64) {
|
||||
let mut meta_data_w = self.network_globals.local_metadata.write();
|
||||
|
||||
*meta_data_w.seq_number_mut() += 1;
|
||||
if let Ok(cgc) = meta_data_w.custody_group_count_mut() {
|
||||
*cgc = custody_group_count;
|
||||
}
|
||||
let seq_number = *meta_data_w.seq_number();
|
||||
let meta_data = meta_data_w.clone();
|
||||
|
||||
drop(meta_data_w);
|
||||
self.eth2_rpc_mut().update_seq_number(seq_number);
|
||||
// Save the updated metadata to disk
|
||||
utils::save_metadata_to_disk(&self.network_dir, meta_data);
|
||||
}
|
||||
|
||||
/// Sends a Ping request to the peer.
|
||||
#[instrument(parent = None,
|
||||
level = "trace",
|
||||
fields(service = "libp2p"),
|
||||
name = "libp2p",
|
||||
skip_all
|
||||
)]
|
||||
fn ping(&mut self, peer_id: PeerId) {
|
||||
self.eth2_rpc_mut().ping(peer_id, AppRequestId::Internal);
|
||||
}
|
||||
|
||||
/// Sends a METADATA request to a peer.
|
||||
#[instrument(parent = None,
|
||||
level = "trace",
|
||||
fields(service = "libp2p"),
|
||||
name = "libp2p",
|
||||
skip_all
|
||||
)]
|
||||
fn send_meta_data_request(&mut self, peer_id: PeerId) {
|
||||
let event = if self.fork_context.spec.is_peer_das_scheduled() {
|
||||
// Nodes with higher custody will probably start advertising it
|
||||
@@ -1400,34 +1198,9 @@ impl<E: EthSpec> Network<E> {
|
||||
}
|
||||
|
||||
/// Sends a METADATA response to a peer.
|
||||
#[instrument(parent = None,
|
||||
level = "trace",
|
||||
fields(service = "libp2p"),
|
||||
name = "libp2p",
|
||||
skip_all
|
||||
)]
|
||||
fn send_meta_data_response(
|
||||
&mut self,
|
||||
_req: MetadataRequest<E>,
|
||||
inbound_request_id: InboundRequestId,
|
||||
peer_id: PeerId,
|
||||
) {
|
||||
let metadata = self.network_globals.local_metadata.read().clone();
|
||||
// The encoder is responsible for sending the negotiated version of the metadata
|
||||
let event = RpcResponse::Success(RpcSuccessResponse::MetaData(Arc::new(metadata)));
|
||||
self.eth2_rpc_mut()
|
||||
.send_response(peer_id, inbound_request_id, event);
|
||||
}
|
||||
|
||||
// RPC Propagation methods
|
||||
/// Queues the response to be sent upwards as long at it was requested outside the Behaviour.
|
||||
#[must_use = "return the response"]
|
||||
#[instrument(parent = None,
|
||||
level = "trace",
|
||||
fields(service = "libp2p"),
|
||||
name = "libp2p",
|
||||
skip_all
|
||||
)]
|
||||
fn build_response(
|
||||
&mut self,
|
||||
app_request_id: AppRequestId,
|
||||
@@ -1446,12 +1219,6 @@ impl<E: EthSpec> Network<E> {
|
||||
|
||||
/// Dial cached Enrs in discovery service that are in the given `subnet_id` and aren't
|
||||
/// in Connected, Dialing or Banned state.
|
||||
#[instrument(parent = None,
|
||||
level = "trace",
|
||||
fields(service = "libp2p"),
|
||||
name = "libp2p",
|
||||
skip_all
|
||||
)]
|
||||
fn dial_cached_enrs_in_subnet(&mut self, subnet: Subnet, spec: Arc<ChainSpec>) {
|
||||
let predicate = subnet_predicate::<E>(vec![subnet], spec);
|
||||
let peers_to_dial: Vec<Enr> = self
|
||||
@@ -1494,12 +1261,6 @@ impl<E: EthSpec> Network<E> {
|
||||
/* Sub-behaviour event handling functions */
|
||||
|
||||
/// Handle a gossipsub event.
|
||||
#[instrument(parent = None,
|
||||
level = "trace",
|
||||
fields(service = "libp2p"),
|
||||
name = "libp2p",
|
||||
skip_all
|
||||
)]
|
||||
fn inject_gs_event(&mut self, event: gossipsub::Event) -> Option<NetworkEvent<E>> {
|
||||
match event {
|
||||
gossipsub::Event::Message {
|
||||
@@ -1606,14 +1367,12 @@ impl<E: EthSpec> Network<E> {
|
||||
} => {
|
||||
debug!(
|
||||
peer_id = %peer_id,
|
||||
publish = failed_messages.publish,
|
||||
forward = failed_messages.forward,
|
||||
priority = failed_messages.priority,
|
||||
non_priority = failed_messages.non_priority,
|
||||
"Slow gossipsub peer"
|
||||
);
|
||||
// Punish the peer if it cannot handle priority messages
|
||||
if failed_messages.timeout > 10 {
|
||||
if failed_messages.priority > 10 {
|
||||
debug!(%peer_id, "Slow gossipsub peer penalized for priority failure");
|
||||
self.peer_manager_mut().report_peer(
|
||||
&peer_id,
|
||||
@@ -1622,7 +1381,7 @@ impl<E: EthSpec> Network<E> {
|
||||
None,
|
||||
"publish_timeout_penalty",
|
||||
);
|
||||
} else if failed_messages.total_queue_full() > 10 {
|
||||
} else if failed_messages.non_priority > 10 {
|
||||
debug!(%peer_id, "Slow gossipsub peer penalized for send queue full");
|
||||
self.peer_manager_mut().report_peer(
|
||||
&peer_id,
|
||||
@@ -1638,12 +1397,6 @@ impl<E: EthSpec> Network<E> {
|
||||
}
|
||||
|
||||
/// Handle an RPC event.
|
||||
#[instrument(parent = None,
|
||||
level = "trace",
|
||||
fields(service = "libp2p"),
|
||||
name = "libp2p",
|
||||
skip_all
|
||||
)]
|
||||
fn inject_rpc_event(&mut self, event: RPCMessage<AppRequestId, E>) -> Option<NetworkEvent<E>> {
|
||||
let peer_id = event.peer_id;
|
||||
|
||||
@@ -1706,9 +1459,13 @@ impl<E: EthSpec> Network<E> {
|
||||
self.peer_manager_mut().ping_request(&peer_id, ping.data);
|
||||
None
|
||||
}
|
||||
RequestType::MetaData(req) => {
|
||||
RequestType::MetaData(_req) => {
|
||||
// send the requested meta-data
|
||||
self.send_meta_data_response(req, inbound_request_id, peer_id);
|
||||
let metadata = self.network_globals.local_metadata.read().clone();
|
||||
// The encoder is responsible for sending the negotiated version of the metadata
|
||||
let response =
|
||||
RpcResponse::Success(RpcSuccessResponse::MetaData(Arc::new(metadata)));
|
||||
self.send_response(peer_id, inbound_request_id, response);
|
||||
None
|
||||
}
|
||||
RequestType::Goodbye(reason) => {
|
||||
@@ -1930,12 +1687,6 @@ impl<E: EthSpec> Network<E> {
|
||||
}
|
||||
|
||||
/// Handle an identify event.
|
||||
#[instrument(parent = None,
|
||||
level = "trace",
|
||||
fields(service = "libp2p"),
|
||||
name = "libp2p",
|
||||
skip_all
|
||||
)]
|
||||
fn inject_identify_event(&mut self, event: identify::Event) -> Option<NetworkEvent<E>> {
|
||||
match event {
|
||||
identify::Event::Received {
|
||||
@@ -1958,12 +1709,6 @@ impl<E: EthSpec> Network<E> {
|
||||
}
|
||||
|
||||
/// Handle a peer manager event.
|
||||
#[instrument(parent = None,
|
||||
level = "trace",
|
||||
fields(service = "libp2p"),
|
||||
name = "libp2p",
|
||||
skip_all
|
||||
)]
|
||||
fn inject_pm_event(&mut self, event: PeerManagerEvent) -> Option<NetworkEvent<E>> {
|
||||
match event {
|
||||
PeerManagerEvent::PeerConnectedIncoming(peer_id) => {
|
||||
@@ -2017,12 +1762,6 @@ impl<E: EthSpec> Network<E> {
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(parent = None,
|
||||
level = "trace",
|
||||
fields(service = "libp2p"),
|
||||
name = "libp2p",
|
||||
skip_all
|
||||
)]
|
||||
fn inject_upnp_event(&mut self, event: libp2p::upnp::Event) {
|
||||
match event {
|
||||
libp2p::upnp::Event::NewExternalAddr(addr) => {
|
||||
@@ -2066,12 +1805,6 @@ impl<E: EthSpec> Network<E> {
|
||||
}
|
||||
|
||||
/* Networking polling */
|
||||
#[instrument(parent = None,
|
||||
level = "trace",
|
||||
fields(service = "libp2p"),
|
||||
name = "libp2p",
|
||||
skip_all
|
||||
)]
|
||||
pub async fn next_event(&mut self) -> NetworkEvent<E> {
|
||||
loop {
|
||||
tokio::select! {
|
||||
@@ -2105,12 +1838,6 @@ impl<E: EthSpec> Network<E> {
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(parent = None,
|
||||
level = "trace",
|
||||
fields(service = "libp2p"),
|
||||
name = "libp2p",
|
||||
skip_all
|
||||
)]
|
||||
fn parse_swarm_event(
|
||||
&mut self,
|
||||
event: SwarmEvent<BehaviourEvent<E>>,
|
||||
@@ -2152,6 +1879,7 @@ impl<E: EthSpec> Network<E> {
|
||||
send_back_addr,
|
||||
error,
|
||||
connection_id: _,
|
||||
peer_id: _,
|
||||
} => {
|
||||
let error_repr = match error {
|
||||
libp2p::swarm::ListenError::Aborted => {
|
||||
@@ -2160,8 +1888,8 @@ impl<E: EthSpec> Network<E> {
|
||||
libp2p::swarm::ListenError::WrongPeerId { obtained, endpoint } => {
|
||||
format!("Wrong peer id, obtained {obtained}, endpoint {endpoint:?}")
|
||||
}
|
||||
libp2p::swarm::ListenError::LocalPeerId { endpoint } => {
|
||||
format!("Dialing local peer id {endpoint:?}")
|
||||
libp2p::swarm::ListenError::LocalPeerId { address } => {
|
||||
format!("Dialing local peer id {address:?}")
|
||||
}
|
||||
libp2p::swarm::ListenError::Denied { cause } => {
|
||||
format!("Connection was denied with cause: {cause:?}")
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
use crate::multiaddr::Protocol;
|
||||
use crate::rpc::methods::MetaDataV3;
|
||||
use crate::rpc::{MetaData, MetaDataV1, MetaDataV2};
|
||||
use crate::rpc::{MetaData, MetaDataV2, MetaDataV3};
|
||||
use crate::types::{EnrAttestationBitfield, EnrSyncCommitteeBitfield, GossipEncoding, GossipKind};
|
||||
use crate::{GossipTopic, NetworkConfig};
|
||||
use futures::future::Either;
|
||||
use gossipsub;
|
||||
use libp2p::core::{multiaddr::Multiaddr, muxing::StreamMuxerBox, transport::Boxed};
|
||||
use libp2p::identity::{secp256k1, Keypair};
|
||||
use libp2p::{core, noise, yamux, PeerId, Transport};
|
||||
use prometheus_client::registry::Registry;
|
||||
use libp2p::identity::{Keypair, secp256k1};
|
||||
use libp2p::metrics::Registry;
|
||||
use libp2p::{PeerId, Transport, core, noise, yamux};
|
||||
use ssz::Decode;
|
||||
use std::collections::HashSet;
|
||||
use std::fs::File;
|
||||
@@ -42,7 +41,7 @@ pub fn build_transport(
|
||||
quic_support: bool,
|
||||
) -> std::io::Result<BoxedTransport> {
|
||||
// mplex config
|
||||
let mut mplex_config = libp2p_mplex::MplexConfig::new();
|
||||
let mut mplex_config = libp2p_mplex::Config::new();
|
||||
mplex_config.set_max_buffer_size(256);
|
||||
mplex_config.set_max_buffer_behaviour(libp2p_mplex::MaxBufferBehaviour::Block);
|
||||
|
||||
@@ -79,8 +78,6 @@ pub fn build_transport(
|
||||
Ok(transport)
|
||||
}
|
||||
|
||||
// Useful helper functions for debugging. Currently not used in the client.
|
||||
#[allow(dead_code)]
|
||||
fn keypair_from_hex(hex_bytes: &str) -> Result<Keypair, String> {
|
||||
let hex_bytes = if let Some(stripped) = hex_bytes.strip_prefix("0x") {
|
||||
stripped.to_string()
|
||||
@@ -93,7 +90,6 @@ fn keypair_from_hex(hex_bytes: &str) -> Result<Keypair, String> {
|
||||
.and_then(keypair_from_bytes)
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn keypair_from_bytes(mut bytes: Vec<u8>) -> Result<Keypair, String> {
|
||||
secp256k1::SecretKey::try_from_bytes(&mut bytes)
|
||||
.map(|secret| {
|
||||
@@ -107,21 +103,54 @@ fn keypair_from_bytes(mut bytes: Vec<u8>) -> Result<Keypair, String> {
|
||||
/// generated and is then saved to disk.
|
||||
///
|
||||
/// Currently only secp256k1 keys are allowed, as these are the only keys supported by discv5.
|
||||
/// Supports both hex format (with or without 0x prefix) and raw bytes format.
|
||||
pub fn load_private_key(config: &NetworkConfig) -> Keypair {
|
||||
// check for key from disk
|
||||
let network_key_f = config.network_dir.join(NETWORK_KEY_FILENAME);
|
||||
if let Ok(mut network_key_file) = File::open(network_key_f.clone()) {
|
||||
let mut key_bytes: Vec<u8> = Vec::with_capacity(36);
|
||||
match network_key_file.read_to_end(&mut key_bytes) {
|
||||
Err(_) => debug!("Could not read network key file"),
|
||||
Ok(_) => {
|
||||
// only accept secp256k1 keys for now
|
||||
if let Ok(secret_key) = secp256k1::SecretKey::try_from_bytes(&mut key_bytes) {
|
||||
let kp: secp256k1::Keypair = secret_key.into();
|
||||
debug!("Loaded network key from disk.");
|
||||
return kp.into();
|
||||
} else {
|
||||
debug!("Network key file is not a valid secp256k1 key");
|
||||
// Limit read to reasonable hex key size: 32 bytes = 64 hex chars + "0x" prefix + whitespace
|
||||
let mut buffer = vec![0u8; 70];
|
||||
match network_key_file.read(&mut buffer) {
|
||||
Ok(bytes_read) => {
|
||||
if let Ok(hex_string) = String::from_utf8(buffer[..bytes_read].to_vec()) {
|
||||
// First try to parse as hex string
|
||||
let hex_content = hex_string.trim();
|
||||
if let Ok(keypair) = keypair_from_hex(hex_content) {
|
||||
debug!("Loaded network key from disk (hex format).");
|
||||
return keypair;
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(_) => debug!("Could not read network key file as string, trying binary format"),
|
||||
}
|
||||
|
||||
// If hex parsing failed or file couldn't be read as string, try binary format
|
||||
if let Ok(mut network_key_file) = File::open(network_key_f.clone()) {
|
||||
let mut key_bytes: Vec<u8> = Vec::with_capacity(36);
|
||||
match network_key_file.read_to_end(&mut key_bytes) {
|
||||
Err(_) => debug!("Could not read network key file"),
|
||||
Ok(_) => {
|
||||
// only accept secp256k1 keys for now
|
||||
if let Ok(secret_key) = secp256k1::SecretKey::try_from_bytes(&mut key_bytes) {
|
||||
let kp: secp256k1::Keypair = secret_key.clone().into();
|
||||
debug!(
|
||||
"Loaded network key from disk (binary format), migrating to hex format."
|
||||
);
|
||||
|
||||
// Migrate binary key to hex format
|
||||
let hex_key = hex::encode(secret_key.to_bytes());
|
||||
if let Err(e) = File::create(network_key_f.clone())
|
||||
.and_then(|mut f| f.write_all(hex_key.as_bytes()))
|
||||
{
|
||||
debug!("Failed to migrate key to hex format: {}", e);
|
||||
} else {
|
||||
debug!("Successfully migrated key to hex format.");
|
||||
}
|
||||
|
||||
return kp.into();
|
||||
} else {
|
||||
debug!("Network key file is not a valid secp256k1 key");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -130,9 +159,8 @@ pub fn load_private_key(config: &NetworkConfig) -> Keypair {
|
||||
// if a key could not be loaded from disk, generate a new one and save it
|
||||
let local_private_key = secp256k1::Keypair::generate();
|
||||
let _ = std::fs::create_dir_all(&config.network_dir);
|
||||
match File::create(network_key_f.clone())
|
||||
.and_then(|mut f| f.write_all(&local_private_key.secret().to_bytes()))
|
||||
{
|
||||
let hex_key = hex::encode(local_private_key.secret().to_bytes());
|
||||
match File::create(network_key_f.clone()).and_then(|mut f| f.write_all(hex_key.as_bytes())) {
|
||||
Ok(_) => {
|
||||
debug!("New network key generated and written to disk");
|
||||
}
|
||||
@@ -165,38 +193,41 @@ pub fn strip_peer_id(addr: &mut Multiaddr) {
|
||||
/// Load metadata from persisted file. Return default metadata if loading fails.
|
||||
pub fn load_or_build_metadata<E: EthSpec>(
|
||||
network_dir: &Path,
|
||||
custody_group_count_opt: Option<u64>,
|
||||
custody_group_count: u64,
|
||||
) -> MetaData<E> {
|
||||
// We load a V2 metadata version by default (regardless of current fork)
|
||||
// since a V2 metadata can be converted to V1. The RPC encoder is responsible
|
||||
// We load a V3 metadata version by default (regardless of current fork)
|
||||
// since a V3 metadata can be converted to V1 or V2. The RPC encoder is responsible
|
||||
// for sending the correct metadata version based on the negotiated protocol version.
|
||||
let mut meta_data = MetaDataV2 {
|
||||
let mut meta_data = MetaDataV3 {
|
||||
seq_number: 0,
|
||||
attnets: EnrAttestationBitfield::<E>::default(),
|
||||
syncnets: EnrSyncCommitteeBitfield::<E>::default(),
|
||||
custody_group_count,
|
||||
};
|
||||
|
||||
// Read metadata from persisted file if available
|
||||
let metadata_path = network_dir.join(METADATA_FILENAME);
|
||||
if let Ok(mut metadata_file) = File::open(metadata_path) {
|
||||
let mut metadata_ssz = Vec::new();
|
||||
if metadata_file.read_to_end(&mut metadata_ssz).is_ok() {
|
||||
// Attempt to read a MetaDataV2 version from the persisted file,
|
||||
// if that fails, read MetaDataV1
|
||||
match MetaDataV2::<E>::from_ssz_bytes(&metadata_ssz) {
|
||||
// Attempt to read a MetaDataV3 version from the persisted file,
|
||||
// if that fails, read MetaDataV2
|
||||
match MetaDataV3::<E>::from_ssz_bytes(&metadata_ssz) {
|
||||
Ok(persisted_metadata) => {
|
||||
meta_data.seq_number = persisted_metadata.seq_number;
|
||||
// Increment seq number if persisted attnet is not default
|
||||
if persisted_metadata.attnets != meta_data.attnets
|
||||
|| persisted_metadata.syncnets != meta_data.syncnets
|
||||
|| persisted_metadata.custody_group_count != meta_data.custody_group_count
|
||||
{
|
||||
meta_data.seq_number += 1;
|
||||
}
|
||||
debug!("Loaded metadata from disk");
|
||||
}
|
||||
Err(_) => {
|
||||
match MetaDataV1::<E>::from_ssz_bytes(&metadata_ssz) {
|
||||
match MetaDataV2::<E>::from_ssz_bytes(&metadata_ssz) {
|
||||
Ok(persisted_metadata) => {
|
||||
let persisted_metadata = MetaData::V1(persisted_metadata);
|
||||
let persisted_metadata = MetaData::V2(persisted_metadata);
|
||||
// Increment seq number as the persisted metadata version is updated
|
||||
meta_data.seq_number = *persisted_metadata.seq_number() + 1;
|
||||
debug!("Loaded metadata from disk");
|
||||
@@ -213,19 +244,8 @@ pub fn load_or_build_metadata<E: EthSpec>(
|
||||
}
|
||||
};
|
||||
|
||||
// Wrap the MetaData
|
||||
let meta_data = if let Some(custody_group_count) = custody_group_count_opt {
|
||||
MetaData::V3(MetaDataV3 {
|
||||
attnets: meta_data.attnets,
|
||||
seq_number: meta_data.seq_number,
|
||||
syncnets: meta_data.syncnets,
|
||||
custody_group_count,
|
||||
})
|
||||
} else {
|
||||
MetaData::V2(meta_data)
|
||||
};
|
||||
|
||||
debug!(seq_num = meta_data.seq_number(), "Metadata sequence number");
|
||||
debug!(seq_num = meta_data.seq_number, "Metadata sequence number");
|
||||
let meta_data = MetaData::V3(meta_data);
|
||||
save_metadata_to_disk(network_dir, meta_data.clone());
|
||||
meta_data
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user