Merge branch 'unstable' into eip4844
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "beacon_node"
|
||||
version = "4.0.1"
|
||||
version = "4.1.0"
|
||||
authors = ["Paul Hauner <paul@paulhauner.com>", "Age Manning <Age@AgeManning.com"]
|
||||
edition = "2021"
|
||||
|
||||
|
||||
@@ -110,7 +110,6 @@ use tokio_stream::Stream;
|
||||
use tree_hash::TreeHash;
|
||||
use types::beacon_state::CloneConfig;
|
||||
use types::consts::eip4844::MIN_EPOCHS_FOR_BLOBS_SIDECARS_REQUESTS;
|
||||
use types::consts::merge::INTERVALS_PER_SLOT;
|
||||
use types::*;
|
||||
|
||||
pub type ForkChoiceError = fork_choice::Error<crate::ForkChoiceStoreError>;
|
||||
@@ -132,12 +131,6 @@ pub const VALIDATOR_PUBKEY_CACHE_LOCK_TIMEOUT: Duration = Duration::from_secs(1)
|
||||
/// The timeout for the eth1 finalization cache
|
||||
pub const ETH1_FINALIZATION_CACHE_LOCK_TIMEOUT: Duration = Duration::from_millis(200);
|
||||
|
||||
/// The latest delay from the start of the slot at which to attempt a 1-slot re-org.
|
||||
fn max_re_org_slot_delay(seconds_per_slot: u64) -> Duration {
|
||||
// Allow at least half of the attestation deadline for the block to propagate.
|
||||
Duration::from_secs(seconds_per_slot) / INTERVALS_PER_SLOT as u32 / 2
|
||||
}
|
||||
|
||||
// These keys are all zero because they get stored in different columns, see `DBColumn` type.
|
||||
pub const BEACON_CHAIN_DB_KEY: Hash256 = Hash256::zero();
|
||||
pub const OP_POOL_DB_KEY: Hash256 = Hash256::zero();
|
||||
@@ -363,7 +356,7 @@ pub struct BeaconChain<T: BeaconChainTypes> {
|
||||
/// in recent epochs.
|
||||
pub(crate) observed_sync_aggregators: RwLock<ObservedSyncAggregators<T::EthSpec>>,
|
||||
/// Maintains a record of which validators have proposed blocks for each slot.
|
||||
pub(crate) observed_block_producers: RwLock<ObservedBlockProducers<T::EthSpec>>,
|
||||
pub observed_block_producers: RwLock<ObservedBlockProducers<T::EthSpec>>,
|
||||
/// Maintains a record of which validators have submitted voluntary exits.
|
||||
pub(crate) observed_voluntary_exits: Mutex<ObservedOperations<SignedVoluntaryExit, T::EthSpec>>,
|
||||
/// Maintains a record of which validators we've seen proposer slashings for.
|
||||
@@ -1090,7 +1083,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
.execution_layer
|
||||
.as_ref()
|
||||
.ok_or(Error::ExecutionLayerMissing)?
|
||||
.get_payload_by_block_hash(exec_block_hash, fork)
|
||||
.get_payload_for_header(&execution_payload_header, fork)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
Error::ExecutionLayerErrorPayloadReconstruction(exec_block_hash, Box::new(e))
|
||||
@@ -2299,12 +2292,14 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
&self,
|
||||
exit: SignedVoluntaryExit,
|
||||
) -> Result<ObservationOutcome<SignedVoluntaryExit, T::EthSpec>, Error> {
|
||||
// NOTE: this could be more efficient if it avoided cloning the head state
|
||||
let wall_clock_state = self.wall_clock_state()?;
|
||||
let head_snapshot = self.head().snapshot;
|
||||
let head_state = &head_snapshot.beacon_state;
|
||||
let wall_clock_epoch = self.epoch()?;
|
||||
|
||||
Ok(self
|
||||
.observed_voluntary_exits
|
||||
.lock()
|
||||
.verify_and_observe(exit, &wall_clock_state, &self.spec)
|
||||
.verify_and_observe_at(exit, wall_clock_epoch, head_state, &self.spec)
|
||||
.map(|exit| {
|
||||
// this method is called for both API and gossip exits, so this covers all exit events
|
||||
if let Some(event_handler) = self.event_handler.as_ref() {
|
||||
@@ -3733,7 +3728,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
let (state, state_root_opt) = self
|
||||
.task_executor
|
||||
.spawn_blocking_handle(
|
||||
move || chain.load_state_for_block_production::<Payload>(slot),
|
||||
move || chain.load_state_for_block_production(slot),
|
||||
"produce_partial_beacon_block",
|
||||
)
|
||||
.ok_or(BlockProductionError::ShuttingDown)?
|
||||
@@ -3756,7 +3751,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
|
||||
/// Load a beacon state from the database for block production. This is a long-running process
|
||||
/// that should not be performed in an `async` context.
|
||||
fn load_state_for_block_production<Payload: ExecPayload<T::EthSpec>>(
|
||||
fn load_state_for_block_production(
|
||||
self: &Arc<Self>,
|
||||
slot: Slot,
|
||||
) -> Result<(BeaconState<T::EthSpec>, Option<Hash256>), BlockProductionError> {
|
||||
@@ -3870,7 +3865,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
// 1. It seems we have time to propagate and still receive the proposer boost.
|
||||
// 2. The current head block was seen late.
|
||||
// 3. The `get_proposer_head` conditions from fork choice pass.
|
||||
let proposing_on_time = slot_delay < max_re_org_slot_delay(self.spec.seconds_per_slot);
|
||||
let proposing_on_time = slot_delay < self.config.re_org_cutoff(self.spec.seconds_per_slot);
|
||||
if !proposing_on_time {
|
||||
debug!(
|
||||
self.log,
|
||||
@@ -3900,6 +3895,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
slot,
|
||||
canonical_head,
|
||||
re_org_threshold,
|
||||
&self.config.re_org_disallowed_offsets,
|
||||
self.config.re_org_max_epochs_since_finalization,
|
||||
)
|
||||
.map_err(|e| match e {
|
||||
@@ -4178,6 +4174,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
.get_preliminary_proposer_head(
|
||||
head_block_root,
|
||||
re_org_threshold,
|
||||
&self.config.re_org_disallowed_offsets,
|
||||
self.config.re_org_max_epochs_since_finalization,
|
||||
)
|
||||
.map_err(|e| e.map_inner_error(Error::ProposerHeadForkChoiceError))?;
|
||||
@@ -4188,7 +4185,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
let re_org_block_slot = head_slot + 1;
|
||||
let fork_choice_slot = info.current_slot;
|
||||
|
||||
// If a re-orging proposal isn't made by the `max_re_org_slot_delay` then we give up
|
||||
// If a re-orging proposal isn't made by the `re_org_cutoff` then we give up
|
||||
// and allow the fork choice update for the canonical head through so that we may attest
|
||||
// correctly.
|
||||
let current_slot_ok = if head_slot == fork_choice_slot {
|
||||
@@ -4199,7 +4196,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
.and_then(|slot_start| {
|
||||
let now = self.slot_clock.now_duration()?;
|
||||
let slot_delay = now.saturating_sub(slot_start);
|
||||
Some(slot_delay <= max_re_org_slot_delay(self.spec.seconds_per_slot))
|
||||
Some(slot_delay <= self.config.re_org_cutoff(self.spec.seconds_per_slot))
|
||||
})
|
||||
.unwrap_or(false)
|
||||
} else {
|
||||
|
||||
@@ -24,7 +24,7 @@ use futures::channel::mpsc::Sender;
|
||||
use kzg::{Kzg, TrustedSetup};
|
||||
use operation_pool::{OperationPool, PersistedOperationPool};
|
||||
use parking_lot::RwLock;
|
||||
use proto_array::ReOrgThreshold;
|
||||
use proto_array::{DisallowedReOrgOffsets, ReOrgThreshold};
|
||||
use slasher::Slasher;
|
||||
use slog::{crit, error, info, Logger};
|
||||
use slot_clock::{SlotClock, TestingSlotClock};
|
||||
@@ -179,6 +179,15 @@ where
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the proposer re-org disallowed offsets list.
|
||||
pub fn proposer_re_org_disallowed_offsets(
|
||||
mut self,
|
||||
disallowed_offsets: DisallowedReOrgOffsets,
|
||||
) -> Self {
|
||||
self.chain_config.re_org_disallowed_offsets = disallowed_offsets;
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the store (database).
|
||||
///
|
||||
/// Should generally be called early in the build chain.
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
pub use proto_array::ReOrgThreshold;
|
||||
pub use proto_array::{DisallowedReOrgOffsets, ReOrgThreshold};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std::time::Duration;
|
||||
use types::{Checkpoint, Epoch};
|
||||
|
||||
pub const DEFAULT_RE_ORG_THRESHOLD: ReOrgThreshold = ReOrgThreshold(20);
|
||||
pub const DEFAULT_RE_ORG_MAX_EPOCHS_SINCE_FINALIZATION: Epoch = Epoch::new(2);
|
||||
/// Default to 1/12th of the slot, which is 1 second on mainnet.
|
||||
pub const DEFAULT_RE_ORG_CUTOFF_DENOMINATOR: u32 = 12;
|
||||
pub const DEFAULT_FORK_CHOICE_BEFORE_PROPOSAL_TIMEOUT: u64 = 250;
|
||||
|
||||
/// Default fraction of a slot lookahead for payload preparation (12/3 = 4 seconds on mainnet).
|
||||
@@ -34,6 +36,13 @@ pub struct ChainConfig {
|
||||
pub re_org_threshold: Option<ReOrgThreshold>,
|
||||
/// Maximum number of epochs since finalization for attempting a proposer re-org.
|
||||
pub re_org_max_epochs_since_finalization: Epoch,
|
||||
/// Maximum delay after the start of the slot at which to propose a reorging block.
|
||||
pub re_org_cutoff_millis: Option<u64>,
|
||||
/// Additional epoch offsets at which re-orging block proposals are not permitted.
|
||||
///
|
||||
/// By default this list is empty, but it can be useful for reacting to network conditions, e.g.
|
||||
/// slow gossip of re-org blocks at slot 1 in the epoch.
|
||||
pub re_org_disallowed_offsets: DisallowedReOrgOffsets,
|
||||
/// Number of milliseconds to wait for fork choice before proposing a block.
|
||||
///
|
||||
/// If set to 0 then block proposal will not wait for fork choice at all.
|
||||
@@ -82,6 +91,8 @@ impl Default for ChainConfig {
|
||||
max_network_size: 10 * 1_048_576, // 10M
|
||||
re_org_threshold: Some(DEFAULT_RE_ORG_THRESHOLD),
|
||||
re_org_max_epochs_since_finalization: DEFAULT_RE_ORG_MAX_EPOCHS_SINCE_FINALIZATION,
|
||||
re_org_cutoff_millis: None,
|
||||
re_org_disallowed_offsets: DisallowedReOrgOffsets::default(),
|
||||
fork_choice_before_proposal_timeout_ms: DEFAULT_FORK_CHOICE_BEFORE_PROPOSAL_TIMEOUT,
|
||||
// Builder fallback configs that are set in `clap` will override these.
|
||||
builder_fallback_skips: 3,
|
||||
@@ -100,3 +111,14 @@ impl Default for ChainConfig {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ChainConfig {
|
||||
/// The latest delay from the start of the slot at which to attempt a 1-slot re-org.
|
||||
pub fn re_org_cutoff(&self, seconds_per_slot: u64) -> Duration {
|
||||
self.re_org_cutoff_millis
|
||||
.map(Duration::from_millis)
|
||||
.unwrap_or_else(|| {
|
||||
Duration::from_secs(seconds_per_slot) / DEFAULT_RE_ORG_CUTOFF_DENOMINATOR
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@ fn get_sync_status<T: EthSpec>(
|
||||
let period = T::SlotsPerEth1VotingPeriod::to_u64();
|
||||
let voting_period_start_slot = (current_slot / period) * period;
|
||||
|
||||
let period_start = slot_start_seconds::<T>(
|
||||
let period_start = slot_start_seconds(
|
||||
genesis_time,
|
||||
spec.seconds_per_slot,
|
||||
voting_period_start_slot,
|
||||
@@ -470,7 +470,7 @@ impl<T: EthSpec> Eth1ChainBackend<T> for CachingEth1Backend<T> {
|
||||
fn eth1_data(&self, state: &BeaconState<T>, spec: &ChainSpec) -> Result<Eth1Data, Error> {
|
||||
let period = T::SlotsPerEth1VotingPeriod::to_u64();
|
||||
let voting_period_start_slot = (state.slot() / period) * period;
|
||||
let voting_period_start_seconds = slot_start_seconds::<T>(
|
||||
let voting_period_start_seconds = slot_start_seconds(
|
||||
state.genesis_time(),
|
||||
spec.seconds_per_slot,
|
||||
voting_period_start_slot,
|
||||
@@ -658,11 +658,7 @@ fn find_winning_vote(valid_votes: Eth1DataVoteCount) -> Option<Eth1Data> {
|
||||
}
|
||||
|
||||
/// Returns the unix-epoch seconds at the start of the given `slot`.
|
||||
fn slot_start_seconds<T: EthSpec>(
|
||||
genesis_unix_seconds: u64,
|
||||
seconds_per_slot: u64,
|
||||
slot: Slot,
|
||||
) -> u64 {
|
||||
fn slot_start_seconds(genesis_unix_seconds: u64, seconds_per_slot: u64, slot: Slot) -> u64 {
|
||||
genesis_unix_seconds + slot.as_u64() * seconds_per_slot
|
||||
}
|
||||
|
||||
@@ -698,7 +694,7 @@ mod test {
|
||||
fn get_voting_period_start_seconds(state: &BeaconState<E>, spec: &ChainSpec) -> u64 {
|
||||
let period = <E as EthSpec>::SlotsPerEth1VotingPeriod::to_u64();
|
||||
let voting_period_start_slot = (state.slot() / period) * period;
|
||||
slot_start_seconds::<E>(
|
||||
slot_start_seconds(
|
||||
state.genesis_time(),
|
||||
spec.seconds_per_slot,
|
||||
voting_period_start_slot,
|
||||
@@ -708,23 +704,23 @@ mod test {
|
||||
#[test]
|
||||
fn slot_start_time() {
|
||||
let zero_sec = 0;
|
||||
assert_eq!(slot_start_seconds::<E>(100, zero_sec, Slot::new(2)), 100);
|
||||
assert_eq!(slot_start_seconds(100, zero_sec, Slot::new(2)), 100);
|
||||
|
||||
let one_sec = 1;
|
||||
assert_eq!(slot_start_seconds::<E>(100, one_sec, Slot::new(0)), 100);
|
||||
assert_eq!(slot_start_seconds::<E>(100, one_sec, Slot::new(1)), 101);
|
||||
assert_eq!(slot_start_seconds::<E>(100, one_sec, Slot::new(2)), 102);
|
||||
assert_eq!(slot_start_seconds(100, one_sec, Slot::new(0)), 100);
|
||||
assert_eq!(slot_start_seconds(100, one_sec, Slot::new(1)), 101);
|
||||
assert_eq!(slot_start_seconds(100, one_sec, Slot::new(2)), 102);
|
||||
|
||||
let three_sec = 3;
|
||||
assert_eq!(slot_start_seconds::<E>(100, three_sec, Slot::new(0)), 100);
|
||||
assert_eq!(slot_start_seconds::<E>(100, three_sec, Slot::new(1)), 103);
|
||||
assert_eq!(slot_start_seconds::<E>(100, three_sec, Slot::new(2)), 106);
|
||||
assert_eq!(slot_start_seconds(100, three_sec, Slot::new(0)), 100);
|
||||
assert_eq!(slot_start_seconds(100, three_sec, Slot::new(1)), 103);
|
||||
assert_eq!(slot_start_seconds(100, three_sec, Slot::new(2)), 106);
|
||||
|
||||
let five_sec = 5;
|
||||
assert_eq!(slot_start_seconds::<E>(100, five_sec, Slot::new(0)), 100);
|
||||
assert_eq!(slot_start_seconds::<E>(100, five_sec, Slot::new(1)), 105);
|
||||
assert_eq!(slot_start_seconds::<E>(100, five_sec, Slot::new(2)), 110);
|
||||
assert_eq!(slot_start_seconds::<E>(100, five_sec, Slot::new(3)), 115);
|
||||
assert_eq!(slot_start_seconds(100, five_sec, Slot::new(0)), 100);
|
||||
assert_eq!(slot_start_seconds(100, five_sec, Slot::new(1)), 105);
|
||||
assert_eq!(slot_start_seconds(100, five_sec, Slot::new(2)), 110);
|
||||
assert_eq!(slot_start_seconds(100, five_sec, Slot::new(3)), 115);
|
||||
}
|
||||
|
||||
fn get_eth1_block(timestamp: u64, number: u64) -> Eth1Block {
|
||||
|
||||
@@ -35,7 +35,7 @@ pub mod migrate;
|
||||
mod naive_aggregation_pool;
|
||||
mod observed_aggregates;
|
||||
mod observed_attesters;
|
||||
mod observed_block_producers;
|
||||
pub mod observed_block_producers;
|
||||
pub mod observed_operations;
|
||||
pub mod otb_verification_service;
|
||||
mod persisted_beacon_chain;
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
use derivative::Derivative;
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
use ssz::{Decode, Encode};
|
||||
use state_processing::{SigVerifiedOp, VerifyOperation};
|
||||
use state_processing::{SigVerifiedOp, VerifyOperation, VerifyOperationAt};
|
||||
use std::collections::HashSet;
|
||||
use std::marker::PhantomData;
|
||||
use types::{
|
||||
AttesterSlashing, BeaconState, ChainSpec, EthSpec, ForkName, ProposerSlashing,
|
||||
AttesterSlashing, BeaconState, ChainSpec, Epoch, EthSpec, ForkName, ProposerSlashing,
|
||||
SignedBlsToExecutionChange, SignedVoluntaryExit, Slot,
|
||||
};
|
||||
|
||||
@@ -87,12 +87,16 @@ impl<E: EthSpec> ObservableOperation<E> for SignedBlsToExecutionChange {
|
||||
}
|
||||
|
||||
impl<T: ObservableOperation<E>, E: EthSpec> ObservedOperations<T, E> {
|
||||
pub fn verify_and_observe(
|
||||
pub fn verify_and_observe_parametric<F>(
|
||||
&mut self,
|
||||
op: T,
|
||||
validate: F,
|
||||
head_state: &BeaconState<E>,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<ObservationOutcome<T, E>, T::Error> {
|
||||
) -> Result<ObservationOutcome<T, E>, T::Error>
|
||||
where
|
||||
F: Fn(T) -> Result<SigVerifiedOp<T, E>, T::Error>,
|
||||
{
|
||||
self.reset_at_fork_boundary(head_state.slot(), spec);
|
||||
|
||||
let observed_validator_indices = &mut self.observed_validator_indices;
|
||||
@@ -112,7 +116,7 @@ impl<T: ObservableOperation<E>, E: EthSpec> ObservedOperations<T, E> {
|
||||
}
|
||||
|
||||
// Validate the op using operation-specific logic (`verify_attester_slashing`, etc).
|
||||
let verified_op = op.validate(head_state, spec)?;
|
||||
let verified_op = validate(op)?;
|
||||
|
||||
// Add the relevant indices to the set of known indices to prevent processing of duplicates
|
||||
// in the future.
|
||||
@@ -121,6 +125,16 @@ impl<T: ObservableOperation<E>, E: EthSpec> ObservedOperations<T, E> {
|
||||
Ok(ObservationOutcome::New(verified_op))
|
||||
}
|
||||
|
||||
pub fn verify_and_observe(
|
||||
&mut self,
|
||||
op: T,
|
||||
head_state: &BeaconState<E>,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<ObservationOutcome<T, E>, T::Error> {
|
||||
let validate = |op: T| op.validate(head_state, spec);
|
||||
self.verify_and_observe_parametric(op, validate, head_state, spec)
|
||||
}
|
||||
|
||||
/// Reset the cache when crossing a fork boundary.
|
||||
///
|
||||
/// This prevents an attacker from crafting a self-slashing which is only valid before the fork
|
||||
@@ -140,3 +154,16 @@ impl<T: ObservableOperation<E>, E: EthSpec> ObservedOperations<T, E> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ObservableOperation<E> + VerifyOperationAt<E>, E: EthSpec> ObservedOperations<T, E> {
|
||||
pub fn verify_and_observe_at(
|
||||
&mut self,
|
||||
op: T,
|
||||
verify_at_epoch: Epoch,
|
||||
head_state: &BeaconState<E>,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<ObservationOutcome<T, E>, T::Error> {
|
||||
let validate = |op: T| op.validate_at(head_state, verify_at_epoch, spec);
|
||||
self.verify_and_observe_parametric(op, validate, head_state, spec)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,3 +10,4 @@ sensitive_url = { path = "../../common/sensitive_url" }
|
||||
eth2 = { path = "../../common/eth2" }
|
||||
serde = { version = "1.0.116", features = ["derive"] }
|
||||
serde_json = "1.0.58"
|
||||
lighthouse_version = { path = "../../common/lighthouse_version" }
|
||||
|
||||
@@ -17,6 +17,9 @@ pub const DEFAULT_TIMEOUT_MILLIS: u64 = 15000;
|
||||
/// This timeout is in accordance with v0.2.0 of the [builder specs](https://github.com/flashbots/mev-boost/pull/20).
|
||||
pub const DEFAULT_GET_HEADER_TIMEOUT_MILLIS: u64 = 1000;
|
||||
|
||||
/// Default user agent for HTTP requests.
|
||||
pub const DEFAULT_USER_AGENT: &str = lighthouse_version::VERSION;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Timeouts {
|
||||
get_header: Duration,
|
||||
@@ -41,23 +44,23 @@ pub struct BuilderHttpClient {
|
||||
client: reqwest::Client,
|
||||
server: SensitiveUrl,
|
||||
timeouts: Timeouts,
|
||||
user_agent: String,
|
||||
}
|
||||
|
||||
impl BuilderHttpClient {
|
||||
pub fn new(server: SensitiveUrl) -> Result<Self, Error> {
|
||||
pub fn new(server: SensitiveUrl, user_agent: Option<String>) -> Result<Self, Error> {
|
||||
let user_agent = user_agent.unwrap_or(DEFAULT_USER_AGENT.to_string());
|
||||
let client = reqwest::Client::builder().user_agent(&user_agent).build()?;
|
||||
Ok(Self {
|
||||
client: reqwest::Client::new(),
|
||||
client,
|
||||
server,
|
||||
timeouts: Timeouts::default(),
|
||||
user_agent,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn new_with_timeouts(server: SensitiveUrl, timeouts: Timeouts) -> Result<Self, Error> {
|
||||
Ok(Self {
|
||||
client: reqwest::Client::new(),
|
||||
server,
|
||||
timeouts,
|
||||
})
|
||||
pub fn get_user_agent(&self) -> &str {
|
||||
&self.user_agent
|
||||
}
|
||||
|
||||
async fn get_with_timeout<T: DeserializeOwned, U: IntoUrl>(
|
||||
|
||||
@@ -1289,7 +1289,7 @@ mod test {
|
||||
transactions,
|
||||
..<_>::default()
|
||||
});
|
||||
let json = serde_json::to_value(&ep)?;
|
||||
let json = serde_json::to_value(ep)?;
|
||||
Ok(json.get("transactions").unwrap().clone())
|
||||
}
|
||||
|
||||
|
||||
@@ -113,6 +113,8 @@ pub enum Error {
|
||||
transactions_root: Hash256,
|
||||
},
|
||||
InvalidJWTSecret(String),
|
||||
InvalidForkForPayload,
|
||||
InvalidPayloadBody(String),
|
||||
BeaconStateError(BeaconStateError),
|
||||
}
|
||||
|
||||
@@ -277,6 +279,8 @@ pub struct Config {
|
||||
pub execution_endpoints: Vec<SensitiveUrl>,
|
||||
/// Endpoint urls for services providing the builder api.
|
||||
pub builder_url: Option<SensitiveUrl>,
|
||||
/// User agent to send with requests to the builder API.
|
||||
pub builder_user_agent: Option<String>,
|
||||
/// JWT secrets for the above endpoints running the engine api.
|
||||
pub secret_files: Vec<PathBuf>,
|
||||
/// The default fee recipient to use on the beacon node if none if provided from
|
||||
@@ -307,6 +311,7 @@ impl<T: EthSpec> ExecutionLayer<T> {
|
||||
let Config {
|
||||
execution_endpoints: urls,
|
||||
builder_url,
|
||||
builder_user_agent,
|
||||
secret_files,
|
||||
suggested_fee_recipient,
|
||||
jwt_id,
|
||||
@@ -367,12 +372,17 @@ impl<T: EthSpec> ExecutionLayer<T> {
|
||||
|
||||
let builder = builder_url
|
||||
.map(|url| {
|
||||
let builder_client = BuilderHttpClient::new(url.clone()).map_err(Error::Builder);
|
||||
info!(log,
|
||||
let builder_client = BuilderHttpClient::new(url.clone(), builder_user_agent)
|
||||
.map_err(Error::Builder)?;
|
||||
|
||||
info!(
|
||||
log,
|
||||
"Connected to external block builder";
|
||||
"builder_url" => ?url,
|
||||
"builder_profit_threshold" => builder_profit_threshold);
|
||||
builder_client
|
||||
"builder_profit_threshold" => builder_profit_threshold,
|
||||
"local_user_agent" => builder_client.get_user_agent(),
|
||||
);
|
||||
Ok::<_, Error>(builder_client)
|
||||
})
|
||||
.transpose()?;
|
||||
|
||||
@@ -1675,14 +1685,59 @@ impl<T: EthSpec> ExecutionLayer<T> {
|
||||
.map_err(Error::EngineError)
|
||||
}
|
||||
|
||||
pub async fn get_payload_by_block_hash(
|
||||
/// Fetch a full payload from the execution node.
|
||||
///
|
||||
/// This will fail if the payload is not from the finalized portion of the chain.
|
||||
pub async fn get_payload_for_header(
|
||||
&self,
|
||||
header: &ExecutionPayloadHeader<T>,
|
||||
fork: ForkName,
|
||||
) -> Result<Option<ExecutionPayload<T>>, Error> {
|
||||
let hash = header.block_hash();
|
||||
let block_number = header.block_number();
|
||||
|
||||
// Handle default payload body.
|
||||
if header.block_hash() == ExecutionBlockHash::zero() {
|
||||
let payload = match fork {
|
||||
ForkName::Merge => ExecutionPayloadMerge::default().into(),
|
||||
ForkName::Capella => ExecutionPayloadCapella::default().into(),
|
||||
ForkName::Base | ForkName::Altair => {
|
||||
return Err(Error::InvalidForkForPayload);
|
||||
}
|
||||
};
|
||||
return Ok(Some(payload));
|
||||
}
|
||||
|
||||
// Use efficient payload bodies by range method if supported.
|
||||
let capabilities = self.get_engine_capabilities(None).await?;
|
||||
if capabilities.get_payload_bodies_by_range_v1 {
|
||||
let mut payload_bodies = self.get_payload_bodies_by_range(block_number, 1).await?;
|
||||
|
||||
if payload_bodies.len() != 1 {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let opt_payload_body = payload_bodies.pop().flatten();
|
||||
opt_payload_body
|
||||
.map(|body| {
|
||||
body.to_payload(header.clone())
|
||||
.map_err(Error::InvalidPayloadBody)
|
||||
})
|
||||
.transpose()
|
||||
} else {
|
||||
// Fall back to eth_blockByHash.
|
||||
self.get_payload_by_hash_legacy(hash, fork).await
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_payload_by_hash_legacy(
|
||||
&self,
|
||||
hash: ExecutionBlockHash,
|
||||
fork: ForkName,
|
||||
) -> Result<Option<ExecutionPayload<T>>, Error> {
|
||||
self.engine()
|
||||
.request(|engine| async move {
|
||||
self.get_payload_by_block_hash_from_engine(engine, hash, fork)
|
||||
self.get_payload_by_hash_from_engine(engine, hash, fork)
|
||||
.await
|
||||
})
|
||||
.await
|
||||
@@ -1690,7 +1745,7 @@ impl<T: EthSpec> ExecutionLayer<T> {
|
||||
.map_err(Error::EngineError)
|
||||
}
|
||||
|
||||
async fn get_payload_by_block_hash_from_engine(
|
||||
async fn get_payload_by_hash_from_engine(
|
||||
&self,
|
||||
engine: &Engine,
|
||||
hash: ExecutionBlockHash,
|
||||
@@ -1704,7 +1759,7 @@ impl<T: EthSpec> ExecutionLayer<T> {
|
||||
ForkName::Capella => Ok(Some(ExecutionPayloadCapella::default().into())),
|
||||
ForkName::Eip4844 => Ok(Some(ExecutionPayloadEip4844::default().into())),
|
||||
ForkName::Base | ForkName::Altair => Err(ApiError::UnsupportedForkVariant(
|
||||
format!("called get_payload_by_block_hash_from_engine with {}", fork),
|
||||
format!("called get_payload_by_hash_from_engine with {}", fork),
|
||||
)),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -152,6 +152,7 @@ pub async fn create_api_server_on_port<T: BeaconChainTypes>(
|
||||
None,
|
||||
meta_data,
|
||||
vec![],
|
||||
false,
|
||||
&log,
|
||||
));
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//! Generic tests that make use of the (newer) `InteractiveApiTester`
|
||||
use beacon_chain::{
|
||||
chain_config::ReOrgThreshold,
|
||||
chain_config::{DisallowedReOrgOffsets, ReOrgThreshold},
|
||||
test_utils::{AttestationStrategy, BlockStrategy, SyncCommitteeStrategy},
|
||||
};
|
||||
use eth2::types::DepositContractData;
|
||||
@@ -110,6 +110,8 @@ pub struct ReOrgTest {
|
||||
misprediction: bool,
|
||||
/// Whether to expect withdrawals to change on epoch boundaries.
|
||||
expect_withdrawals_change_on_epoch: bool,
|
||||
/// Epoch offsets to avoid proposing reorg blocks at.
|
||||
disallowed_offsets: Vec<u64>,
|
||||
}
|
||||
|
||||
impl Default for ReOrgTest {
|
||||
@@ -127,6 +129,7 @@ impl Default for ReOrgTest {
|
||||
should_re_org: true,
|
||||
misprediction: false,
|
||||
expect_withdrawals_change_on_epoch: false,
|
||||
disallowed_offsets: vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -238,6 +241,32 @@ pub async fn proposer_boost_re_org_head_distance() {
|
||||
.await;
|
||||
}
|
||||
|
||||
// Check that a re-org at a disallowed offset fails.
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
pub async fn proposer_boost_re_org_disallowed_offset() {
|
||||
let offset = 4;
|
||||
proposer_boost_re_org_test(ReOrgTest {
|
||||
head_slot: Slot::new(E::slots_per_epoch() + offset - 1),
|
||||
disallowed_offsets: vec![offset],
|
||||
should_re_org: false,
|
||||
..Default::default()
|
||||
})
|
||||
.await;
|
||||
}
|
||||
|
||||
// Check that a re-org at the *only* allowed offset succeeds.
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
pub async fn proposer_boost_re_org_disallowed_offset_exact() {
|
||||
let offset = 4;
|
||||
let disallowed_offsets = (0..E::slots_per_epoch()).filter(|o| *o != offset).collect();
|
||||
proposer_boost_re_org_test(ReOrgTest {
|
||||
head_slot: Slot::new(E::slots_per_epoch() + offset - 1),
|
||||
disallowed_offsets,
|
||||
..Default::default()
|
||||
})
|
||||
.await;
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
pub async fn proposer_boost_re_org_very_unhealthy() {
|
||||
proposer_boost_re_org_test(ReOrgTest {
|
||||
@@ -286,6 +315,7 @@ pub async fn proposer_boost_re_org_test(
|
||||
should_re_org,
|
||||
misprediction,
|
||||
expect_withdrawals_change_on_epoch,
|
||||
disallowed_offsets,
|
||||
}: ReOrgTest,
|
||||
) {
|
||||
assert!(head_slot > 0);
|
||||
@@ -320,6 +350,9 @@ pub async fn proposer_boost_re_org_test(
|
||||
.proposer_re_org_max_epochs_since_finalization(Epoch::new(
|
||||
max_epochs_since_finalization,
|
||||
))
|
||||
.proposer_re_org_disallowed_offsets(
|
||||
DisallowedReOrgOffsets::new::<E>(disallowed_offsets).unwrap(),
|
||||
)
|
||||
})),
|
||||
)
|
||||
.await;
|
||||
|
||||
@@ -1875,21 +1875,6 @@ impl ApiTester {
|
||||
.unwrap();
|
||||
assert_eq!(result_ssz, expected, "{:?}", state_id);
|
||||
|
||||
// Check legacy v1 API.
|
||||
let result_v1 = self
|
||||
.client
|
||||
.get_debug_beacon_states_v1(state_id.0)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
if let (Some(json), Some(expected)) = (&result_v1, &expected) {
|
||||
assert_eq!(json.version, None);
|
||||
assert_eq!(json.data, *expected, "{:?}", state_id);
|
||||
} else {
|
||||
assert_eq!(result_v1, None);
|
||||
assert_eq!(expected, None);
|
||||
}
|
||||
|
||||
// Check that version headers are provided.
|
||||
let url = self
|
||||
.client
|
||||
|
||||
@@ -101,6 +101,9 @@ pub struct Config {
|
||||
/// List of trusted libp2p nodes which are not scored.
|
||||
pub trusted_peers: Vec<PeerIdSerialized>,
|
||||
|
||||
/// Disables peer scoring altogether.
|
||||
pub disable_peer_scoring: bool,
|
||||
|
||||
/// Client version
|
||||
pub client_version: String,
|
||||
|
||||
@@ -309,6 +312,7 @@ impl Default for Config {
|
||||
boot_nodes_multiaddr: vec![],
|
||||
libp2p_nodes: vec![],
|
||||
trusted_peers: vec![],
|
||||
disable_peer_scoring: false,
|
||||
client_version: lighthouse_version::version_with_platform(),
|
||||
disable_discovery: false,
|
||||
upnp_enabled: true,
|
||||
|
||||
@@ -1162,6 +1162,7 @@ mod tests {
|
||||
syncnets: Default::default(),
|
||||
}),
|
||||
vec![],
|
||||
false,
|
||||
&log,
|
||||
);
|
||||
Discovery::new(&keypair, &config, Arc::new(globals), &log)
|
||||
|
||||
@@ -41,12 +41,14 @@ pub struct PeerDB<TSpec: EthSpec> {
|
||||
disconnected_peers: usize,
|
||||
/// Counts banned peers in total and per ip
|
||||
banned_peers_count: BannedPeersCount,
|
||||
/// Specifies if peer scoring is disabled.
|
||||
disable_peer_scoring: bool,
|
||||
/// PeerDB's logger
|
||||
log: slog::Logger,
|
||||
}
|
||||
|
||||
impl<TSpec: EthSpec> PeerDB<TSpec> {
|
||||
pub fn new(trusted_peers: Vec<PeerId>, log: &slog::Logger) -> Self {
|
||||
pub fn new(trusted_peers: Vec<PeerId>, disable_peer_scoring: bool, log: &slog::Logger) -> Self {
|
||||
// Initialize the peers hashmap with trusted peers
|
||||
let peers = trusted_peers
|
||||
.into_iter()
|
||||
@@ -56,6 +58,7 @@ impl<TSpec: EthSpec> PeerDB<TSpec> {
|
||||
log: log.clone(),
|
||||
disconnected_peers: 0,
|
||||
banned_peers_count: BannedPeersCount::default(),
|
||||
disable_peer_scoring,
|
||||
peers,
|
||||
}
|
||||
}
|
||||
@@ -704,7 +707,11 @@ impl<TSpec: EthSpec> PeerDB<TSpec> {
|
||||
warn!(log_ref, "Updating state of unknown peer";
|
||||
"peer_id" => %peer_id, "new_state" => ?new_state);
|
||||
}
|
||||
PeerInfo::default()
|
||||
if self.disable_peer_scoring {
|
||||
PeerInfo::trusted_peer_info()
|
||||
} else {
|
||||
PeerInfo::default()
|
||||
}
|
||||
});
|
||||
|
||||
// Ban the peer if the score is not already low enough.
|
||||
@@ -1300,7 +1307,7 @@ mod tests {
|
||||
|
||||
fn get_db() -> PeerDB<M> {
|
||||
let log = build_log(slog::Level::Debug, false);
|
||||
PeerDB::new(vec![], &log)
|
||||
PeerDB::new(vec![], false, &log)
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -1999,7 +2006,7 @@ mod tests {
|
||||
fn test_trusted_peers_score() {
|
||||
let trusted_peer = PeerId::random();
|
||||
let log = build_log(slog::Level::Debug, false);
|
||||
let mut pdb: PeerDB<M> = PeerDB::new(vec![trusted_peer], &log);
|
||||
let mut pdb: PeerDB<M> = PeerDB::new(vec![trusted_peer], false, &log);
|
||||
|
||||
pdb.connect_ingoing(&trusted_peer, "/ip4/0.0.0.0".parse().unwrap(), None);
|
||||
|
||||
@@ -2018,4 +2025,28 @@ mod tests {
|
||||
Score::max_score().score()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_disable_peer_scoring() {
|
||||
let peer = PeerId::random();
|
||||
let log = build_log(slog::Level::Debug, false);
|
||||
let mut pdb: PeerDB<M> = PeerDB::new(vec![], true, &log);
|
||||
|
||||
pdb.connect_ingoing(&peer, "/ip4/0.0.0.0".parse().unwrap(), None);
|
||||
|
||||
// Check trusted status and score
|
||||
assert!(pdb.peer_info(&peer).unwrap().is_trusted());
|
||||
assert_eq!(
|
||||
pdb.peer_info(&peer).unwrap().score().score(),
|
||||
Score::max_score().score()
|
||||
);
|
||||
|
||||
// Adding/Subtracting score should have no effect on a trusted peer
|
||||
add_score(&mut pdb, &peer, -50.0);
|
||||
|
||||
assert_eq!(
|
||||
pdb.peer_info(&peer).unwrap().score().score(),
|
||||
Score::max_score().score()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -173,6 +173,7 @@ impl<AppReqId: ReqId, TSpec: EthSpec> Network<AppReqId, TSpec> {
|
||||
.iter()
|
||||
.map(|x| PeerId::from(x.clone()))
|
||||
.collect(),
|
||||
config.disable_peer_scoring,
|
||||
&log,
|
||||
);
|
||||
Arc::new(globals)
|
||||
|
||||
@@ -39,6 +39,7 @@ impl<TSpec: EthSpec> NetworkGlobals<TSpec> {
|
||||
listen_port_tcp6: Option<u16>,
|
||||
local_metadata: MetaData<TSpec>,
|
||||
trusted_peers: Vec<PeerId>,
|
||||
disable_peer_scoring: bool,
|
||||
log: &slog::Logger,
|
||||
) -> Self {
|
||||
NetworkGlobals {
|
||||
@@ -48,7 +49,7 @@ impl<TSpec: EthSpec> NetworkGlobals<TSpec> {
|
||||
listen_port_tcp4,
|
||||
listen_port_tcp6,
|
||||
local_metadata: RwLock::new(local_metadata),
|
||||
peers: RwLock::new(PeerDB::new(trusted_peers, log)),
|
||||
peers: RwLock::new(PeerDB::new(trusted_peers, disable_peer_scoring, log)),
|
||||
gossipsub_subscriptions: RwLock::new(HashSet::new()),
|
||||
sync_state: RwLock::new(SyncState::Stalled),
|
||||
backfill_state: RwLock::new(BackFillState::NotRequired),
|
||||
@@ -144,6 +145,7 @@ impl<TSpec: EthSpec> NetworkGlobals<TSpec> {
|
||||
syncnets: Default::default(),
|
||||
}),
|
||||
vec![],
|
||||
false,
|
||||
log,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -185,6 +185,7 @@ impl TestRig {
|
||||
None,
|
||||
meta_data,
|
||||
vec![],
|
||||
false,
|
||||
&log,
|
||||
));
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ pub const QUEUED_ATTESTATION_DELAY: Duration = Duration::from_secs(12);
|
||||
pub const QUEUED_LIGHT_CLIENT_UPDATE_DELAY: Duration = Duration::from_secs(12);
|
||||
|
||||
/// For how long to queue rpc blocks before sending them back for reprocessing.
|
||||
pub const QUEUED_RPC_BLOCK_DELAY: Duration = Duration::from_secs(3);
|
||||
pub const QUEUED_RPC_BLOCK_DELAY: Duration = Duration::from_secs(4);
|
||||
|
||||
/// Set an arbitrary upper-bound on the number of queued blocks to avoid DoS attacks. The fact that
|
||||
/// we signature-verify blocks before putting them in the queue *should* protect against this, but
|
||||
@@ -520,7 +520,7 @@ impl<T: BeaconChainTypes> ReprocessQueue<T> {
|
||||
return;
|
||||
}
|
||||
|
||||
// Queue the block for 1/4th of a slot
|
||||
// Queue the block for 1/3rd of a slot
|
||||
self.rpc_block_delay_queue
|
||||
.insert(rpc_block, QUEUED_RPC_BLOCK_DELAY);
|
||||
}
|
||||
|
||||
@@ -10,12 +10,15 @@ use crate::sync::{BatchProcessResult, ChainId};
|
||||
use beacon_chain::blob_verification::{AsBlock, BlockWrapper, IntoAvailableBlock};
|
||||
use beacon_chain::CountUnrealized;
|
||||
use beacon_chain::{
|
||||
observed_block_producers::Error as ObserveError, validator_monitor::get_block_delay_ms,
|
||||
BeaconChainError, BeaconChainTypes, BlockError, ChainSegmentResult, HistoricalBlockError,
|
||||
NotifyExecutionLayer,
|
||||
};
|
||||
use lighthouse_network::PeerAction;
|
||||
use slog::{debug, error, info, warn};
|
||||
use slot_clock::SlotClock;
|
||||
use std::sync::Arc;
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
use tokio::sync::mpsc;
|
||||
use types::{Epoch, Hash256, SignedBeaconBlock};
|
||||
|
||||
@@ -84,6 +87,66 @@ impl<T: BeaconChainTypes> Worker<T> {
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
// Returns `true` if the time now is after the 4s attestation deadline.
|
||||
let block_is_late = SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
// If we can't read the system time clock then indicate that the
|
||||
// block is late (and therefore should *not* be requeued). This
|
||||
// avoids infinite loops.
|
||||
.map_or(true, |now| {
|
||||
get_block_delay_ms(now, block.message(), &self.chain.slot_clock)
|
||||
> self.chain.slot_clock.unagg_attestation_production_delay()
|
||||
});
|
||||
|
||||
// Checks if a block from this proposer is already known.
|
||||
let proposal_already_known = || {
|
||||
match self
|
||||
.chain
|
||||
.observed_block_producers
|
||||
.read()
|
||||
.proposer_has_been_observed(block.message())
|
||||
{
|
||||
Ok(is_observed) => is_observed,
|
||||
// Both of these blocks will be rejected, so reject them now rather
|
||||
// than re-queuing them.
|
||||
Err(ObserveError::FinalizedBlock { .. })
|
||||
| Err(ObserveError::ValidatorIndexTooHigh { .. }) => false,
|
||||
}
|
||||
};
|
||||
|
||||
// If we've already seen a block from this proposer *and* the block
|
||||
// arrived before the attestation deadline, requeue it to ensure it is
|
||||
// imported late enough that it won't receive a proposer boost.
|
||||
if !block_is_late && proposal_already_known() {
|
||||
debug!(
|
||||
self.log,
|
||||
"Delaying processing of duplicate RPC block";
|
||||
"block_root" => ?block_root,
|
||||
"proposer" => block.message().proposer_index(),
|
||||
"slot" => block.slot()
|
||||
);
|
||||
|
||||
// Send message to work reprocess queue to retry the block
|
||||
let reprocess_msg = ReprocessQueueMessage::RpcBlock(QueuedRpcBlock {
|
||||
block_root,
|
||||
block: block.clone(),
|
||||
process_type,
|
||||
seen_timestamp,
|
||||
should_process: true,
|
||||
});
|
||||
|
||||
if reprocess_tx.try_send(reprocess_msg).is_err() {
|
||||
error!(
|
||||
self.log,
|
||||
"Failed to inform block import";
|
||||
"source" => "rpc",
|
||||
"block_root" => %block_root
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
let slot = block.slot();
|
||||
let parent_root = block.message().parent_root();
|
||||
let available_block = block
|
||||
|
||||
@@ -497,7 +497,8 @@ impl<T: EthSpec> OperationPool<T> {
|
||||
|exit| {
|
||||
filter(exit.as_inner())
|
||||
&& exit.signature_is_still_valid(&state.fork())
|
||||
&& verify_exit(state, exit.as_inner(), VerifySignatures::False, spec).is_ok()
|
||||
&& verify_exit(state, None, exit.as_inner(), VerifySignatures::False, spec)
|
||||
.is_ok()
|
||||
},
|
||||
|exit| exit.as_inner().clone(),
|
||||
T::MaxVoluntaryExits::to_usize(),
|
||||
|
||||
@@ -240,6 +240,14 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> {
|
||||
.help("Disables the discv5 discovery protocol. The node will not search for new peers or participate in the discovery protocol.")
|
||||
.takes_value(false),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("disable-peer-scoring")
|
||||
.long("disable-peer-scoring")
|
||||
.help("Disables peer scoring in lighthouse. WARNING: This is a dev only flag is only meant to be used in local testing scenarios \
|
||||
Using this flag on a real network may cause your node to become eclipsed and see a different view of the network")
|
||||
.takes_value(false)
|
||||
.hidden(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("trusted-peers")
|
||||
.long("trusted-peers")
|
||||
@@ -919,6 +927,28 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> {
|
||||
allowed. Default: 2")
|
||||
.conflicts_with("disable-proposer-reorgs")
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("proposer-reorg-cutoff")
|
||||
.long("proposer-reorg-cutoff")
|
||||
.value_name("MILLISECONDS")
|
||||
.help("Maximum delay after the start of the slot at which to propose a reorging \
|
||||
block. Lower values can prevent failed reorgs by ensuring the block has \
|
||||
ample time to propagate and be processed by the network. The default is \
|
||||
1/12th of a slot (1 second on mainnet)")
|
||||
.conflicts_with("disable-proposer-reorgs")
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("proposer-reorg-disallowed-offsets")
|
||||
.long("proposer-reorg-disallowed-offsets")
|
||||
.value_name("N1,N2,...")
|
||||
.help("Comma-separated list of integer offsets which can be used to avoid \
|
||||
proposing reorging blocks at certain slots. An offset of N means that \
|
||||
reorging proposals will not be attempted at any slot such that \
|
||||
`slot % SLOTS_PER_EPOCH == N`. By default only re-orgs at offset 0 will be \
|
||||
avoided. Any offsets supplied with this flag will impose additional \
|
||||
restrictions.")
|
||||
.conflicts_with("disable-proposer-reorgs")
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("prepare-payload-lookahead")
|
||||
.long("prepare-payload-lookahead")
|
||||
@@ -1012,6 +1042,15 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> {
|
||||
.default_value("0")
|
||||
.takes_value(true)
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("builder-user-agent")
|
||||
.long("builder-user-agent")
|
||||
.value_name("STRING")
|
||||
.help("The HTTP user agent to send alongside requests to the builder URL. The \
|
||||
default is Lighthouse's version string.")
|
||||
.requires("builder")
|
||||
.takes_value(true)
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("count-unrealized")
|
||||
.long("count-unrealized")
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use beacon_chain::chain_config::{
|
||||
ReOrgThreshold, DEFAULT_PREPARE_PAYLOAD_LOOKAHEAD_FACTOR,
|
||||
DisallowedReOrgOffsets, ReOrgThreshold, DEFAULT_PREPARE_PAYLOAD_LOOKAHEAD_FACTOR,
|
||||
DEFAULT_RE_ORG_MAX_EPOCHS_SINCE_FINALIZATION, DEFAULT_RE_ORG_THRESHOLD,
|
||||
};
|
||||
use beacon_chain::TrustedSetup;
|
||||
@@ -330,6 +330,9 @@ pub fn get_config<E: EthSpec>(
|
||||
let payload_builder =
|
||||
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")?;
|
||||
}
|
||||
|
||||
// Set config values from parse values.
|
||||
@@ -723,6 +726,23 @@ pub fn get_config<E: EthSpec>(
|
||||
client_config.chain.re_org_max_epochs_since_finalization =
|
||||
clap_utils::parse_optional(cli_args, "proposer-reorg-epochs-since-finalization")?
|
||||
.unwrap_or(DEFAULT_RE_ORG_MAX_EPOCHS_SINCE_FINALIZATION);
|
||||
client_config.chain.re_org_cutoff_millis =
|
||||
clap_utils::parse_optional(cli_args, "proposer-reorg-cutoff")?;
|
||||
|
||||
if let Some(disallowed_offsets_str) =
|
||||
clap_utils::parse_optional::<String>(cli_args, "proposer-reorg-disallowed-offsets")?
|
||||
{
|
||||
let disallowed_offsets = disallowed_offsets_str
|
||||
.split(',')
|
||||
.map(|s| {
|
||||
s.parse()
|
||||
.map_err(|e| format!("invalid disallowed-offsets: {e:?}"))
|
||||
})
|
||||
.collect::<Result<Vec<u64>, _>>()?;
|
||||
client_config.chain.re_org_disallowed_offsets =
|
||||
DisallowedReOrgOffsets::new::<E>(disallowed_offsets)
|
||||
.map_err(|e| format!("invalid disallowed-offsets: {e:?}"))?;
|
||||
}
|
||||
}
|
||||
|
||||
// Note: This overrides any previous flags that enable this option.
|
||||
@@ -1045,6 +1065,10 @@ pub fn set_network_config(
|
||||
.collect::<Result<Vec<Multiaddr>, _>>()?;
|
||||
}
|
||||
|
||||
if cli_args.is_present("disable-peer-scoring") {
|
||||
config.disable_peer_scoring = true;
|
||||
}
|
||||
|
||||
if let Some(trusted_peers_str) = cli_args.value_of("trusted-peers") {
|
||||
config.trusted_peers = trusted_peers_str
|
||||
.split(',')
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//! Implementation of historic state reconstruction (given complete block history).
|
||||
use crate::hot_cold_store::{HotColdDB, HotColdDBError};
|
||||
use crate::{Error, ItemStore, KeyValueStore};
|
||||
use crate::{Error, ItemStore};
|
||||
use itertools::{process_results, Itertools};
|
||||
use slog::info;
|
||||
use state_processing::{
|
||||
@@ -13,8 +13,8 @@ use types::{EthSpec, Hash256};
|
||||
impl<E, Hot, Cold> HotColdDB<E, Hot, Cold>
|
||||
where
|
||||
E: EthSpec,
|
||||
Hot: KeyValueStore<E> + ItemStore<E>,
|
||||
Cold: KeyValueStore<E> + ItemStore<E>,
|
||||
Hot: ItemStore<E>,
|
||||
Cold: ItemStore<E>,
|
||||
{
|
||||
pub fn reconstruct_historic_states(self: &Arc<Self>) -> Result<(), Error> {
|
||||
let mut anchor = if let Some(anchor) = self.get_anchor_info() {
|
||||
|
||||
Reference in New Issue
Block a user