mirror of
https://github.com/sigp/lighthouse.git
synced 2026-03-03 00:31:50 +00:00
Compare commits
17 Commits
sync-start
...
v7.0.0-bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dc320e3faa | ||
|
|
e473500456 | ||
|
|
627c1bac89 | ||
|
|
0c5580f23f | ||
|
|
279afb0696 | ||
|
|
fd1ca8ef23 | ||
|
|
df3038d902 | ||
|
|
88c0f9d60a | ||
|
|
c61cf26622 | ||
|
|
2883429f69 | ||
|
|
19fc31a75b | ||
|
|
ff2376efec | ||
|
|
d4586ea92d | ||
|
|
1b9b61bb77 | ||
|
|
11f17e52a0 | ||
|
|
d472689fa2 | ||
|
|
bbc1200b2d |
8
Cargo.lock
generated
8
Cargo.lock
generated
@@ -860,7 +860,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "beacon_node"
|
||||
version = "7.0.0-beta.0"
|
||||
version = "7.0.0-beta.1"
|
||||
dependencies = [
|
||||
"account_utils",
|
||||
"beacon_chain",
|
||||
@@ -1108,7 +1108,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "boot_node"
|
||||
version = "7.0.0-beta.0"
|
||||
version = "7.0.0-beta.1"
|
||||
dependencies = [
|
||||
"beacon_node",
|
||||
"bytes",
|
||||
@@ -4811,7 +4811,7 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
|
||||
|
||||
[[package]]
|
||||
name = "lcli"
|
||||
version = "7.0.0-beta.0"
|
||||
version = "7.0.0-beta.1"
|
||||
dependencies = [
|
||||
"account_utils",
|
||||
"beacon_chain",
|
||||
@@ -5366,7 +5366,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "lighthouse"
|
||||
version = "7.0.0-beta.0"
|
||||
version = "7.0.0-beta.1"
|
||||
dependencies = [
|
||||
"account_manager",
|
||||
"account_utils",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "beacon_node"
|
||||
version = "7.0.0-beta.0"
|
||||
version = "7.0.0-beta.1"
|
||||
authors = [
|
||||
"Paul Hauner <paul@paulhauner.com>",
|
||||
"Age Manning <Age@AgeManning.com",
|
||||
|
||||
@@ -4848,7 +4848,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
let proposer_index = if let Some(proposer) = cached_proposer {
|
||||
proposer.index as u64
|
||||
} else {
|
||||
if head_epoch + 2 < proposal_epoch {
|
||||
if 2 + 2 == 5 && head_epoch + 2 < proposal_epoch {
|
||||
warn!(
|
||||
self.log,
|
||||
"Skipping proposer preparation";
|
||||
@@ -6089,8 +6089,10 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
//
|
||||
// This prevents the routine from running during sync.
|
||||
let head_slot = cached_head.head_slot();
|
||||
if head_slot + T::EthSpec::slots_per_epoch() * PREPARE_PROPOSER_HISTORIC_EPOCHS
|
||||
< current_slot
|
||||
if 2 + 2 == 5
|
||||
&& head_slot
|
||||
+ T::EthSpec::slots_per_epoch() * PREPARE_PROPOSER_HISTORIC_EPOCHS
|
||||
< current_slot
|
||||
{
|
||||
debug!(
|
||||
chain.log,
|
||||
|
||||
@@ -90,6 +90,7 @@ use std::borrow::Cow;
|
||||
use std::fmt::Debug;
|
||||
use std::fs;
|
||||
use std::io::Write;
|
||||
use std::str::FromStr;
|
||||
use std::sync::Arc;
|
||||
use store::{Error as DBError, HotStateSummary, KeyValueStore, StoreOp};
|
||||
use strum::AsRefStr;
|
||||
@@ -146,7 +147,9 @@ pub enum BlockError {
|
||||
///
|
||||
/// It's unclear if this block is valid, but it cannot be processed without already knowing
|
||||
/// its parent.
|
||||
ParentUnknown { parent_root: Hash256 },
|
||||
ParentUnknown {
|
||||
parent_root: Hash256,
|
||||
},
|
||||
/// The block slot is greater than the present slot.
|
||||
///
|
||||
/// ## Peer scoring
|
||||
@@ -161,7 +164,10 @@ pub enum BlockError {
|
||||
/// ## Peer scoring
|
||||
///
|
||||
/// The peer has incompatible state transition logic and is faulty.
|
||||
StateRootMismatch { block: Hash256, local: Hash256 },
|
||||
StateRootMismatch {
|
||||
block: Hash256,
|
||||
local: Hash256,
|
||||
},
|
||||
/// The block was a genesis block, these blocks cannot be re-imported.
|
||||
GenesisBlock,
|
||||
/// The slot is finalized, no need to import.
|
||||
@@ -180,7 +186,9 @@ pub enum BlockError {
|
||||
///
|
||||
/// It's unclear if this block is valid, but it conflicts with finality and shouldn't be
|
||||
/// imported.
|
||||
NotFinalizedDescendant { block_parent_root: Hash256 },
|
||||
NotFinalizedDescendant {
|
||||
block_parent_root: Hash256,
|
||||
},
|
||||
/// Block is already known and valid, no need to re-import.
|
||||
///
|
||||
/// ## Peer scoring
|
||||
@@ -207,7 +215,10 @@ pub enum BlockError {
|
||||
/// ## Peer scoring
|
||||
///
|
||||
/// The block is invalid and the peer is faulty.
|
||||
IncorrectBlockProposer { block: u64, local_shuffling: u64 },
|
||||
IncorrectBlockProposer {
|
||||
block: u64,
|
||||
local_shuffling: u64,
|
||||
},
|
||||
/// The `block.proposal_index` is not known.
|
||||
///
|
||||
/// ## Peer scoring
|
||||
@@ -225,7 +236,10 @@ pub enum BlockError {
|
||||
/// ## Peer scoring
|
||||
///
|
||||
/// The block is invalid and the peer is faulty.
|
||||
BlockIsNotLaterThanParent { block_slot: Slot, parent_slot: Slot },
|
||||
BlockIsNotLaterThanParent {
|
||||
block_slot: Slot,
|
||||
parent_slot: Slot,
|
||||
},
|
||||
/// At least one block in the chain segment did not have it's parent root set to the root of
|
||||
/// the prior block.
|
||||
///
|
||||
@@ -281,7 +295,10 @@ pub enum BlockError {
|
||||
/// If it's actually our fault (e.g. our execution node database is corrupt) we have bigger
|
||||
/// problems to worry about than losing peers, and we're doing the network a favour by
|
||||
/// disconnecting.
|
||||
ParentExecutionPayloadInvalid { parent_root: Hash256 },
|
||||
ParentExecutionPayloadInvalid {
|
||||
parent_root: Hash256,
|
||||
},
|
||||
KnownInvalidExecutionPayload(Hash256),
|
||||
/// The block is a slashable equivocation from the proposer.
|
||||
///
|
||||
/// ## Peer scoring
|
||||
@@ -1326,6 +1343,13 @@ impl<T: BeaconChainTypes> ExecutionPendingBlock<T> {
|
||||
chain: &Arc<BeaconChain<T>>,
|
||||
notify_execution_layer: NotifyExecutionLayer,
|
||||
) -> Result<Self, BlockError> {
|
||||
if block_root
|
||||
== Hash256::from_str("2db899881ed8546476d0b92c6aa9110bea9a4cd0dbeb5519eb0ea69575f1f359")
|
||||
.expect("valid hash")
|
||||
{
|
||||
return Err(BlockError::KnownInvalidExecutionPayload(block_root));
|
||||
}
|
||||
|
||||
chain
|
||||
.observed_slashable
|
||||
.write()
|
||||
|
||||
@@ -94,6 +94,8 @@ pub struct ChainConfig {
|
||||
/// The delay in milliseconds applied by the node between sending each blob or data column batch.
|
||||
/// This doesn't apply if the node is the block proposer.
|
||||
pub blob_publication_batch_interval: Duration,
|
||||
pub disable_attesting: bool,
|
||||
pub sync_tolerance_epochs: u64,
|
||||
}
|
||||
|
||||
impl Default for ChainConfig {
|
||||
@@ -129,6 +131,8 @@ impl Default for ChainConfig {
|
||||
enable_sampling: false,
|
||||
blob_publication_batches: 4,
|
||||
blob_publication_batch_interval: Duration::from_millis(300),
|
||||
disable_attesting: false,
|
||||
sync_tolerance_epochs: 16,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,11 +46,11 @@ tree_hash = { workspace = true }
|
||||
types = { workspace = true }
|
||||
warp = { workspace = true }
|
||||
warp_utils = { workspace = true }
|
||||
proto_array = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
genesis = { workspace = true }
|
||||
logging = { workspace = true }
|
||||
proto_array = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
|
||||
[[test]]
|
||||
|
||||
@@ -107,13 +107,6 @@ use warp_utils::{query::multi_key_query, reject::convert_rejection, uor::Unifyin
|
||||
|
||||
const API_PREFIX: &str = "eth";
|
||||
|
||||
/// If the node is within this many epochs from the head, we declare it to be synced regardless of
|
||||
/// the network sync state.
|
||||
///
|
||||
/// This helps prevent attacks where nodes can convince us that we're syncing some non-existent
|
||||
/// finalized head.
|
||||
const SYNC_TOLERANCE_EPOCHS: u64 = 8;
|
||||
|
||||
/// A custom type which allows for both unsecured and TLS-enabled HTTP servers.
|
||||
type HttpServer = (SocketAddr, Pin<Box<dyn Future<Output = ()> + Send>>);
|
||||
|
||||
@@ -157,6 +150,7 @@ pub struct Config {
|
||||
pub duplicate_block_status_code: StatusCode,
|
||||
pub enable_light_client_server: bool,
|
||||
pub target_peers: usize,
|
||||
pub sync_tolerance_epochs: usize,
|
||||
}
|
||||
|
||||
impl Default for Config {
|
||||
@@ -173,6 +167,7 @@ impl Default for Config {
|
||||
duplicate_block_status_code: StatusCode::ACCEPTED,
|
||||
enable_light_client_server: true,
|
||||
target_peers: 100,
|
||||
sync_tolerance_epochs: 16,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -473,7 +468,8 @@ pub fn serve<T: BeaconChainTypes>(
|
||||
)
|
||||
})?;
|
||||
|
||||
let tolerance = SYNC_TOLERANCE_EPOCHS * T::EthSpec::slots_per_epoch();
|
||||
let tolerance =
|
||||
chain.config.sync_tolerance_epochs * T::EthSpec::slots_per_epoch();
|
||||
|
||||
if head_slot + tolerance >= current_slot {
|
||||
Ok(())
|
||||
@@ -1859,6 +1855,13 @@ pub fn serve<T: BeaconChainTypes>(
|
||||
network_tx: UnboundedSender<NetworkMessage<T::EthSpec>>,
|
||||
reprocess_tx: Option<Sender<ReprocessQueueMessage>>,
|
||||
log: Logger| async move {
|
||||
if chain.config.disable_attesting {
|
||||
return convert_rejection::<Response<String>>(Err(
|
||||
warp_utils::reject::custom_bad_request("Attesting disabled".to_string()),
|
||||
))
|
||||
.await;
|
||||
}
|
||||
|
||||
let attestations = attestations.into_iter().map(Either::Left).collect();
|
||||
let result = crate::publish_attestations::publish_attestations(
|
||||
task_spawner,
|
||||
@@ -1891,6 +1894,12 @@ pub fn serve<T: BeaconChainTypes>(
|
||||
network_tx: UnboundedSender<NetworkMessage<T::EthSpec>>,
|
||||
reprocess_tx: Option<Sender<ReprocessQueueMessage>>,
|
||||
log: Logger| async move {
|
||||
if chain.config.disable_attesting {
|
||||
return convert_rejection::<Response<String>>(Err(
|
||||
warp_utils::reject::custom_bad_request("Attesting disabled".to_string()),
|
||||
))
|
||||
.await;
|
||||
}
|
||||
let attestations =
|
||||
match crate::publish_attestations::deserialize_attestation_payload::<T>(
|
||||
payload, fork_name, &log,
|
||||
@@ -1937,49 +1946,66 @@ pub fn serve<T: BeaconChainTypes>(
|
||||
task_spawner: TaskSpawner<T::EthSpec>,
|
||||
chain: Arc<BeaconChain<T>>,
|
||||
query: api_types::AttestationPoolQuery| {
|
||||
task_spawner.blocking_response_task(Priority::P1, move || {
|
||||
let query_filter = |data: &AttestationData| {
|
||||
query.slot.is_none_or(|slot| slot == data.slot)
|
||||
&& query
|
||||
.committee_index
|
||||
.is_none_or(|index| index == data.index)
|
||||
};
|
||||
async move {
|
||||
if chain.config.disable_attesting {
|
||||
return convert_rejection::<Response<String>>(Err(
|
||||
warp_utils::reject::custom_bad_request(
|
||||
"Attesting disabled".to_string(),
|
||||
),
|
||||
))
|
||||
.await;
|
||||
}
|
||||
task_spawner
|
||||
.blocking_response_task(Priority::P1, move || {
|
||||
let query_filter = |data: &AttestationData| {
|
||||
query.slot.is_none_or(|slot| slot == data.slot)
|
||||
&& query
|
||||
.committee_index
|
||||
.is_none_or(|index| index == data.index)
|
||||
};
|
||||
|
||||
let mut attestations = chain.op_pool.get_filtered_attestations(query_filter);
|
||||
attestations.extend(
|
||||
chain
|
||||
.naive_aggregation_pool
|
||||
.read()
|
||||
.iter()
|
||||
.filter(|&att| query_filter(att.data()))
|
||||
.cloned(),
|
||||
);
|
||||
// Use the current slot to find the fork version, and convert all messages to the
|
||||
// current fork's format. This is to ensure consistent message types matching
|
||||
// `Eth-Consensus-Version`.
|
||||
let current_slot =
|
||||
chain
|
||||
.slot_clock
|
||||
.now()
|
||||
.ok_or(warp_utils::reject::custom_server_error(
|
||||
"unable to read slot clock".to_string(),
|
||||
))?;
|
||||
let fork_name = chain.spec.fork_name_at_slot::<T::EthSpec>(current_slot);
|
||||
let attestations = attestations
|
||||
.into_iter()
|
||||
.filter(|att| {
|
||||
(fork_name.electra_enabled() && matches!(att, Attestation::Electra(_)))
|
||||
|| (!fork_name.electra_enabled()
|
||||
&& matches!(att, Attestation::Base(_)))
|
||||
let mut attestations =
|
||||
chain.op_pool.get_filtered_attestations(query_filter);
|
||||
attestations.extend(
|
||||
chain
|
||||
.naive_aggregation_pool
|
||||
.read()
|
||||
.iter()
|
||||
.filter(|&att| query_filter(att.data()))
|
||||
.cloned(),
|
||||
);
|
||||
// Use the current slot to find the fork version, and convert all messages to the
|
||||
// current fork's format. This is to ensure consistent message types matching
|
||||
// `Eth-Consensus-Version`.
|
||||
let current_slot = chain.slot_clock.now().ok_or(
|
||||
warp_utils::reject::custom_server_error(
|
||||
"unable to read slot clock".to_string(),
|
||||
),
|
||||
)?;
|
||||
let fork_name =
|
||||
chain.spec.fork_name_at_slot::<T::EthSpec>(current_slot);
|
||||
let attestations = attestations
|
||||
.into_iter()
|
||||
.filter(|att| {
|
||||
(fork_name.electra_enabled()
|
||||
&& matches!(att, Attestation::Electra(_)))
|
||||
|| (!fork_name.electra_enabled()
|
||||
&& matches!(att, Attestation::Base(_)))
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let res = fork_versioned_response(
|
||||
endpoint_version,
|
||||
fork_name,
|
||||
&attestations,
|
||||
)?;
|
||||
Ok(add_consensus_version_header(
|
||||
warp::reply::json(&res).into_response(),
|
||||
fork_name,
|
||||
))
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let res = fork_versioned_response(endpoint_version, fork_name, &attestations)?;
|
||||
Ok(add_consensus_version_header(
|
||||
warp::reply::json(&res).into_response(),
|
||||
fork_name,
|
||||
))
|
||||
})
|
||||
.await
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
@@ -2200,12 +2226,24 @@ pub fn serve<T: BeaconChainTypes>(
|
||||
signatures: Vec<SyncCommitteeMessage>,
|
||||
network_tx: UnboundedSender<NetworkMessage<T::EthSpec>>,
|
||||
log: Logger| {
|
||||
task_spawner.blocking_json_task(Priority::P0, move || {
|
||||
sync_committees::process_sync_committee_signatures(
|
||||
signatures, network_tx, &chain, log,
|
||||
)?;
|
||||
Ok(api_types::GenericResponse::from(()))
|
||||
})
|
||||
async move {
|
||||
if chain.config.disable_attesting {
|
||||
return convert_rejection::<Response<String>>(Err(
|
||||
warp_utils::reject::custom_bad_request(
|
||||
"Attesting disabled".to_string(),
|
||||
),
|
||||
))
|
||||
.await;
|
||||
}
|
||||
task_spawner
|
||||
.blocking_json_task(Priority::P0, move || {
|
||||
sync_committees::process_sync_committee_signatures(
|
||||
signatures, network_tx, &chain, log,
|
||||
)?;
|
||||
Ok(api_types::GenericResponse::from(()))
|
||||
})
|
||||
.await
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
@@ -3419,10 +3457,22 @@ pub fn serve<T: BeaconChainTypes>(
|
||||
indices: api_types::ValidatorIndexData,
|
||||
task_spawner: TaskSpawner<T::EthSpec>,
|
||||
chain: Arc<BeaconChain<T>>| {
|
||||
task_spawner.blocking_json_task(Priority::P0, move || {
|
||||
not_synced_filter?;
|
||||
attester_duties::attester_duties(epoch, &indices.0, &chain)
|
||||
})
|
||||
async move {
|
||||
if chain.config.disable_attesting {
|
||||
return convert_rejection::<Response<String>>(Err(
|
||||
warp_utils::reject::custom_bad_request(
|
||||
"Attesting disabled".to_string(),
|
||||
),
|
||||
))
|
||||
.await;
|
||||
}
|
||||
task_spawner
|
||||
.blocking_json_task(Priority::P0, move || {
|
||||
not_synced_filter?;
|
||||
attester_duties::attester_duties(epoch, &indices.0, &chain)
|
||||
})
|
||||
.await
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
@@ -3447,10 +3497,22 @@ pub fn serve<T: BeaconChainTypes>(
|
||||
indices: api_types::ValidatorIndexData,
|
||||
task_spawner: TaskSpawner<T::EthSpec>,
|
||||
chain: Arc<BeaconChain<T>>| {
|
||||
task_spawner.blocking_json_task(Priority::P0, move || {
|
||||
not_synced_filter?;
|
||||
sync_committees::sync_committee_duties(epoch, &indices.0, &chain)
|
||||
})
|
||||
async move {
|
||||
if chain.config.disable_attesting {
|
||||
return convert_rejection::<Response<String>>(Err(
|
||||
warp_utils::reject::custom_bad_request(
|
||||
"Attesting disabled".to_string(),
|
||||
),
|
||||
))
|
||||
.await;
|
||||
}
|
||||
task_spawner
|
||||
.blocking_json_task(Priority::P0, move || {
|
||||
not_synced_filter?;
|
||||
sync_committees::sync_committee_duties(epoch, &indices.0, &chain)
|
||||
})
|
||||
.await
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
@@ -3468,23 +3530,35 @@ pub fn serve<T: BeaconChainTypes>(
|
||||
not_synced_filter: Result<(), Rejection>,
|
||||
task_spawner: TaskSpawner<T::EthSpec>,
|
||||
chain: Arc<BeaconChain<T>>| {
|
||||
task_spawner.blocking_json_task(Priority::P0, move || {
|
||||
not_synced_filter?;
|
||||
chain
|
||||
.get_aggregated_sync_committee_contribution(&sync_committee_data)
|
||||
.map_err(|e| {
|
||||
warp_utils::reject::custom_bad_request(format!(
|
||||
"unable to fetch sync contribution: {:?}",
|
||||
e
|
||||
))
|
||||
})?
|
||||
.map(api_types::GenericResponse::from)
|
||||
.ok_or_else(|| {
|
||||
warp_utils::reject::custom_not_found(
|
||||
"no matching sync contribution found".to_string(),
|
||||
)
|
||||
async move {
|
||||
if chain.config.disable_attesting {
|
||||
return convert_rejection::<Response<String>>(Err(
|
||||
warp_utils::reject::custom_bad_request(
|
||||
"Attesting disabled".to_string(),
|
||||
),
|
||||
))
|
||||
.await;
|
||||
}
|
||||
task_spawner
|
||||
.blocking_json_task(Priority::P0, move || {
|
||||
not_synced_filter?;
|
||||
chain
|
||||
.get_aggregated_sync_committee_contribution(&sync_committee_data)
|
||||
.map_err(|e| {
|
||||
warp_utils::reject::custom_bad_request(format!(
|
||||
"unable to fetch sync contribution: {:?}",
|
||||
e
|
||||
))
|
||||
})?
|
||||
.map(api_types::GenericResponse::from)
|
||||
.ok_or_else(|| {
|
||||
warp_utils::reject::custom_not_found(
|
||||
"no matching sync contribution found".to_string(),
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
.await
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
@@ -3509,6 +3583,15 @@ pub fn serve<T: BeaconChainTypes>(
|
||||
chain: Arc<BeaconChain<T>>,
|
||||
aggregates: Vec<SignedAggregateAndProof<T::EthSpec>>,
|
||||
network_tx: UnboundedSender<NetworkMessage<T::EthSpec>>, log: Logger| {
|
||||
async move {
|
||||
if chain.config.disable_attesting {
|
||||
return convert_rejection::<Response<String>>(Err(
|
||||
warp_utils::reject::custom_bad_request(
|
||||
"Attesting disabled".to_string(),
|
||||
),
|
||||
))
|
||||
.await;
|
||||
}
|
||||
task_spawner.blocking_json_task(Priority::P0, move || {
|
||||
not_synced_filter?;
|
||||
let seen_timestamp = timestamp_now();
|
||||
@@ -3604,7 +3687,8 @@ pub fn serve<T: BeaconChainTypes>(
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
})
|
||||
}).await
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
@@ -3625,36 +3709,58 @@ pub fn serve<T: BeaconChainTypes>(
|
||||
contributions: Vec<SignedContributionAndProof<T::EthSpec>>,
|
||||
network_tx: UnboundedSender<NetworkMessage<T::EthSpec>>,
|
||||
log: Logger| {
|
||||
task_spawner.blocking_json_task(Priority::P0, move || {
|
||||
not_synced_filter?;
|
||||
sync_committees::process_signed_contribution_and_proofs(
|
||||
contributions,
|
||||
network_tx,
|
||||
&chain,
|
||||
log,
|
||||
)?;
|
||||
Ok(api_types::GenericResponse::from(()))
|
||||
})
|
||||
async move {
|
||||
if chain.config.disable_attesting {
|
||||
return convert_rejection::<Response<String>>(Err(
|
||||
warp_utils::reject::custom_bad_request(
|
||||
"Attesting disabled".to_string(),
|
||||
),
|
||||
))
|
||||
.await;
|
||||
}
|
||||
task_spawner
|
||||
.blocking_json_task(Priority::P0, move || {
|
||||
not_synced_filter?;
|
||||
sync_committees::process_signed_contribution_and_proofs(
|
||||
contributions,
|
||||
network_tx,
|
||||
&chain,
|
||||
log,
|
||||
)?;
|
||||
Ok(api_types::GenericResponse::from(()))
|
||||
})
|
||||
.await
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
// POST validator/beacon_committee_subscriptions
|
||||
let post_validator_beacon_committee_subscriptions = eth_v1
|
||||
.and(warp::path("validator"))
|
||||
.and(warp::path("beacon_committee_subscriptions"))
|
||||
.and(warp::path::end())
|
||||
.and(warp_utils::json::json())
|
||||
.and(validator_subscription_tx_filter.clone())
|
||||
.and(task_spawner_filter.clone())
|
||||
.and(chain_filter.clone())
|
||||
.and(log_filter.clone())
|
||||
.then(
|
||||
|subscriptions: Vec<api_types::BeaconCommitteeSubscription>,
|
||||
validator_subscription_tx: Sender<ValidatorSubscriptionMessage>,
|
||||
task_spawner: TaskSpawner<T::EthSpec>,
|
||||
chain: Arc<BeaconChain<T>>,
|
||||
log: Logger| {
|
||||
task_spawner.blocking_json_task(Priority::P0, move || {
|
||||
let post_validator_beacon_committee_subscriptions =
|
||||
eth_v1
|
||||
.and(warp::path("validator"))
|
||||
.and(warp::path("beacon_committee_subscriptions"))
|
||||
.and(warp::path::end())
|
||||
.and(warp_utils::json::json())
|
||||
.and(validator_subscription_tx_filter.clone())
|
||||
.and(task_spawner_filter.clone())
|
||||
.and(chain_filter.clone())
|
||||
.and(log_filter.clone())
|
||||
.then(
|
||||
|subscriptions: Vec<api_types::BeaconCommitteeSubscription>,
|
||||
validator_subscription_tx: Sender<ValidatorSubscriptionMessage>,
|
||||
task_spawner: TaskSpawner<T::EthSpec>,
|
||||
chain: Arc<BeaconChain<T>>,
|
||||
log: Logger| {
|
||||
async move {
|
||||
if chain.config.disable_attesting {
|
||||
return convert_rejection::<Response<String>>(Err(
|
||||
warp_utils::reject::custom_bad_request(
|
||||
"Attesting disabled".to_string(),
|
||||
),
|
||||
))
|
||||
.await;
|
||||
}
|
||||
task_spawner.blocking_json_task(Priority::P0, move || {
|
||||
let subscriptions: std::collections::BTreeSet<_> = subscriptions
|
||||
.iter()
|
||||
.map(|subscription| {
|
||||
@@ -3686,9 +3792,10 @@ pub fn serve<T: BeaconChainTypes>(
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})
|
||||
},
|
||||
);
|
||||
}).await
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
// POST validator/prepare_beacon_proposer
|
||||
let post_validator_prepare_beacon_proposer = eth_v1
|
||||
@@ -3945,6 +4052,15 @@ pub fn serve<T: BeaconChainTypes>(
|
||||
chain: Arc<BeaconChain<T>>,
|
||||
log: Logger
|
||||
| {
|
||||
async move {
|
||||
if chain.config.disable_attesting {
|
||||
return convert_rejection::<Response<String>>(Err(
|
||||
warp_utils::reject::custom_bad_request(
|
||||
"Attesting disabled".to_string(),
|
||||
),
|
||||
))
|
||||
.await;
|
||||
}
|
||||
task_spawner.blocking_json_task(Priority::P0, move || {
|
||||
for subscription in subscriptions {
|
||||
chain
|
||||
@@ -3969,7 +4085,8 @@ pub fn serve<T: BeaconChainTypes>(
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})
|
||||
}).await
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
@@ -4422,6 +4539,34 @@ pub fn serve<T: BeaconChainTypes>(
|
||||
},
|
||||
);
|
||||
|
||||
let post_lighthouse_fork_choice_invalidate = warp::path("lighthouse")
|
||||
.and(warp::path("fork_choice"))
|
||||
.and(warp::path("invalidate"))
|
||||
.and(warp::path::end())
|
||||
.and(task_spawner_filter.clone())
|
||||
.and(chain_filter.clone())
|
||||
.and(warp_utils::json::json())
|
||||
.then(
|
||||
|task_spawner: TaskSpawner<T::EthSpec>,
|
||||
chain: Arc<BeaconChain<T>>,
|
||||
block_root: Hash256| {
|
||||
task_spawner.blocking_json_task(Priority::P0, move || {
|
||||
let invalidation =
|
||||
proto_array::InvalidationOperation::InvalidateOne { block_root };
|
||||
chain
|
||||
.canonical_head
|
||||
.fork_choice_write_lock()
|
||||
.on_invalid_execution_payload(&invalidation)
|
||||
.map_err(|e| {
|
||||
warp_utils::reject::custom_server_error(format!(
|
||||
"not invalidated due to error: {e:?}"
|
||||
))
|
||||
})?;
|
||||
Ok("invalidated")
|
||||
})
|
||||
},
|
||||
);
|
||||
|
||||
// GET lighthouse/analysis/block_rewards
|
||||
let get_lighthouse_block_rewards = warp::path("lighthouse")
|
||||
.and(warp::path("analysis"))
|
||||
@@ -4783,6 +4928,7 @@ pub fn serve<T: BeaconChainTypes>(
|
||||
.uor(post_validator_liveness_epoch)
|
||||
.uor(post_lighthouse_liveness)
|
||||
.uor(post_lighthouse_database_reconstruct)
|
||||
.uor(post_lighthouse_fork_choice_invalidate)
|
||||
.uor(post_lighthouse_block_rewards)
|
||||
.uor(post_lighthouse_ui_validator_metrics)
|
||||
.uor(post_lighthouse_ui_validator_info)
|
||||
|
||||
@@ -1457,6 +1457,7 @@ impl<T: BeaconChainTypes> NetworkBeaconProcessor<T> {
|
||||
| Err(e @ BlockError::InconsistentFork(_))
|
||||
| Err(e @ BlockError::ExecutionPayloadError(_))
|
||||
| Err(e @ BlockError::ParentExecutionPayloadInvalid { .. })
|
||||
| Err(e @ BlockError::KnownInvalidExecutionPayload(_))
|
||||
| Err(e @ BlockError::GenesisBlock) => {
|
||||
warn!(self.log, "Could not verify block for gossip. Rejecting the block";
|
||||
"error" => %e);
|
||||
|
||||
@@ -800,6 +800,18 @@ impl<T: BeaconChainTypes> NetworkBeaconProcessor<T> {
|
||||
peer_action: Some(PeerAction::LowToleranceError),
|
||||
})
|
||||
}
|
||||
// Penalise peers for sending us banned blocks.
|
||||
BlockError::KnownInvalidExecutionPayload(block_root) => {
|
||||
warn!(
|
||||
self.log,
|
||||
"Received block known to be invalid";
|
||||
"block_root" => ?block_root,
|
||||
);
|
||||
Err(ChainSegmentFailed {
|
||||
message: format!("Banned block: {block_root:?}"),
|
||||
peer_action: Some(PeerAction::LowToleranceError),
|
||||
})
|
||||
}
|
||||
other => {
|
||||
debug!(
|
||||
self.log, "Invalid block received";
|
||||
|
||||
@@ -553,6 +553,22 @@ pub fn cli_app() -> Command {
|
||||
.action(ArgAction::Set)
|
||||
.display_order(0)
|
||||
)
|
||||
.arg(
|
||||
Arg::new("disable-attesting")
|
||||
.long("disable-attesting")
|
||||
.help("Turn off attestation related APIs so that we have some hope of producing \
|
||||
blocks")
|
||||
.action(ArgAction::SetTrue)
|
||||
.display_order(0)
|
||||
)
|
||||
.arg(
|
||||
Arg::new("sync-tolerance-epochs")
|
||||
.long("sync-tolerance-epochs")
|
||||
.help("If the beacon node is within this many epochs from the head, we declare it to \
|
||||
be synced regardless of the network sync state")
|
||||
.action(ArgAction::Set)
|
||||
.display_order(0)
|
||||
)
|
||||
.arg(
|
||||
Arg::new("http-sse-capacity-multiplier")
|
||||
.long("http-sse-capacity-multiplier")
|
||||
|
||||
@@ -191,6 +191,16 @@ pub fn get_config<E: EthSpec>(
|
||||
client_config.chain.enable_light_client_server = false;
|
||||
}
|
||||
|
||||
if cli_args.get_flag("disable-attesting") {
|
||||
client_config.chain.disable_attesting = true;
|
||||
}
|
||||
|
||||
if let Some(sync_tolerance_epochs) =
|
||||
clap_utils::parse_optional(cli_args, "sync-tolerance-epochs")?
|
||||
{
|
||||
client_config.chain.sync_tolerance_epochs = sync_tolerance_epochs;
|
||||
}
|
||||
|
||||
if let Some(cache_size) = clap_utils::parse_optional(cli_args, "shuffling-cache-size")? {
|
||||
client_config.chain.shuffling_cache_size = cache_size;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "boot_node"
|
||||
version = "7.0.0-beta.0"
|
||||
version = "7.0.0-beta.1"
|
||||
authors = ["Sigma Prime <contact@sigmaprime.io>"]
|
||||
edition = { workspace = true }
|
||||
|
||||
|
||||
@@ -17,8 +17,8 @@ pub const VERSION: &str = git_version!(
|
||||
// NOTE: using --match instead of --exclude for compatibility with old Git
|
||||
"--match=thiswillnevermatchlol"
|
||||
],
|
||||
prefix = "Lighthouse/v7.0.0-beta.0-",
|
||||
fallback = "Lighthouse/v7.0.0-beta.0"
|
||||
prefix = "Lighthouse/v7.0.0-beta.1-",
|
||||
fallback = "Lighthouse/v7.0.0-beta.1"
|
||||
);
|
||||
|
||||
/// Returns the first eight characters of the latest commit hash for this build.
|
||||
@@ -54,7 +54,7 @@ pub fn version_with_platform() -> String {
|
||||
///
|
||||
/// `1.5.1`
|
||||
pub fn version() -> &'static str {
|
||||
"7.0.0-beta.0"
|
||||
"7.0.0-beta.1"
|
||||
}
|
||||
|
||||
/// Returns the name of the current client running.
|
||||
|
||||
@@ -531,15 +531,7 @@ impl ProtoArray {
|
||||
|| latest_valid_ancestor_is_descendant
|
||||
{
|
||||
match &node.execution_status {
|
||||
// It's illegal for an execution client to declare that some previously-valid block
|
||||
// is now invalid. This is a consensus failure on their behalf.
|
||||
ExecutionStatus::Valid(hash) => {
|
||||
return Err(Error::ValidExecutionStatusBecameInvalid {
|
||||
block_root: node.root,
|
||||
payload_block_hash: *hash,
|
||||
})
|
||||
}
|
||||
ExecutionStatus::Optimistic(hash) => {
|
||||
ExecutionStatus::Valid(hash) | ExecutionStatus::Optimistic(hash) => {
|
||||
invalidated_indices.insert(index);
|
||||
node.execution_status = ExecutionStatus::Invalid(*hash);
|
||||
|
||||
@@ -597,13 +589,9 @@ impl ProtoArray {
|
||||
if let Some(parent_index) = node.parent {
|
||||
if invalidated_indices.contains(&parent_index) {
|
||||
match &node.execution_status {
|
||||
ExecutionStatus::Valid(hash) => {
|
||||
return Err(Error::ValidExecutionStatusBecameInvalid {
|
||||
block_root: node.root,
|
||||
payload_block_hash: *hash,
|
||||
})
|
||||
}
|
||||
ExecutionStatus::Optimistic(hash) | ExecutionStatus::Invalid(hash) => {
|
||||
ExecutionStatus::Valid(hash)
|
||||
| ExecutionStatus::Optimistic(hash)
|
||||
| ExecutionStatus::Invalid(hash) => {
|
||||
node.execution_status = ExecutionStatus::Invalid(*hash)
|
||||
}
|
||||
ExecutionStatus::Irrelevant(_) => {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "lcli"
|
||||
description = "Lighthouse CLI (modeled after zcli)"
|
||||
version = "7.0.0-beta.0"
|
||||
version = "7.0.0-beta.1"
|
||||
authors = ["Paul Hauner <paul@paulhauner.com>"]
|
||||
edition = { workspace = true }
|
||||
|
||||
|
||||
@@ -2,7 +2,9 @@ use clap::ArgMatches;
|
||||
use clap_utils::{parse_optional, parse_required};
|
||||
use environment::Environment;
|
||||
use eth2::{
|
||||
types::{BlockId, ChainSpec, ForkName, PublishBlockRequest, SignedBlockContents},
|
||||
types::{
|
||||
BlockId, BroadcastValidation, ChainSpec, ForkName, PublishBlockRequest, SignedBlockContents,
|
||||
},
|
||||
BeaconNodeHttpClient, Error, SensitiveUrl, Timeouts,
|
||||
};
|
||||
use eth2_network_config::Eth2NetworkConfig;
|
||||
@@ -85,7 +87,10 @@ pub async fn run_async<T: EthSpec>(
|
||||
// 2. Apply blocks to target.
|
||||
for (slot, block) in blocks.iter().rev() {
|
||||
println!("posting block at slot {slot}");
|
||||
if let Err(e) = target.post_beacon_blocks(block).await {
|
||||
if let Err(e) = target
|
||||
.post_beacon_blocks_v2(block, Some(BroadcastValidation::Consensus))
|
||||
.await
|
||||
{
|
||||
if let Error::ServerMessage(ref e) = e {
|
||||
if e.code == 202 {
|
||||
println!("duplicate block detected while posting block at slot {slot}");
|
||||
@@ -115,7 +120,7 @@ async fn get_block_from_source<T: EthSpec>(
|
||||
let mut f = File::open(&cache_path).unwrap();
|
||||
let mut bytes = vec![];
|
||||
f.read_to_end(&mut bytes).unwrap();
|
||||
PublishBlockRequest::from_ssz_bytes(&bytes, ForkName::Deneb).unwrap()
|
||||
PublishBlockRequest::from_ssz_bytes(&bytes, ForkName::Electra).unwrap()
|
||||
} else {
|
||||
let block_from_source = source
|
||||
.get_beacon_blocks_ssz::<T>(block_id, spec)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "lighthouse"
|
||||
version = "7.0.0-beta.0"
|
||||
version = "7.0.0-beta.1"
|
||||
authors = ["Sigma Prime <contact@sigmaprime.io>"]
|
||||
edition = { workspace = true }
|
||||
autotests = false
|
||||
|
||||
@@ -2579,6 +2579,16 @@ fn light_client_http_server_disabled() {
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn disable_attesting() {
|
||||
CommandLineTest::new()
|
||||
.flag("disable-attesting", None)
|
||||
.run_with_zero_port()
|
||||
.with_config(|config| {
|
||||
assert!(config.chain.disable_attesting);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gui_flag() {
|
||||
CommandLineTest::new()
|
||||
|
||||
@@ -97,6 +97,14 @@ pub struct ValidatorClient {
|
||||
)]
|
||||
pub disable_auto_discover: bool,
|
||||
|
||||
#[clap(
|
||||
long,
|
||||
help = "Disable everything except block proposals",
|
||||
display_order = 0,
|
||||
help_heading = FLAG_HEADER
|
||||
)]
|
||||
pub disable_attesting: bool,
|
||||
|
||||
#[clap(
|
||||
long,
|
||||
help = "If present, the validator client will use longer timeouts for requests \
|
||||
|
||||
@@ -85,6 +85,7 @@ pub struct Config {
|
||||
/// Configuration for the initialized validators
|
||||
#[serde(flatten)]
|
||||
pub initialized_validators: InitializedValidatorsConfig,
|
||||
pub disable_attesting: bool,
|
||||
}
|
||||
|
||||
impl Default for Config {
|
||||
@@ -126,6 +127,7 @@ impl Default for Config {
|
||||
validator_registration_batch_size: 500,
|
||||
distributed: false,
|
||||
initialized_validators: <_>::default(),
|
||||
disable_attesting: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -379,6 +381,8 @@ impl Config {
|
||||
true
|
||||
};
|
||||
|
||||
config.disable_attesting = validator_client_config.disable_attesting;
|
||||
|
||||
Ok(config)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -325,7 +325,7 @@ impl<E: EthSpec> ProductionValidatorClient<E> {
|
||||
get_validator_block: slot_duration / HTTP_GET_VALIDATOR_BLOCK_TIMEOUT_QUOTIENT,
|
||||
}
|
||||
} else {
|
||||
Timeouts::set_all(slot_duration)
|
||||
Timeouts::set_all(25 * slot_duration)
|
||||
};
|
||||
|
||||
Ok(BeaconNodeHttpClient::from_components(
|
||||
@@ -478,6 +478,7 @@ impl<E: EthSpec> ProductionValidatorClient<E> {
|
||||
context: duties_context,
|
||||
enable_high_validator_count_metrics: config.enable_high_validator_count_metrics,
|
||||
distributed: config.distributed,
|
||||
disable_attesting: config.disable_attesting,
|
||||
});
|
||||
|
||||
// Update the metrics server.
|
||||
@@ -507,6 +508,7 @@ impl<E: EthSpec> ProductionValidatorClient<E> {
|
||||
.validator_store(validator_store.clone())
|
||||
.beacon_nodes(beacon_nodes.clone())
|
||||
.runtime_context(context.service_context("attestation".into()))
|
||||
.disable(config.disable_attesting)
|
||||
.build()?;
|
||||
|
||||
let preparation_service = PreparationServiceBuilder::new()
|
||||
|
||||
@@ -21,6 +21,7 @@ pub struct AttestationServiceBuilder<T: SlotClock + 'static, E: EthSpec> {
|
||||
slot_clock: Option<T>,
|
||||
beacon_nodes: Option<Arc<BeaconNodeFallback<T, E>>>,
|
||||
context: Option<RuntimeContext<E>>,
|
||||
disable: bool,
|
||||
}
|
||||
|
||||
impl<T: SlotClock + 'static, E: EthSpec> AttestationServiceBuilder<T, E> {
|
||||
@@ -31,6 +32,7 @@ impl<T: SlotClock + 'static, E: EthSpec> AttestationServiceBuilder<T, E> {
|
||||
slot_clock: None,
|
||||
beacon_nodes: None,
|
||||
context: None,
|
||||
disable: false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,6 +61,11 @@ impl<T: SlotClock + 'static, E: EthSpec> AttestationServiceBuilder<T, E> {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn disable(mut self, disable: bool) -> Self {
|
||||
self.disable = disable;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build(self) -> Result<AttestationService<T, E>, String> {
|
||||
Ok(AttestationService {
|
||||
inner: Arc::new(Inner {
|
||||
@@ -77,6 +84,7 @@ impl<T: SlotClock + 'static, E: EthSpec> AttestationServiceBuilder<T, E> {
|
||||
context: self
|
||||
.context
|
||||
.ok_or("Cannot build AttestationService without runtime_context")?,
|
||||
disable: self.disable,
|
||||
}),
|
||||
})
|
||||
}
|
||||
@@ -89,6 +97,7 @@ pub struct Inner<T, E: EthSpec> {
|
||||
slot_clock: T,
|
||||
beacon_nodes: Arc<BeaconNodeFallback<T, E>>,
|
||||
context: RuntimeContext<E>,
|
||||
disable: bool,
|
||||
}
|
||||
|
||||
/// Attempts to produce attestations for all known validators 1/3rd of the way through each slot.
|
||||
@@ -120,6 +129,10 @@ impl<T: SlotClock + 'static, E: EthSpec> AttestationService<T, E> {
|
||||
/// Starts the service which periodically produces attestations.
|
||||
pub fn start_update_service(self, spec: &ChainSpec) -> Result<(), String> {
|
||||
let log = self.context.log().clone();
|
||||
if self.disable {
|
||||
info!(log, "Attestation service disabled");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let slot_duration = Duration::from_secs(spec.seconds_per_slot);
|
||||
let duration_to_next_slot = self
|
||||
|
||||
@@ -230,6 +230,7 @@ pub struct DutiesService<T, E: EthSpec> {
|
||||
pub enable_high_validator_count_metrics: bool,
|
||||
/// If this validator is running in distributed mode.
|
||||
pub distributed: bool,
|
||||
pub disable_attesting: bool,
|
||||
}
|
||||
|
||||
impl<T: SlotClock + 'static, E: EthSpec> DutiesService<T, E> {
|
||||
@@ -403,6 +404,11 @@ pub fn start_update_service<T: SlotClock + 'static, E: EthSpec>(
|
||||
"duties_service_proposers",
|
||||
);
|
||||
|
||||
// Skip starting attestation duties or sync committee services.
|
||||
if core_duties_service.disable_attesting {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Spawn the task which keeps track of local attestation duties.
|
||||
*/
|
||||
|
||||
@@ -87,6 +87,11 @@ impl<T: SlotClock + 'static, E: EthSpec> SyncCommitteeService<T, E> {
|
||||
|
||||
pub fn start_update_service(self, spec: &ChainSpec) -> Result<(), String> {
|
||||
let log = self.context.log().clone();
|
||||
if self.duties_service.disable_attesting {
|
||||
info!(log, "Sync committee service disabled");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let slot_duration = Duration::from_secs(spec.seconds_per_slot);
|
||||
let duration_to_next_slot = self
|
||||
.slot_clock
|
||||
|
||||
Reference in New Issue
Block a user