Merge branch 'unstable' into electra-alpha7

This commit is contained in:
Pawan Dhananjay
2024-11-04 16:33:02 -08:00
12 changed files with 281 additions and 255 deletions

View File

@@ -41,7 +41,7 @@ jobs:
sudo add-apt-repository ppa:rmescandon/yq
echo "deb [trusted=yes] https://apt.fury.io/kurtosis-tech/ /" | sudo tee /etc/apt/sources.list.d/kurtosis.list
sudo apt update
sudo apt install -y kurtosis-cli yq
sudo apt install -y kurtosis-cli=1.3.1 yq
kurtosis analytics disable
- name: Download Docker image artifact
@@ -88,7 +88,7 @@ jobs:
sudo add-apt-repository ppa:rmescandon/yq
echo "deb [trusted=yes] https://apt.fury.io/kurtosis-tech/ /" | sudo tee /etc/apt/sources.list.d/kurtosis.list
sudo apt update
sudo apt install -y kurtosis-cli yq
sudo apt install -y kurtosis-cli=1.3.1 yq
kurtosis analytics disable
- name: Download Docker image artifact
@@ -124,7 +124,7 @@ jobs:
sudo add-apt-repository ppa:rmescandon/yq
echo "deb [trusted=yes] https://apt.fury.io/kurtosis-tech/ /" | sudo tee /etc/apt/sources.list.d/kurtosis.list
sudo apt update
sudo apt install -y kurtosis-cli yq
sudo apt install -y kurtosis-cli=1.3.1 yq
kurtosis analytics disable
- name: Download Docker image artifact

View File

@@ -2,6 +2,9 @@
- Remove the beta tag from the v1.2 upgrade.
See [PR 6344](https://github.com/sigp/lighthouse/pull/6344)
- Correct state inconsistencies with the mesh and connected peers due to the fanout mapping.
See [PR 6244](https://github.com/sigp/lighthouse/pull/6244)
- Implement IDONTWANT messages as per [spec](https://github.com/libp2p/specs/pull/548).
See [PR 5422](https://github.com/sigp/lighthouse/pull/5422)

View File

@@ -764,7 +764,7 @@ where
}
} else {
tracing::error!(peer_id = %peer_id,
"Could not PUBLISH, peer doesn't exist in connected peer list");
"Could not send PUBLISH, peer doesn't exist in connected peer list");
}
}
@@ -1066,7 +1066,7 @@ where
});
} else {
tracing::error!(peer = %peer_id,
"Could not GRAFT, peer doesn't exist in connected peer list");
"Could not send GRAFT, peer doesn't exist in connected peer list");
}
// If the peer did not previously exist in any mesh, inform the handler
@@ -1165,7 +1165,7 @@ where
peer.sender.prune(prune);
} else {
tracing::error!(peer = %peer_id,
"Could not PRUNE, peer doesn't exist in connected peer list");
"Could not send PRUNE, peer doesn't exist in connected peer list");
}
// If the peer did not previously exist in any mesh, inform the handler
@@ -1344,7 +1344,7 @@ where
}
} else {
tracing::error!(peer = %peer_id,
"Could not IWANT, peer doesn't exist in connected peer list");
"Could not send IWANT, peer doesn't exist in connected peer list");
}
}
tracing::trace!(peer=%peer_id, "Completed IHAVE handling for peer");
@@ -1367,7 +1367,7 @@ where
for id in iwant_msgs {
// If we have it and the IHAVE count is not above the threshold,
// foward the message.
// forward the message.
if let Some((msg, count)) = self
.mcache
.get_with_iwant_counts(&id, peer_id)
@@ -1407,7 +1407,7 @@ where
}
} else {
tracing::error!(peer = %peer_id,
"Could not IWANT, peer doesn't exist in connected peer list");
"Could not send IWANT, peer doesn't exist in connected peer list");
}
}
}
@@ -2050,8 +2050,11 @@ where
}
}
// remove unsubscribed peers from the mesh if it exists
// remove unsubscribed peers from the mesh and fanout if they exist there.
for (peer_id, topic_hash) in unsubscribed_peers {
self.fanout
.get_mut(&topic_hash)
.map(|peers| peers.remove(&peer_id));
self.remove_peer_from_mesh(&peer_id, &topic_hash, None, false, Churn::Unsub);
}
@@ -2075,7 +2078,7 @@ where
}
} else {
tracing::error!(peer = %propagation_source,
"Could not GRAFT, peer doesn't exist in connected peer list");
"Could not send GRAFT, peer doesn't exist in connected peer list");
}
// Notify the application of the subscriptions
@@ -2093,6 +2096,8 @@ where
fn apply_iwant_penalties(&mut self) {
if let Some((peer_score, ..)) = &mut self.peer_score {
for (peer, count) in self.gossip_promises.get_broken_promises() {
// We do not apply penalties to nodes that have disconnected.
if self.connected_peers.contains_key(&peer) {
peer_score.add_penalty(&peer, count);
if let Some(metrics) = self.metrics.as_mut() {
metrics.register_score_penalty(Penalty::BrokenPromise);
@@ -2100,6 +2105,7 @@ where
}
}
}
}
/// Heartbeat function which shifts the memcache and updates the mesh.
fn heartbeat(&mut self) {
@@ -2590,7 +2596,7 @@ where
}
} else {
tracing::error!(peer = %peer_id,
"Could not IHAVE, peer doesn't exist in connected peer list");
"Could not send IHAVE, peer doesn't exist in connected peer list");
}
}
}
@@ -2676,7 +2682,7 @@ where
peer.sender.prune(prune);
} else {
tracing::error!(peer = %peer_id,
"Could not PRUNE, peer doesn't exist in connected peer list");
"Could not send PRUNE, peer doesn't exist in connected peer list");
}
// inform the handler
@@ -2713,8 +2719,8 @@ where
for peer_id in recipient_peers {
let Some(peer) = self.connected_peers.get_mut(peer_id) else {
tracing::error!(peer = %peer_id,
"Could not IDONTWANT, peer doesn't exist in connected peer list");
// It can be the case that promises to disconnected peers appear here. In this case
// we simply ignore the peer-id.
continue;
};
@@ -2979,7 +2985,7 @@ where
}
} else {
tracing::error!(peer = %peer_id,
"Could not SUBSCRIBE, peer doesn't exist in connected peer list");
"Could not send SUBSCRIBE, peer doesn't exist in connected peer list");
}
}

View File

@@ -37,10 +37,7 @@ use slog::{crit, debug, info, o, trace, warn};
use std::num::{NonZeroU8, NonZeroUsize};
use std::path::PathBuf;
use std::pin::Pin;
use std::{
sync::Arc,
task::{Context, Poll},
};
use std::sync::Arc;
use types::{
consts::altair::SYNC_COMMITTEE_SUBNET_COUNT, EnrForkId, EthSpec, ForkContext, Slot, SubnetId,
};
@@ -1794,12 +1791,45 @@ impl<E: EthSpec> Network<E> {
/* Networking polling */
/// Poll the p2p networking stack.
///
/// This will poll the swarm and do maintenance routines.
pub fn poll_network(&mut self, cx: &mut Context) -> Poll<NetworkEvent<E>> {
while let Poll::Ready(Some(swarm_event)) = self.swarm.poll_next_unpin(cx) {
let maybe_event = match swarm_event {
pub async fn next_event(&mut self) -> NetworkEvent<E> {
loop {
tokio::select! {
// Poll the libp2p `Swarm`.
// This will poll the swarm and do maintenance routines.
Some(event) = self.swarm.next() => {
if let Some(event) = self.parse_swarm_event(event) {
return event;
}
},
// perform gossipsub score updates when necessary
_ = self.update_gossipsub_scores.tick() => {
let this = self.swarm.behaviour_mut();
this.peer_manager.update_gossipsub_scores(&this.gossipsub);
}
// poll the gossipsub cache to clear expired messages
Some(result) = self.gossip_cache.next() => {
match result {
Err(e) => warn!(self.log, "Gossip cache error"; "error" => e),
Ok(expired_topic) => {
if let Some(v) = metrics::get_int_counter(
&metrics::GOSSIP_EXPIRED_LATE_PUBLISH_PER_TOPIC_KIND,
&[expired_topic.kind().as_ref()],
) {
v.inc()
};
}
}
}
}
}
}
fn parse_swarm_event(
&mut self,
event: SwarmEvent<BehaviourEvent<E>>,
) -> Option<NetworkEvent<E>> {
match event {
SwarmEvent::Behaviour(behaviour_event) => match behaviour_event {
// Handle sub-behaviour events.
BehaviourEvent::Gossipsub(ge) => self.inject_gs_event(ge),
@@ -1872,9 +1902,7 @@ impl<E: EthSpec> Network<E> {
// behaviour implementation.
None
}
SwarmEvent::NewListenAddr { address, .. } => {
Some(NetworkEvent::NewListenAddr(address))
}
SwarmEvent::NewListenAddr { address, .. } => Some(NetworkEvent::NewListenAddr(address)),
SwarmEvent::ExpiredListenAddr { address, .. } => {
debug!(self.log, "Listen address expired"; "address" => %address);
None
@@ -1905,37 +1933,6 @@ impl<E: EthSpec> Network<E> {
// release notes more than compiler feedback
None
}
};
if let Some(ev) = maybe_event {
return Poll::Ready(ev);
}
}
// perform gossipsub score updates when necessary
while self.update_gossipsub_scores.poll_tick(cx).is_ready() {
let this = self.swarm.behaviour_mut();
this.peer_manager.update_gossipsub_scores(&this.gossipsub);
}
// poll the gossipsub cache to clear expired messages
while let Poll::Ready(Some(result)) = self.gossip_cache.poll_next_unpin(cx) {
match result {
Err(e) => warn!(self.log, "Gossip cache error"; "error" => e),
Ok(expired_topic) => {
if let Some(v) = metrics::get_int_counter(
&metrics::GOSSIP_EXPIRED_LATE_PUBLISH_PER_TOPIC_KIND,
&[expired_topic.kind().as_ref()],
) {
v.inc()
};
}
}
}
Poll::Pending
}
pub async fn next_event(&mut self) -> NetworkEvent<E> {
futures::future::poll_fn(|cx| self.poll_network(cx)).await
}
}

View File

@@ -793,6 +793,7 @@ pub fn cli_app() -> Command {
.help("Server endpoint for an execution layer JWT-authenticated HTTP \
JSON-RPC connection. Uses the same endpoint to populate the \
deposit cache.")
.required(true)
.action(ArgAction::Set)
.display_order(0)
)

View File

@@ -284,7 +284,8 @@ pub fn get_config<E: EthSpec>(
client_config.eth1.cache_follow_distance = Some(follow_distance);
}
if let Some(endpoints) = cli_args.get_one::<String>("execution-endpoint") {
// `--execution-endpoint` is required now.
let endpoints: String = clap_utils::parse_required(cli_args, "execution-endpoint")?;
let mut el_config = execution_layer::Config::default();
// Always follow the deposit contract when there is an execution endpoint.
@@ -299,8 +300,12 @@ pub fn get_config<E: EthSpec>(
client_config.sync_eth1_chain = true;
// Parse a single execution endpoint, logging warnings if multiple endpoints are supplied.
let execution_endpoint =
parse_only_one_value(endpoints, SensitiveUrl::parse, "--execution-endpoint", log)?;
let execution_endpoint = parse_only_one_value(
endpoints.as_str(),
SensitiveUrl::parse,
"--execution-endpoint",
log,
)?;
// JWTs are required if `--execution-endpoint` is supplied. They can be either passed via
// file_path or directly as string.
@@ -313,8 +318,7 @@ pub fn get_config<E: EthSpec>(
// Check if the JWT secret key is passed directly via cli flag and persist it to the default
// file location.
} else if let Some(jwt_secret_key) = cli_args.get_one::<String>("execution-jwt-secret-key")
{
} else if let Some(jwt_secret_key) = cli_args.get_one::<String>("execution-jwt-secret-key") {
use std::fs::File;
use std::io::Write;
secret_file = client_config.data_dir().join(DEFAULT_JWT_FILE);
@@ -338,8 +342,7 @@ pub fn get_config<E: EthSpec>(
parse_only_one_value(endpoint, SensitiveUrl::parse, "--builder", log)?;
el_config.builder_url = Some(payload_builder);
el_config.builder_user_agent =
clap_utils::parse_optional(cli_args, "builder-user-agent")?;
el_config.builder_user_agent = clap_utils::parse_optional(cli_args, "builder-user-agent")?;
el_config.builder_header_timeout =
clap_utils::parse_optional(cli_args, "builder-header-timeout")?
@@ -369,7 +372,6 @@ pub fn get_config<E: EthSpec>(
// Store the EL config in the client config.
client_config.execution_layer = Some(el_config);
}
// 4844 params
if let Some(trusted_setup) = context

View File

@@ -5,7 +5,7 @@ The primary component which connects to the Ethereum 2.0 P2P network and
downloads, verifies and stores blocks. Provides a HTTP API for querying the
beacon chain and publishing messages to the network.
Usage: lighthouse beacon_node [OPTIONS]
Usage: lighthouse beacon_node [OPTIONS] --execution-endpoint <EXECUTION-ENDPOINT>
Options:
--auto-compact-db <auto-compact-db>

View File

@@ -13,7 +13,7 @@ use std::slice::SliceIndex;
/// ## Example
///
/// ```
/// use ssz_types::{RuntimeVariableList};
/// use types::{RuntimeVariableList};
///
/// let base: Vec<u64> = vec![1, 2, 3, 4];
///

View File

@@ -24,7 +24,9 @@ use types::non_zero_usize::new_non_zero_usize;
use types::{Address, Checkpoint, Epoch, Hash256, MainnetEthSpec};
use unused_port::{unused_tcp4_port, unused_tcp6_port, unused_udp4_port, unused_udp6_port};
const DEFAULT_ETH1_ENDPOINT: &str = "http://localhost:8545/";
const DEFAULT_EXECUTION_ENDPOINT: &str = "http://localhost:8551/";
const DEFAULT_EXECUTION_JWT_SECRET_KEY: &str =
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
// These dummy ports should ONLY be used for `enr-xxx-port` flags that do not bind.
const DUMMY_ENR_TCP_PORT: u16 = 7777;
@@ -52,6 +54,18 @@ struct CommandLineTest {
}
impl CommandLineTest {
fn new() -> CommandLineTest {
let mut base_cmd = base_cmd();
base_cmd
.arg("--execution-endpoint")
.arg(DEFAULT_EXECUTION_ENDPOINT)
.arg("--execution-jwt-secret-key")
.arg(DEFAULT_EXECUTION_JWT_SECRET_KEY);
CommandLineTest { cmd: base_cmd }
}
// Required for testing different JWT authentication methods.
fn new_with_no_execution_endpoint() -> CommandLineTest {
let base_cmd = base_cmd();
CommandLineTest { cmd: base_cmd }
}
@@ -104,7 +118,7 @@ fn staking_flag() {
assert!(config.sync_eth1_chain);
assert_eq!(
config.eth1.endpoint.get_endpoint().to_string(),
DEFAULT_ETH1_ENDPOINT
DEFAULT_EXECUTION_ENDPOINT
);
});
}
@@ -253,7 +267,7 @@ fn always_prepare_payload_default() {
#[test]
fn always_prepare_payload_override() {
let dir = TempDir::new().expect("Unable to create temporary directory");
CommandLineTest::new()
CommandLineTest::new_with_no_execution_endpoint()
.flag("always-prepare-payload", None)
.flag(
"suggested-fee-recipient",
@@ -459,7 +473,7 @@ fn run_bellatrix_execution_endpoints_flag_test(flag: &str) {
// this is way better but intersperse is still a nightly feature :/
// let endpoint_arg: String = urls.into_iter().intersperse(",").collect();
CommandLineTest::new()
CommandLineTest::new_with_no_execution_endpoint()
.flag(flag, Some(&endpoint_arg))
.flag("execution-jwt", Some(&jwts_arg))
.run_with_zero_port()
@@ -480,7 +494,7 @@ fn run_bellatrix_execution_endpoints_flag_test(flag: &str) {
#[test]
fn run_execution_jwt_secret_key_is_persisted() {
let jwt_secret_key = "0x3cbc11b0d8fa16f3344eacfd6ff6430b9d30734450e8adcf5400f88d327dcb33";
CommandLineTest::new()
CommandLineTest::new_with_no_execution_endpoint()
.flag("execution-endpoint", Some("http://localhost:8551/"))
.flag("execution-jwt-secret-key", Some(jwt_secret_key))
.run_with_zero_port()
@@ -501,7 +515,7 @@ fn run_execution_jwt_secret_key_is_persisted() {
#[test]
fn execution_timeout_multiplier_flag() {
let dir = TempDir::new().expect("Unable to create temporary directory");
CommandLineTest::new()
CommandLineTest::new_with_no_execution_endpoint()
.flag("execution-endpoint", Some("http://meow.cats"))
.flag(
"execution-jwt",
@@ -528,7 +542,7 @@ fn bellatrix_jwt_secrets_flag() {
let mut file = File::create(dir.path().join("jwtsecrets")).expect("Unable to create file");
file.write_all(b"0x3cbc11b0d8fa16f3344eacfd6ff6430b9d30734450e8adcf5400f88d327dcb33")
.expect("Unable to write to file");
CommandLineTest::new()
CommandLineTest::new_with_no_execution_endpoint()
.flag("execution-endpoints", Some("http://localhost:8551/"))
.flag(
"jwt-secrets",
@@ -550,7 +564,7 @@ fn bellatrix_jwt_secrets_flag() {
#[test]
fn bellatrix_fee_recipient_flag() {
let dir = TempDir::new().expect("Unable to create temporary directory");
CommandLineTest::new()
CommandLineTest::new_with_no_execution_endpoint()
.flag("execution-endpoint", Some("http://meow.cats"))
.flag(
"execution-jwt",
@@ -591,7 +605,7 @@ fn run_payload_builder_flag_test_with_config<F: Fn(&Config)>(
f: F,
) {
let dir = TempDir::new().expect("Unable to create temporary directory");
let mut test = CommandLineTest::new();
let mut test = CommandLineTest::new_with_no_execution_endpoint();
test.flag("execution-endpoint", Some("http://meow.cats"))
.flag(
"execution-jwt",
@@ -713,7 +727,7 @@ fn run_jwt_optional_flags_test(jwt_flag: &str, jwt_id_flag: &str, jwt_version_fl
let jwt_file = "jwt-file";
let id = "bn-1";
let version = "Lighthouse-v2.1.3";
CommandLineTest::new()
CommandLineTest::new_with_no_execution_endpoint()
.flag("execution-endpoint", Some(execution_endpoint))
.flag(jwt_flag, dir.path().join(jwt_file).as_os_str().to_str())
.flag(jwt_id_flag, Some(id))
@@ -2430,13 +2444,13 @@ fn logfile_format_flag() {
fn sync_eth1_chain_default() {
CommandLineTest::new()
.run_with_zero_port()
.with_config(|config| assert_eq!(config.sync_eth1_chain, false));
.with_config(|config| assert_eq!(config.sync_eth1_chain, true));
}
#[test]
fn sync_eth1_chain_execution_endpoints_flag() {
let dir = TempDir::new().expect("Unable to create temporary directory");
CommandLineTest::new()
CommandLineTest::new_with_no_execution_endpoint()
.flag("execution-endpoints", Some("http://localhost:8551/"))
.flag(
"execution-jwt",
@@ -2449,7 +2463,7 @@ fn sync_eth1_chain_execution_endpoints_flag() {
#[test]
fn sync_eth1_chain_disable_deposit_contract_sync_flag() {
let dir = TempDir::new().expect("Unable to create temporary directory");
CommandLineTest::new()
CommandLineTest::new_with_no_execution_endpoint()
.flag("disable-deposit-contract-sync", None)
.flag("execution-endpoints", Some("http://localhost:8551/"))
.flag(

View File

@@ -206,7 +206,7 @@ pub fn run_basic_sim(matches: &ArgMatches) -> Result<(), String> {
node.server.all_payloads_valid();
});
let duration_to_genesis = network.duration_to_genesis().await;
let duration_to_genesis = network.duration_to_genesis().await?;
println!("Duration to genesis: {}", duration_to_genesis.as_secs());
sleep(duration_to_genesis).await;

View File

@@ -194,7 +194,7 @@ pub fn run_fallback_sim(matches: &ArgMatches) -> Result<(), String> {
);
}
let duration_to_genesis = network.duration_to_genesis().await;
let duration_to_genesis = network.duration_to_genesis().await?;
println!("Duration to genesis: {}", duration_to_genesis.as_secs());
sleep(duration_to_genesis).await;

View File

@@ -459,7 +459,7 @@ impl<E: EthSpec> LocalNetwork<E> {
.map(|body| body.unwrap().data.finalized.epoch)
}
pub async fn duration_to_genesis(&self) -> Duration {
pub async fn duration_to_genesis(&self) -> Result<Duration, &'static str> {
let nodes = self.remote_nodes().expect("Failed to get remote nodes");
let bootnode = nodes.first().expect("Should contain bootnode");
let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
@@ -471,6 +471,9 @@ impl<E: EthSpec> LocalNetwork<E> {
.data
.genesis_time,
);
genesis_time - now
genesis_time.checked_sub(now).ok_or(
"The genesis time has already passed since all nodes started. The node startup time \
may have regressed, and the current `GENESIS_DELAY` is no longer sufficient.",
)
}
}