Merge branch 'unstable' into vc-fallback

This commit is contained in:
Mac L
2024-01-31 19:24:52 +11:00
119 changed files with 2579 additions and 1054 deletions

View File

@@ -157,6 +157,12 @@ pub struct ValidatorDefinition {
#[serde(skip_serializing_if = "Option::is_none")]
pub builder_proposals: Option<bool>,
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub builder_boost_factor: Option<u64>,
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub prefer_builder_proposals: Option<bool>,
#[serde(default)]
pub description: String,
#[serde(flatten)]
pub signing_definition: SigningDefinition,
@@ -169,6 +175,7 @@ impl ValidatorDefinition {
/// ## Notes
///
/// This function does not check the password against the keystore.
#[allow(clippy::too_many_arguments)]
pub fn new_keystore_with_password<P: AsRef<Path>>(
voting_keystore_path: P,
voting_keystore_password_storage: PasswordStorage,
@@ -176,6 +183,8 @@ impl ValidatorDefinition {
suggested_fee_recipient: Option<Address>,
gas_limit: Option<u64>,
builder_proposals: Option<bool>,
builder_boost_factor: Option<u64>,
prefer_builder_proposals: Option<bool>,
) -> Result<Self, Error> {
let voting_keystore_path = voting_keystore_path.as_ref().into();
let keystore =
@@ -196,6 +205,8 @@ impl ValidatorDefinition {
suggested_fee_recipient,
gas_limit,
builder_proposals,
builder_boost_factor,
prefer_builder_proposals,
signing_definition: SigningDefinition::LocalKeystore {
voting_keystore_path,
voting_keystore_password_path,
@@ -344,6 +355,8 @@ impl ValidatorDefinitions {
suggested_fee_recipient: None,
gas_limit: None,
builder_proposals: None,
builder_boost_factor: None,
prefer_builder_proposals: None,
signing_definition: SigningDefinition::LocalKeystore {
voting_keystore_path,
voting_keystore_password_path,

View File

@@ -378,26 +378,27 @@ impl BeaconNodeHttpClient {
if let Some(timeout) = timeout {
builder = builder.timeout(timeout);
}
let response = builder.json(body).send().await?;
ok_or_error(response).await
}
/// Generic POST function supporting arbitrary responses and timeouts.
async fn post_generic_with_ssz_body<T: Into<Body>, U: IntoUrl>(
/// Does not include Content-Type application/json in the request header.
async fn post_generic_json_without_content_type_header<T: Serialize, U: IntoUrl>(
&self,
url: U,
body: T,
body: &T,
timeout: Option<Duration>,
) -> Result<Response, Error> {
let mut builder = self.client.post(url);
if let Some(timeout) = timeout {
builder = builder.timeout(timeout);
}
let response = builder
.header("Content-Type", "application/octet-stream")
.body(body)
.send()
.await?;
let serialized_body = serde_json::to_vec(body).map_err(Error::InvalidJson)?;
let response = builder.body(serialized_body).send().await?;
ok_or_error(response).await
}
@@ -871,10 +872,11 @@ impl BeaconNodeHttpClient {
.push("beacon")
.push("blocks");
self.post_generic_with_ssz_body(
self.post_generic_with_consensus_version_and_ssz_body(
path,
block_contents.as_ssz_bytes(),
Some(self.timeouts.proposal),
block_contents.signed_block().fork_name_unchecked(),
)
.await?;
@@ -915,8 +917,13 @@ impl BeaconNodeHttpClient {
.push("beacon")
.push("blinded_blocks");
self.post_generic_with_ssz_body(path, block.as_ssz_bytes(), Some(self.timeouts.proposal))
.await?;
self.post_generic_with_consensus_version_and_ssz_body(
path,
block.as_ssz_bytes(),
Some(self.timeouts.proposal),
block.fork_name_unchecked(),
)
.await?;
Ok(())
}
@@ -1082,8 +1089,18 @@ impl BeaconNodeHttpClient {
pub async fn get_blobs<T: EthSpec>(
&self,
block_id: BlockId,
indices: Option<&[u64]>,
) -> Result<Option<GenericResponse<BlobSidecarList<T>>>, Error> {
let path = self.get_blobs_path(block_id)?;
let mut path = self.get_blobs_path(block_id)?;
if let Some(indices) = indices {
let indices_string = indices
.iter()
.map(|i| i.to_string())
.collect::<Vec<_>>()
.join(",");
path.query_pairs_mut()
.append_pair("indices", &indices_string);
}
let Some(response) = self.get_response(path, |b| b).await.optional()? else {
return Ok(None);
};
@@ -1258,7 +1275,8 @@ impl BeaconNodeHttpClient {
.push("pool")
.push("attester_slashings");
self.post(path, slashing).await?;
self.post_generic_json_without_content_type_header(path, slashing, None)
.await?;
Ok(())
}

View File

@@ -8,15 +8,12 @@ mod standard_block_rewards;
mod sync_committee_rewards;
use crate::{
ok_or_error,
types::{
BeaconState, ChainSpec, DepositTreeSnapshot, Epoch, EthSpec, FinalizedExecutionBlock,
GenericResponse, ValidatorId,
DepositTreeSnapshot, Epoch, EthSpec, FinalizedExecutionBlock, GenericResponse, ValidatorId,
},
BeaconNodeHttpClient, DepositData, Error, Eth1Data, Hash256, Slot, StateId, StatusCode,
BeaconNodeHttpClient, DepositData, Error, Eth1Data, Hash256, Slot,
};
use proto_array::core::ProtoArray;
use reqwest::IntoUrl;
use serde::{Deserialize, Serialize};
use ssz::four_byte_option_impl;
use ssz_derive::{Decode, Encode};
@@ -371,27 +368,6 @@ pub struct DatabaseInfo {
}
impl BeaconNodeHttpClient {
/// Perform a HTTP GET request, returning `None` on a 404 error.
async fn get_bytes_opt<U: IntoUrl>(&self, url: U) -> Result<Option<Vec<u8>>, Error> {
let response = self.client.get(url).send().await.map_err(Error::from)?;
match ok_or_error(response).await {
Ok(resp) => Ok(Some(
resp.bytes()
.await
.map_err(Error::from)?
.into_iter()
.collect::<Vec<_>>(),
)),
Err(err) => {
if err.status() == Some(StatusCode::NOT_FOUND) {
Ok(None)
} else {
Err(err)
}
}
}
}
/// `GET lighthouse/health`
pub async fn get_lighthouse_health(&self) -> Result<GenericResponse<Health>, Error> {
let mut path = self.server.full.clone();
@@ -516,28 +492,6 @@ impl BeaconNodeHttpClient {
self.get(path).await
}
/// `GET lighthouse/beacon/states/{state_id}/ssz`
pub async fn get_lighthouse_beacon_states_ssz<E: EthSpec>(
&self,
state_id: &StateId,
spec: &ChainSpec,
) -> Result<Option<BeaconState<E>>, Error> {
let mut path = self.server.full.clone();
path.path_segments_mut()
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
.push("lighthouse")
.push("beacon")
.push("states")
.push(&state_id.to_string())
.push("ssz");
self.get_bytes_opt(path)
.await?
.map(|bytes| BeaconState::from_ssz_bytes(&bytes, spec).map_err(Error::InvalidSsz))
.transpose()
}
/// `GET lighthouse/staking`
pub async fn get_lighthouse_staking(&self) -> Result<bool, Error> {
let mut path = self.server.full.clone();

View File

@@ -483,12 +483,15 @@ impl ValidatorClientHttpClient {
}
/// `PATCH lighthouse/validators/{validator_pubkey}`
#[allow(clippy::too_many_arguments)]
pub async fn patch_lighthouse_validators(
&self,
voting_pubkey: &PublicKeyBytes,
enabled: Option<bool>,
gas_limit: Option<u64>,
builder_proposals: Option<bool>,
builder_boost_factor: Option<u64>,
prefer_builder_proposals: Option<bool>,
graffiti: Option<GraffitiString>,
) -> Result<(), Error> {
let mut path = self.server.full.clone();
@@ -505,6 +508,8 @@ impl ValidatorClientHttpClient {
enabled,
gas_limit,
builder_proposals,
builder_boost_factor,
prefer_builder_proposals,
graffiti,
},
)

View File

@@ -32,6 +32,12 @@ pub struct ValidatorRequest {
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub builder_proposals: Option<bool>,
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub builder_boost_factor: Option<u64>,
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub prefer_builder_proposals: Option<bool>,
#[serde(with = "serde_utils::quoted_u64")]
pub deposit_gwei: u64,
}
@@ -86,6 +92,12 @@ pub struct ValidatorPatchRequest {
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub graffiti: Option<GraffitiString>,
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub builder_boost_factor: Option<u64>,
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub prefer_builder_proposals: Option<bool>,
}
#[derive(Clone, PartialEq, Serialize, Deserialize)]
@@ -105,6 +117,12 @@ pub struct KeystoreValidatorsPostRequest {
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub builder_proposals: Option<bool>,
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub builder_boost_factor: Option<u64>,
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub prefer_builder_proposals: Option<bool>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
@@ -135,6 +153,12 @@ pub struct Web3SignerValidatorRequest {
pub client_identity_path: Option<PathBuf>,
#[serde(skip_serializing_if = "Option::is_none")]
pub client_identity_password: Option<String>,
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub builder_boost_factor: Option<u64>,
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub prefer_builder_proposals: Option<bool>,
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]

View File

@@ -15,6 +15,7 @@ use ssz_derive::{Decode, Encode};
use std::convert::TryFrom;
use std::fmt::{self, Display};
use std::str::{from_utf8, FromStr};
use std::sync::Arc;
use std::time::Duration;
use types::beacon_block_body::KzgCommitments;
pub use types::*;
@@ -1479,15 +1480,15 @@ mod tests {
type E = MainnetEthSpec;
let spec = ForkName::Capella.make_genesis_spec(E::default_spec());
let block: PublishBlockRequest<E> = SignedBeaconBlock::from_block(
let block: PublishBlockRequest<E> = Arc::new(SignedBeaconBlock::from_block(
BeaconBlock::<E>::Capella(BeaconBlockCapella::empty(&spec)),
Signature::empty(),
)
))
.try_into()
.expect("should convert into signed block contents");
let decoded: PublishBlockRequest<E> =
PublishBlockRequest::from_ssz_bytes(&block.as_ssz_bytes(), &spec)
PublishBlockRequest::from_ssz_bytes(&block.as_ssz_bytes(), ForkName::Capella)
.expect("should decode Block");
assert!(matches!(decoded, PublishBlockRequest::Block(_)));
}
@@ -1503,11 +1504,14 @@ mod tests {
);
let blobs = BlobsList::<E>::from(vec![Blob::<E>::default()]);
let kzg_proofs = KzgProofs::<E>::from(vec![KzgProof::empty()]);
let signed_block_contents = PublishBlockRequest::new(block, Some((kzg_proofs, blobs)));
let signed_block_contents =
PublishBlockRequest::new(Arc::new(block), Some((kzg_proofs, blobs)));
let decoded: PublishBlockRequest<E> =
PublishBlockRequest::from_ssz_bytes(&signed_block_contents.as_ssz_bytes(), &spec)
.expect("should decode BlockAndBlobSidecars");
let decoded: PublishBlockRequest<E> = PublishBlockRequest::from_ssz_bytes(
&signed_block_contents.as_ssz_bytes(),
ForkName::Deneb,
)
.expect("should decode BlockAndBlobSidecars");
assert!(matches!(decoded, PublishBlockRequest::BlockContents(_)));
}
}
@@ -1642,7 +1646,7 @@ impl<T: EthSpec> FullBlockContents<T> {
) -> PublishBlockRequest<T> {
let (block, maybe_blobs) = self.deconstruct();
let signed_block = block.sign(secret_key, fork, genesis_validators_root, spec);
PublishBlockRequest::new(signed_block, maybe_blobs)
PublishBlockRequest::new(Arc::new(signed_block), maybe_blobs)
}
}
@@ -1673,7 +1677,10 @@ impl<T: EthSpec> Into<BeaconBlock<T>> for FullBlockContents<T> {
}
}
pub type SignedBlockContentsTuple<T> = (SignedBeaconBlock<T>, Option<(KzgProofs<T>, BlobsList<T>)>);
pub type SignedBlockContentsTuple<T> = (
Arc<SignedBeaconBlock<T>>,
Option<(KzgProofs<T>, BlobsList<T>)>,
);
fn parse_required_header<T>(
headers: &HeaderMap,
@@ -1728,12 +1735,12 @@ impl TryFrom<&HeaderMap> for ProduceBlockV3Metadata {
#[ssz(enum_behaviour = "transparent")]
pub enum PublishBlockRequest<T: EthSpec> {
BlockContents(SignedBlockContents<T>),
Block(SignedBeaconBlock<T>),
Block(Arc<SignedBeaconBlock<T>>),
}
impl<T: EthSpec> PublishBlockRequest<T> {
pub fn new(
block: SignedBeaconBlock<T>,
block: Arc<SignedBeaconBlock<T>>,
blob_items: Option<(KzgProofs<T>, BlobsList<T>)>,
) -> Self {
match blob_items {
@@ -1746,23 +1753,12 @@ impl<T: EthSpec> PublishBlockRequest<T> {
}
}
/// SSZ decode with fork variant determined by slot.
pub fn from_ssz_bytes(bytes: &[u8], spec: &ChainSpec) -> Result<Self, ssz::DecodeError> {
let slot_len = <Slot as Decode>::ssz_fixed_len();
let slot_bytes = bytes
.get(0..slot_len)
.ok_or(DecodeError::InvalidByteLength {
len: bytes.len(),
expected: slot_len,
})?;
let slot = Slot::from_ssz_bytes(slot_bytes)?;
let fork_at_slot = spec.fork_name_at_slot::<T>(slot);
match fork_at_slot {
/// SSZ decode with fork variant determined by `fork_name`.
pub fn from_ssz_bytes(bytes: &[u8], fork_name: ForkName) -> Result<Self, ssz::DecodeError> {
match fork_name {
ForkName::Base | ForkName::Altair | ForkName::Merge | ForkName::Capella => {
SignedBeaconBlock::from_ssz_bytes(bytes, spec)
.map(|block| PublishBlockRequest::Block(block))
SignedBeaconBlock::from_ssz_bytes_for_fork(bytes, fork_name)
.map(|block| PublishBlockRequest::Block(Arc::new(block)))
}
ForkName::Deneb => {
let mut builder = ssz::SszDecoderBuilder::new(bytes);
@@ -1771,16 +1767,20 @@ impl<T: EthSpec> PublishBlockRequest<T> {
builder.register_type::<BlobsList<T>>()?;
let mut decoder = builder.build()?;
let block = decoder
.decode_next_with(|bytes| SignedBeaconBlock::from_ssz_bytes(bytes, spec))?;
let block = decoder.decode_next_with(|bytes| {
SignedBeaconBlock::from_ssz_bytes_for_fork(bytes, fork_name)
})?;
let kzg_proofs = decoder.decode_next()?;
let blobs = decoder.decode_next()?;
Ok(PublishBlockRequest::new(block, Some((kzg_proofs, blobs))))
Ok(PublishBlockRequest::new(
Arc::new(block),
Some((kzg_proofs, blobs)),
))
}
}
}
pub fn signed_block(&self) -> &SignedBeaconBlock<T> {
pub fn signed_block(&self) -> &Arc<SignedBeaconBlock<T>> {
match self {
PublishBlockRequest::BlockContents(block_and_sidecars) => {
&block_and_sidecars.signed_block
@@ -1810,14 +1810,14 @@ pub fn into_full_block_and_blobs<T: EthSpec>(
let signed_block = blinded_block
.try_into_full_block(None)
.ok_or("Failed to build full block with payload".to_string())?;
Ok(PublishBlockRequest::new(signed_block, None))
Ok(PublishBlockRequest::new(Arc::new(signed_block), None))
}
// This variant implies a pre-deneb block
Some(FullPayloadContents::Payload(execution_payload)) => {
let signed_block = blinded_block
.try_into_full_block(Some(execution_payload))
.ok_or("Failed to build full block with payload".to_string())?;
Ok(PublishBlockRequest::new(signed_block, None))
Ok(PublishBlockRequest::new(Arc::new(signed_block), None))
}
// This variant implies a post-deneb block
Some(FullPayloadContents::PayloadAndBlobs(payload_and_blobs)) => {
@@ -1826,7 +1826,7 @@ pub fn into_full_block_and_blobs<T: EthSpec>(
.ok_or("Failed to build full block with payload".to_string())?;
Ok(PublishBlockRequest::new(
signed_block,
Arc::new(signed_block),
Some((
payload_and_blobs.blobs_bundle.proofs,
payload_and_blobs.blobs_bundle.blobs,
@@ -1836,10 +1836,10 @@ pub fn into_full_block_and_blobs<T: EthSpec>(
}
}
impl<T: EthSpec> TryFrom<SignedBeaconBlock<T>> for PublishBlockRequest<T> {
impl<T: EthSpec> TryFrom<Arc<SignedBeaconBlock<T>>> for PublishBlockRequest<T> {
type Error = &'static str;
fn try_from(block: SignedBeaconBlock<T>) -> Result<Self, Self::Error> {
match block {
fn try_from(block: Arc<SignedBeaconBlock<T>>) -> Result<Self, Self::Error> {
match *block {
SignedBeaconBlock::Base(_)
| SignedBeaconBlock::Altair(_)
| SignedBeaconBlock::Merge(_)
@@ -1860,7 +1860,7 @@ impl<T: EthSpec> From<SignedBlockContentsTuple<T>> for PublishBlockRequest<T> {
#[derive(Debug, Clone, Serialize, Deserialize, Encode)]
#[serde(bound = "T: EthSpec")]
pub struct SignedBlockContents<T: EthSpec> {
pub signed_block: SignedBeaconBlock<T>,
pub signed_block: Arc<SignedBeaconBlock<T>>,
pub kzg_proofs: KzgProofs<T>,
#[serde(with = "ssz_types::serde_utils::list_of_hex_fixed_vec")]
pub blobs: BlobsList<T>,

View File

@@ -1,145 +1,38 @@
# Extends the mainnet preset
PRESET_BASE: gnosis
# needs to exist because of Prysm. Otherwise it conflicts with mainnet genesis
CONFIG_NAME: chiado
PRESET_BASE: 'gnosis'
# Free-form short name of the network that this configuration applies to - known
# canonical network names include:
# * 'mainnet' - there can be only one
# * 'prater' - testnet
# Must match the regex: [a-z0-9\-]
CONFIG_NAME: 'chiado'
# Transition
# ---------------------------------------------------------------
# Projected time: 2022-11-04T15:00:00.000Z, block: 680928
TERMINAL_TOTAL_DIFFICULTY: 231707791542740786049188744689299064356246512
# By default, don't use these params
TERMINAL_BLOCK_HASH: 0x0000000000000000000000000000000000000000000000000000000000000000
TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH: 18446744073709551615
# Genesis
# ---------------------------------------------------------------
# *CUSTOM
MIN_GENESIS_ACTIVE_VALIDATOR_COUNT: 6000
# 10 October 2022 10:00:00 GMT+0000
MIN_GENESIS_TIME: 1665396000
GENESIS_DELAY: 300
# Projected time: 2022-11-04T15:00:00.000Z, block: 680928
TERMINAL_TOTAL_DIFFICULTY: 231707791542740786049188744689299064356246512
# Deposit contract
# ---------------------------------------------------------------
# NOTE: Don't use a value too high, or Teku rejects it (4294906129 NOK)
DEPOSIT_CHAIN_ID: 10200
DEPOSIT_NETWORK_ID: 10200
DEPOSIT_CONTRACT_ADDRESS: 0xb97036A26259B7147018913bD58a774cf91acf25
# Misc
# ---------------------------------------------------------------
# 2**6 (= 64)
MAX_COMMITTEES_PER_SLOT: 64
# 2**7 (= 128)
TARGET_COMMITTEE_SIZE: 128
# 2**11 (= 2,048)
MAX_VALIDATORS_PER_COMMITTEE: 2048
# 2**2 (= 4)
MIN_PER_EPOCH_CHURN_LIMIT: 4
# 2**3 (= 8)
MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT: 8
# 2**12 (= 4096)
CHURN_LIMIT_QUOTIENT: 4096
# See issue 563
SHUFFLE_ROUND_COUNT: 90
# 4
HYSTERESIS_QUOTIENT: 4
# 1 (minus 0.25)
HYSTERESIS_DOWNWARD_MULTIPLIER: 1
# 5 (plus 1.25)
HYSTERESIS_UPWARD_MULTIPLIER: 5
# Validator
# ---------------------------------------------------------------
# 2**10 (= 1024) ~1.4 hour
ETH1_FOLLOW_DISTANCE: 1024
# 2**4 (= 16)
TARGET_AGGREGATORS_PER_COMMITTEE: 16
# 2**0 (= 1)
RANDOM_SUBNETS_PER_VALIDATOR: 1
# 2**8 (= 256)
EPOCHS_PER_RANDOM_SUBNET_SUBSCRIPTION: 256
# 6 (estimate from xDai mainnet)
SECONDS_PER_ETH1_BLOCK: 6
# Gwei values
# ---------------------------------------------------------------
# 2**0 * 10**9 (= 1,000,000,000) Gwei
MIN_DEPOSIT_AMOUNT: 1000000000
# 2**5 * 10**9 (= 32,000,000,000) Gwei
MAX_EFFECTIVE_BALANCE: 32000000000
# 2**4 * 10**9 (= 16,000,000,000) Gwei
EJECTION_BALANCE: 16000000000
# 2**0 * 10**9 (= 1,000,000,000) Gwei
EFFECTIVE_BALANCE_INCREMENT: 1000000000
# Initial values
# ---------------------------------------------------------------
# GBC area code
GENESIS_FORK_VERSION: 0x0000006f
BLS_WITHDRAWAL_PREFIX: 0x00
# Time parameters
# ---------------------------------------------------------------
# 5 seconds
SECONDS_PER_SLOT: 5
# 2**0 (= 1) slots 12 seconds
MIN_ATTESTATION_INCLUSION_DELAY: 1
# 2**4 (= 16) slots 1.87 minutes
SLOTS_PER_EPOCH: 16
# 2**0 (= 1) epochs 1.87 minutes
MIN_SEED_LOOKAHEAD: 1
# 2**2 (= 4) epochs 7.47 minutes
MAX_SEED_LOOKAHEAD: 4
# 2**6 (= 64) epochs ~2 hours
EPOCHS_PER_ETH1_VOTING_PERIOD: 64
# 2**13 (= 8,192) slots ~15.9 hours
SLOTS_PER_HISTORICAL_ROOT: 8192
# 2**8 (= 256) epochs ~8 hours
MIN_VALIDATOR_WITHDRAWABILITY_DELAY: 256
# 2**8 (= 256) epochs ~8 hours
SHARD_COMMITTEE_PERIOD: 256
# 2**2 (= 4) epochs 7.47 minutes
MIN_EPOCHS_TO_INACTIVITY_PENALTY: 4
# *CUSTOM
GENESIS_DELAY: 300
# State vector lengths
# Forking
# ---------------------------------------------------------------
# 2**16 (= 65,536) epochs ~85 days
EPOCHS_PER_HISTORICAL_VECTOR: 65536
# 2**13 (= 8,192) epochs ~10.6 days
EPOCHS_PER_SLASHINGS_VECTOR: 8192
# 2**24 (= 16,777,216) historical roots, ~15,243 years
HISTORICAL_ROOTS_LIMIT: 16777216
# 2**40 (= 1,099,511,627,776) validator spots
VALIDATOR_REGISTRY_LIMIT: 1099511627776
# Reward and penalty quotients
# ---------------------------------------------------------------
# 25
BASE_REWARD_FACTOR: 25
# 2**9 (= 512)
WHISTLEBLOWER_REWARD_QUOTIENT: 512
# 2**3 (= 8)
PROPOSER_REWARD_QUOTIENT: 8
# 2**26 (= 67,108,864)
INACTIVITY_PENALTY_QUOTIENT: 67108864
# 2**7 (= 128) (lower safety margin at Phase 0 genesis)
MIN_SLASHING_PENALTY_QUOTIENT: 128
# 1 (lower safety margin at Phase 0 genesis)
PROPORTIONAL_SLASHING_MULTIPLIER: 1
# Max operations per block
# ---------------------------------------------------------------
# 2**4 (= 16)
MAX_PROPOSER_SLASHINGS: 16
# 2**1 (= 2)
MAX_ATTESTER_SLASHINGS: 2
# 2**7 (= 128)
MAX_ATTESTATIONS: 128
# 2**4 (= 16)
MAX_DEPOSITS: 16
# 2**4 (= 16)
MAX_VOLUNTARY_EXITS: 16
# Signature domains
# ---------------------------------------------------------------
DOMAIN_BEACON_PROPOSER: 0x00000000
DOMAIN_BEACON_ATTESTER: 0x01000000
DOMAIN_RANDAO: 0x02000000
DOMAIN_DEPOSIT: 0x03000000
DOMAIN_VOLUNTARY_EXIT: 0x04000000
DOMAIN_SELECTION_PROOF: 0x05000000
DOMAIN_AGGREGATE_AND_PROOF: 0x06000000
DOMAIN_SYNC_COMMITTEE: 0x07000000
DOMAIN_SYNC_COMMITTEE_SELECTION_PROOF: 0x08000000
DOMAIN_CONTRIBUTION_AND_PROOF: 0x09000000
# Some forks are disabled for now:
# - These may be re-assigned to another fork-version later
# - Temporarily set to max uint64 value: 2**64 - 1
# Altair
ALTAIR_FORK_VERSION: 0x0100006f
@@ -150,7 +43,95 @@ BELLATRIX_FORK_EPOCH: 180 # Mon Oct 10 2022 14:00:00 GMT+0000
# Capella
CAPELLA_FORK_VERSION: 0x0300006f
CAPELLA_FORK_EPOCH: 244224 # Wed May 24 2023 13:12:00 GMT+0000
# Deneb
DENEB_FORK_VERSION: 0x0400006f
DENEB_FORK_EPOCH: 516608 # Wed Jan 31 2024 18:15:40 GMT+0000
# Time parameters
# ---------------------------------------------------------------
# 5 seconds
SECONDS_PER_SLOT: 5
# 6 (estimate from xDai mainnet)
SECONDS_PER_ETH1_BLOCK: 6
# 2**8 (= 256) epochs ~5.7 hours
MIN_VALIDATOR_WITHDRAWABILITY_DELAY: 256
# 2**8 (= 256) epochs ~5.7 hours
SHARD_COMMITTEE_PERIOD: 256
# 2**10 (= 1024) ~1.4 hour
ETH1_FOLLOW_DISTANCE: 1024
# Validator cycle
# ---------------------------------------------------------------
# 2**2 (= 4)
INACTIVITY_SCORE_BIAS: 4
# 2**4 (= 16)
INACTIVITY_SCORE_RECOVERY_RATE: 16
# 2**4 * 10**9 (= 16,000,000,000) Gwei
EJECTION_BALANCE: 16000000000
# 2**2 (= 4)
MIN_PER_EPOCH_CHURN_LIMIT: 4
# 2**12 (= 4096)
CHURN_LIMIT_QUOTIENT: 4096
# [New in Deneb:EIP7514] 2*
MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT: 2
# Fork choice
# ---------------------------------------------------------------
# 40%
PROPOSER_SCORE_BOOST: 40
# 20%
REORG_HEAD_WEIGHT_THRESHOLD: 20
# 160%
REORG_PARENT_WEIGHT_THRESHOLD: 160
# `2` epochs
REORG_MAX_EPOCHS_SINCE_FINALIZATION: 2
# Deposit contract
# ---------------------------------------------------------------
# xDai Mainnet
DEPOSIT_CHAIN_ID: 10200
DEPOSIT_NETWORK_ID: 10200
DEPOSIT_CONTRACT_ADDRESS: 0xb97036A26259B7147018913bD58a774cf91acf25
# Networking
# ---------------------------------------------------------------
# `10 * 2**20` (= 10485760, 10 MiB)
GOSSIP_MAX_SIZE: 10485760
# `2**10` (= 1024)
MAX_REQUEST_BLOCKS: 1024
# `2**8` (= 256)
EPOCHS_PER_SUBNET_SUBSCRIPTION: 256
# 33024, ~31 days
MIN_EPOCHS_FOR_BLOCK_REQUESTS: 33024
# `10 * 2**20` (=10485760, 10 MiB)
MAX_CHUNK_SIZE: 10485760
# 5s
TTFB_TIMEOUT: 5
# 10s
RESP_TIMEOUT: 10
ATTESTATION_PROPAGATION_SLOT_RANGE: 32
# 500ms
MAXIMUM_GOSSIP_CLOCK_DISPARITY: 500
MESSAGE_DOMAIN_INVALID_SNAPPY: 0x00000000
MESSAGE_DOMAIN_VALID_SNAPPY: 0x01000000
# 2 subnets per node
SUBNETS_PER_NODE: 2
# 2**8 (= 64)
ATTESTATION_SUBNET_COUNT: 64
ATTESTATION_SUBNET_EXTRA_BITS: 0
# ceillog2(ATTESTATION_SUBNET_COUNT) + ATTESTATION_SUBNET_EXTRA_BITS
ATTESTATION_SUBNET_PREFIX_BITS: 6
# Deneb
# `2**7` (=128)
MAX_REQUEST_BLOCKS_DENEB: 128
# MAX_REQUEST_BLOCKS_DENEB * MAX_BLOBS_PER_BLOCK
MAX_REQUEST_BLOB_SIDECARS: 768
# `2**14` (= 16384 epochs, ~15 days)
MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS: 16384
# `6`
BLOB_SIDECAR_SUBNET_COUNT: 6

View File

@@ -33,6 +33,10 @@ TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH: 18446744073709551615
CAPELLA_FORK_VERSION: 0x04017000
CAPELLA_FORK_EPOCH: 256
# Deneb
DENEB_FORK_VERSION: 0x05017000
DENEB_FORK_EPOCH: 29696
# Time parameters
# ---------------------------------------------------------------
# 12 seconds
@@ -57,10 +61,10 @@ INACTIVITY_SCORE_RECOVERY_RATE: 16
EJECTION_BALANCE: 28000000000
# 2**2 (= 4)
MIN_PER_EPOCH_CHURN_LIMIT: 4
# 2**3 (= 8)
MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT: 8
# 2**16 (= 65,536)
CHURN_LIMIT_QUOTIENT: 65536
# [New in Deneb:EIP7514] 2**3 (= 8)
MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT: 8
# Fork choice
# ---------------------------------------------------------------

View File

@@ -33,12 +33,8 @@ CAPELLA_FORK_VERSION: 0x90000072
CAPELLA_FORK_EPOCH: 56832
# Deneb
DENEB_FORK_VERSION: 0x03001020
DENEB_FORK_EPOCH: 18446744073709551615
# Sharding
SHARDING_FORK_VERSION: 0x04001020
SHARDING_FORK_EPOCH: 18446744073709551615
DENEB_FORK_VERSION: 0x90000073
DENEB_FORK_EPOCH: 132608
# Time parameters
# ---------------------------------------------------------------
@@ -64,11 +60,10 @@ INACTIVITY_SCORE_RECOVERY_RATE: 16
EJECTION_BALANCE: 16000000000
# 2**2 (= 4)
MIN_PER_EPOCH_CHURN_LIMIT: 4
# 2**3 (= 8)
MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT: 8
# 2**16 (= 65,536)
CHURN_LIMIT_QUOTIENT: 65536
# [New in Deneb:EIP7514] 2**3 (= 8)
MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT: 8
# Fork choice
# ---------------------------------------------------------------
@@ -81,16 +76,41 @@ DEPOSIT_CHAIN_ID: 11155111
DEPOSIT_NETWORK_ID: 11155111
DEPOSIT_CONTRACT_ADDRESS: 0x7f02C3E3c98b133055B8B348B2Ac625669Ed295D
# Network
# Networking
# ---------------------------------------------------------------
SUBNETS_PER_NODE: 2
# `10 * 2**20` (= 10485760, 10 MiB)
GOSSIP_MAX_SIZE: 10485760
# `2**10` (= 1024)
MAX_REQUEST_BLOCKS: 1024
# `2**8` (= 256)
EPOCHS_PER_SUBNET_SUBSCRIPTION: 256
# `MIN_VALIDATOR_WITHDRAWABILITY_DELAY + CHURN_LIMIT_QUOTIENT // 2` (= 33024, ~5 months)
MIN_EPOCHS_FOR_BLOCK_REQUESTS: 33024
# `10 * 2**20` (=10485760, 10 MiB)
MAX_CHUNK_SIZE: 10485760
# 5s
TTFB_TIMEOUT: 5
# 10s
RESP_TIMEOUT: 10
ATTESTATION_PROPAGATION_SLOT_RANGE: 32
# 500ms
MAXIMUM_GOSSIP_CLOCK_DISPARITY: 500
MESSAGE_DOMAIN_INVALID_SNAPPY: 0x00000000
MESSAGE_DOMAIN_VALID_SNAPPY: 0x01000000
# 2 subnets per node
SUBNETS_PER_NODE: 2
# 2**8 (= 64)
ATTESTATION_SUBNET_COUNT: 64
ATTESTATION_SUBNET_EXTRA_BITS: 0
# ceillog2(ATTESTATION_SUBNET_COUNT) + ATTESTATION_SUBNET_EXTRA_BITS
ATTESTATION_SUBNET_PREFIX_BITS: 6
# Deneb
# `2**7` (=128)
MAX_REQUEST_BLOCKS_DENEB: 128
# MAX_REQUEST_BLOCKS_DENEB * MAX_BLOBS_PER_BLOCK
MAX_REQUEST_BLOB_SIDECARS: 768
# `2**12` (= 4096 epochs, ~18 days)
MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS: 4096
# `6`
BLOB_SIDECAR_SUBNET_COUNT: 6

View File

@@ -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/v4.6.0-rc.0-",
fallback = "Lighthouse/v4.6.0-rc.0"
prefix = "Lighthouse/v4.6.0-",
fallback = "Lighthouse/v4.6.0"
);
/// Returns `VERSION`, but with platform information appended to the end.

View File

@@ -10,6 +10,7 @@ use std::io::{Result, Write};
use std::path::PathBuf;
use std::time::{Duration, Instant};
use tracing_appender::non_blocking::NonBlocking;
use tracing_appender::rolling::{RollingFileAppender, Rotation};
use tracing_logging_layer::LoggingLayer;
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
@@ -21,7 +22,6 @@ mod tracing_logging_layer;
mod tracing_metrics_layer;
pub use sse_logging_components::SSELoggingComponents;
pub use tracing_logging_layer::cleanup_logging_task;
pub use tracing_metrics_layer::MetricsLayer;
/// The minimum interval between log messages indicating that a queue is full.
@@ -234,10 +234,27 @@ pub fn create_tracing_layer(base_tracing_log_path: PathBuf, turn_on_terminal_log
}
};
let libp2p_writer =
tracing_appender::rolling::daily(base_tracing_log_path.clone(), "libp2p.log");
let discv5_writer =
tracing_appender::rolling::daily(base_tracing_log_path.clone(), "discv5.log");
let Ok(libp2p_writer) = RollingFileAppender::builder()
.rotation(Rotation::DAILY)
.max_log_files(2)
.filename_prefix("libp2p")
.filename_suffix("log")
.build(base_tracing_log_path.clone())
else {
eprintln!("Failed to initialize libp2p rolling file appender");
return;
};
let Ok(discv5_writer) = RollingFileAppender::builder()
.rotation(Rotation::DAILY)
.max_log_files(2)
.filename_prefix("discv5")
.filename_suffix("log")
.build(base_tracing_log_path.clone())
else {
eprintln!("Failed to initialize discv5 rolling file appender");
return;
};
let (libp2p_non_blocking_writer, libp2p_guard) = NonBlocking::new(libp2p_writer);
let (discv5_non_blocking_writer, discv5_guard) = NonBlocking::new(discv5_writer);

View File

@@ -1,5 +1,4 @@
use chrono::{naive::Days, prelude::*};
use slog::{debug, warn};
use chrono::prelude::*;
use std::io::Write;
use tracing::Subscriber;
use tracing_appender::non_blocking::{NonBlocking, WorkerGuard};
@@ -55,61 +54,3 @@ impl tracing_core::field::Visit for LogMessageExtractor {
self.message = format!("{} {:?}", self.message, value);
}
}
/// Creates a long lived async task that routinely deletes old tracing log files
pub async fn cleanup_logging_task(path: std::path::PathBuf, log: slog::Logger) {
loop {
// Delay for 1 day and then prune old logs
tokio::time::sleep(std::time::Duration::from_secs(60 * 60 * 24)).await;
let Some(yesterday_date) = chrono::prelude::Local::now()
.naive_local()
.checked_sub_days(Days::new(1))
else {
warn!(log, "Could not calculate the current date");
return;
};
// Search for old log files
let dir = path.as_path();
if dir.is_dir() {
let Ok(files) = std::fs::read_dir(dir) else {
warn!(log, "Could not read log directory contents"; "path" => ?dir);
break;
};
for file in files {
let Ok(dir_entry) = file else {
warn!(log, "Could not read file");
continue;
};
let Ok(file_name) = dir_entry.file_name().into_string() else {
warn!(log, "Could not read file"; "file" => ?dir_entry);
continue;
};
if file_name.starts_with("libp2p.log") | file_name.starts_with("discv5.log") {
let log_file_date = file_name.split('.').collect::<Vec<_>>();
if log_file_date.len() == 3 {
let Ok(log_file_date_type) =
NaiveDate::parse_from_str(log_file_date[2], "%Y-%m-%d")
else {
warn!(log, "Could not parse log file date"; "file" => file_name);
continue;
};
if log_file_date_type < yesterday_date.into() {
// Delete the file, its too old
debug!(log, "Removing old log file"; "file" => &file_name);
if let Err(e) = std::fs::remove_file(dir_entry.path()) {
warn!(log, "Failed to remove log file"; "file" => file_name, "error" => %e);
}
}
}
}
}
}
}
}

View File

@@ -14,8 +14,10 @@ beacon_chain = { workspace = true }
state_processing = { workspace = true }
safe_arith = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
tokio = { workspace = true }
headers = "0.3.2"
lighthouse_metrics = { workspace = true }
lazy_static = { workspace = true }
serde_array_query = "0.1.0"
bytes = { workspace = true }

View File

@@ -0,0 +1,22 @@
use bytes::Bytes;
use serde::de::DeserializeOwned;
use std::error::Error as StdError;
use warp::{Filter, Rejection};
use crate::reject;
struct Json;
type BoxError = Box<dyn StdError + Send + Sync>;
impl Json {
fn decode<T: DeserializeOwned>(bytes: Bytes) -> Result<T, BoxError> {
serde_json::from_slice(&bytes).map_err(Into::into)
}
}
pub fn json<T: DeserializeOwned + Send>() -> impl Filter<Extract = (T,), Error = Rejection> + Copy {
warp::body::bytes().and_then(|bytes: Bytes| async move {
Json::decode(bytes).map_err(|err| reject::custom_deserialize_error(format!("{:?}", err)))
})
}

View File

@@ -2,6 +2,7 @@
//! Lighthouse project. E.g., the `http_api` and `http_metrics` crates.
pub mod cors;
pub mod json;
pub mod metrics;
pub mod query;
pub mod reject;

View File

@@ -82,6 +82,15 @@ pub fn custom_bad_request(msg: String) -> warp::reject::Rejection {
warp::reject::custom(CustomBadRequest(msg))
}
#[derive(Debug)]
pub struct CustomDeserializeError(pub String);
impl Reject for CustomDeserializeError {}
pub fn custom_deserialize_error(msg: String) -> warp::reject::Rejection {
warp::reject::custom(CustomDeserializeError(msg))
}
#[derive(Debug)]
pub struct CustomServerError(pub String);
@@ -161,6 +170,9 @@ pub async fn handle_rejection(err: warp::Rejection) -> Result<impl warp::Reply,
if err.is_not_found() {
code = StatusCode::NOT_FOUND;
message = "NOT_FOUND".to_string();
} else if let Some(e) = err.find::<crate::reject::CustomDeserializeError>() {
message = format!("BAD_REQUEST: body deserialize error: {}", e.0);
code = StatusCode::BAD_REQUEST;
} else if let Some(e) = err.find::<warp::filters::body::BodyDeserializeError>() {
message = format!("BAD_REQUEST: body deserialize error: {}", e);
code = StatusCode::BAD_REQUEST;