mirror of
https://github.com/sigp/lighthouse.git
synced 2026-03-15 02:42:38 +00:00
Merge remote-tracking branch 'origin/unstable' into tree-states
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -10,6 +10,7 @@ pub const DEFAULT_NETWORK_DIR: &str = "network";
|
||||
pub const DEFAULT_VALIDATOR_DIR: &str = "validators";
|
||||
pub const DEFAULT_SECRET_DIR: &str = "secrets";
|
||||
pub const DEFAULT_WALLET_DIR: &str = "wallets";
|
||||
pub const DEFAULT_TRACING_DIR: &str = "tracing";
|
||||
|
||||
/// Base directory name for unnamed testnets passed through the --testnet-dir flag
|
||||
pub const CUSTOM_TESTNET_DIR: &str = "custom";
|
||||
|
||||
@@ -46,6 +46,9 @@ pub const EXECUTION_PAYLOAD_BLINDED_HEADER: &str = "Eth-Execution-Payload-Blinde
|
||||
pub const EXECUTION_PAYLOAD_VALUE_HEADER: &str = "Eth-Execution-Payload-Value";
|
||||
pub const CONSENSUS_BLOCK_VALUE_HEADER: &str = "Eth-Consensus-Block-Value";
|
||||
|
||||
pub const CONTENT_TYPE_HEADER: &str = "Content-Type";
|
||||
pub const SSZ_CONTENT_TYPE_HEADER: &str = "application/octet-stream";
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
/// The `reqwest` client raised an error.
|
||||
@@ -374,25 +377,6 @@ impl BeaconNodeHttpClient {
|
||||
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>(
|
||||
&self,
|
||||
url: U,
|
||||
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?;
|
||||
ok_or_error(response).await
|
||||
}
|
||||
|
||||
/// Generic POST function supporting arbitrary responses and timeouts.
|
||||
async fn post_generic_with_consensus_version<T: Serialize, U: IntoUrl>(
|
||||
&self,
|
||||
@@ -863,10 +847,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?;
|
||||
|
||||
@@ -907,8 +892,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(())
|
||||
}
|
||||
@@ -1074,8 +1064,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);
|
||||
};
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
)
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -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::*;
|
||||
@@ -1480,15 +1481,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(_)));
|
||||
}
|
||||
@@ -1504,11 +1505,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(_)));
|
||||
}
|
||||
}
|
||||
@@ -1643,7 +1647,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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1674,7 +1678,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,
|
||||
@@ -1729,12 +1736,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 {
|
||||
@@ -1747,23 +1754,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);
|
||||
@@ -1772,16 +1768,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
|
||||
@@ -1811,14 +1811,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)) => {
|
||||
@@ -1827,7 +1827,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,
|
||||
@@ -1837,10 +1837,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(_)
|
||||
@@ -1861,7 +1861,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>,
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
# ---------------------------------------------------------------
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
- enr:-Ku4QPn5eVhcoF1opaFEvg1b6JNFD2rqVkHQ8HApOKK61OIcIXD127bKWgAtbwI7pnxx6cDyk_nI88TrZKQaGMZj0q0Bh2F0dG5ldHOIAAAAAAAAAACEZXRoMpC1MD8qAAAAAP__________gmlkgnY0gmlwhDayLMaJc2VjcDI1NmsxoQK2sBOLGcUb4AwuYzFuAVCaNHA-dy24UuEKkeFNgCVCsIN1ZHCCIyg
|
||||
- enr:-Ku4QEWzdnVtXc2Q0ZVigfCGggOVB2Vc1ZCPEc6j21NIFLODSJbvNaef1g4PxhPwl_3kax86YPheFUSLXPRs98vvYsoBh2F0dG5ldHOIAAAAAAAAAACEZXRoMpC1MD8qAAAAAP__________gmlkgnY0gmlwhDZBrP2Jc2VjcDI1NmsxoQM6jr8Rb1ktLEsVcKAPa08wCsKUmvoQ8khiOl_SLozf9IN1ZHCCIyg
|
||||
# Teku team (Consensys)
|
||||
- enr:-KG4QMOEswP62yzDjSwWS4YEjtTZ5PO6r65CPqYBkgTTkrpaedQ8uEUo1uMALtJIvb2w_WWEVmg5yt1UAuK1ftxUU7QDhGV0aDKQu6TalgMAAAD__________4JpZIJ2NIJpcIQEnfA2iXNlY3AyNTZrMaEDfol8oLr6XJ7FsdAYE7lpJhKMls4G_v6qQOGKJUWGb_uDdGNwgiMog3VkcIIjKA
|
||||
- enr:-KG4QNTx85fjxABbSq_Rta9wy56nQ1fHK0PewJbGjLm1M4bMGx5-3Qq4ZX2-iFJ0pys_O90sVXNNOxp2E7afBsGsBrgDhGV0aDKQu6TalgMAAAD__________4JpZIJ2NIJpcIQEnfA2iXNlY3AyNTZrMaECGXWQ-rQ2KZKRH1aOW4IlPDBkY4XDphxg9pxKytFCkayDdGNwgiMog3VkcIIjKA
|
||||
- enr:-KG4QF4B5WrlFcRhUU6dZETwY5ZzAXnA0vGC__L1Kdw602nDZwXSTs5RFXFIFUnbQJmhNGVU6OIX7KVrCSTODsz1tK4DhGV0aDKQu6TalgMAAAD__________4JpZIJ2NIJpcIQExNYEiXNlY3AyNTZrMaECQmM9vp7KhaXhI-nqL_R0ovULLCFSFTa9CPPSdb1zPX6DdGNwgiMog3VkcIIjKA
|
||||
# Prysm team (Prysmatic Labs)
|
||||
- enr:-Ku4QImhMc1z8yCiNJ1TyUxdcfNucje3BGwEHzodEZUan8PherEo4sF7pPHPSIB1NNuSg5fZy7qFsjmUKs2ea1Whi0EBh2F0dG5ldHOIAAAAAAAAAACEZXRoMpD1pf1CAAAAAP__________gmlkgnY0gmlwhBLf22SJc2VjcDI1NmsxoQOVphkDqal4QzPMksc5wnpuC3gvSC8AfbFOnZY_On34wIN1ZHCCIyg
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -8,15 +8,20 @@ edition = { workspace = true }
|
||||
test_logger = [] # Print log output to stderr when running tests instead of dropping it
|
||||
|
||||
[dependencies]
|
||||
slog = { workspace = true }
|
||||
slog-term = { workspace = true }
|
||||
tokio = { workspace = true }
|
||||
lighthouse_metrics = { workspace = true }
|
||||
chrono = { version = "0.4", default-features = false, features = ["clock", "std"] }
|
||||
lazy_static = { workspace = true }
|
||||
sloggers = { workspace = true }
|
||||
slog-async = { workspace = true }
|
||||
take_mut = "0.2.2"
|
||||
lighthouse_metrics = { workspace = true }
|
||||
parking_lot = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
chrono = { version = "0.4", default-features = false, features = ["clock", "std"] }
|
||||
slog = { workspace = true }
|
||||
slog-async = { workspace = true }
|
||||
slog-term = { workspace = true }
|
||||
sloggers = { workspace = true }
|
||||
take_mut = "0.2.2"
|
||||
tokio = { workspace = true, features = [ "time" ] }
|
||||
tracing = "0.1"
|
||||
tracing-core = { workspace = true }
|
||||
tracing-log = { workspace = true }
|
||||
tracing-subscriber = { workspace = true }
|
||||
tracing-appender = { workspace = true }
|
||||
|
||||
@@ -7,13 +7,22 @@ use lighthouse_metrics::{
|
||||
use slog::Logger;
|
||||
use slog_term::Decorator;
|
||||
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};
|
||||
|
||||
pub const MAX_MESSAGE_WIDTH: usize = 40;
|
||||
|
||||
pub mod async_record;
|
||||
mod sse_logging_components;
|
||||
mod tracing_logging_layer;
|
||||
mod tracing_metrics_layer;
|
||||
|
||||
pub use sse_logging_components::SSELoggingComponents;
|
||||
pub use tracing_metrics_layer::MetricsLayer;
|
||||
|
||||
/// The minimum interval between log messages indicating that a queue is full.
|
||||
const LOG_DEBOUNCE_INTERVAL: Duration = Duration::from_secs(30);
|
||||
@@ -214,6 +223,65 @@ impl TimeLatch {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_tracing_layer(base_tracing_log_path: PathBuf, turn_on_terminal_logs: bool) {
|
||||
let filter_layer = match tracing_subscriber::EnvFilter::try_from_default_env()
|
||||
.or_else(|_| tracing_subscriber::EnvFilter::try_new("warn"))
|
||||
{
|
||||
Ok(filter) => filter,
|
||||
Err(e) => {
|
||||
eprintln!("Failed to initialize dependency logging {e}");
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
let custom_layer = LoggingLayer {
|
||||
libp2p_non_blocking_writer,
|
||||
libp2p_guard,
|
||||
discv5_non_blocking_writer,
|
||||
discv5_guard,
|
||||
};
|
||||
|
||||
if let Err(e) = tracing_subscriber::fmt()
|
||||
.with_env_filter(filter_layer)
|
||||
.with_writer(move || {
|
||||
tracing_subscriber::fmt::writer::OptionalWriter::<std::io::Stdout>::from(
|
||||
turn_on_terminal_logs.then(std::io::stdout),
|
||||
)
|
||||
})
|
||||
.finish()
|
||||
.with(MetricsLayer)
|
||||
.with(custom_layer)
|
||||
.try_init()
|
||||
{
|
||||
eprintln!("Failed to initialize dependency logging {e}");
|
||||
}
|
||||
}
|
||||
|
||||
/// Return a logger suitable for test usage.
|
||||
///
|
||||
/// By default no logs will be printed, but they can be enabled via
|
||||
|
||||
56
common/logging/src/tracing_logging_layer.rs
Normal file
56
common/logging/src/tracing_logging_layer.rs
Normal file
@@ -0,0 +1,56 @@
|
||||
use chrono::prelude::*;
|
||||
use std::io::Write;
|
||||
use tracing::Subscriber;
|
||||
use tracing_appender::non_blocking::{NonBlocking, WorkerGuard};
|
||||
use tracing_subscriber::layer::Context;
|
||||
use tracing_subscriber::Layer;
|
||||
|
||||
pub struct LoggingLayer {
|
||||
pub libp2p_non_blocking_writer: NonBlocking,
|
||||
pub libp2p_guard: WorkerGuard,
|
||||
pub discv5_non_blocking_writer: NonBlocking,
|
||||
pub discv5_guard: WorkerGuard,
|
||||
}
|
||||
|
||||
impl<S> Layer<S> for LoggingLayer
|
||||
where
|
||||
S: Subscriber,
|
||||
{
|
||||
fn on_event(&self, event: &tracing::Event<'_>, _ctx: Context<S>) {
|
||||
let meta = event.metadata();
|
||||
let log_level = meta.level();
|
||||
let timestamp = Local::now().format("%Y-%m-%d %H:%M:%S").to_string();
|
||||
|
||||
let target = match meta.target().split_once("::") {
|
||||
Some((crate_name, _)) => crate_name,
|
||||
None => "unknown",
|
||||
};
|
||||
|
||||
let mut writer = match target {
|
||||
"libp2p_gossipsub" => self.libp2p_non_blocking_writer.clone(),
|
||||
"discv5" => self.discv5_non_blocking_writer.clone(),
|
||||
_ => return,
|
||||
};
|
||||
|
||||
let mut visitor = LogMessageExtractor {
|
||||
message: String::default(),
|
||||
};
|
||||
|
||||
event.record(&mut visitor);
|
||||
let message = format!("{} {} {}\n", timestamp, log_level, visitor.message);
|
||||
|
||||
if let Err(e) = writer.write_all(message.as_bytes()) {
|
||||
eprintln!("Failed to write log: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct LogMessageExtractor {
|
||||
message: String,
|
||||
}
|
||||
|
||||
impl tracing_core::field::Visit for LogMessageExtractor {
|
||||
fn record_debug(&mut self, _: &tracing_core::Field, value: &dyn std::fmt::Debug) {
|
||||
self.message = format!("{} {:?}", self.message, value);
|
||||
}
|
||||
}
|
||||
63
common/logging/src/tracing_metrics_layer.rs
Normal file
63
common/logging/src/tracing_metrics_layer.rs
Normal file
@@ -0,0 +1,63 @@
|
||||
//! Exposes [`MetricsLayer`]: A tracing layer that registers metrics of logging events.
|
||||
|
||||
use lighthouse_metrics as metrics;
|
||||
use tracing_log::NormalizeEvent;
|
||||
|
||||
lazy_static! {
|
||||
/// Count of `INFO` logs registered per enabled dependency.
|
||||
pub static ref DEP_INFOS_TOTAL: metrics::Result<metrics::IntCounterVec> =
|
||||
metrics::try_create_int_counter_vec(
|
||||
"dep_info_total",
|
||||
"Count of infos logged per enabled dependency",
|
||||
&["target"]
|
||||
);
|
||||
/// Count of `WARN` logs registered per enabled dependency.
|
||||
pub static ref DEP_WARNS_TOTAL: metrics::Result<metrics::IntCounterVec> =
|
||||
metrics::try_create_int_counter_vec(
|
||||
"dep_warn_total",
|
||||
"Count of warns logged per enabled dependency",
|
||||
&["target"]
|
||||
);
|
||||
/// Count of `ERROR` logs registered per enabled dependency.
|
||||
pub static ref DEP_ERRORS_TOTAL: metrics::Result<metrics::IntCounterVec> =
|
||||
metrics::try_create_int_counter_vec(
|
||||
"dep_error_total",
|
||||
"Count of errors logged per enabled dependency",
|
||||
&["target"]
|
||||
);
|
||||
}
|
||||
|
||||
/// Layer that registers Prometheus metrics for `INFO`, `WARN` and `ERROR` logs emitted per dependency.
|
||||
/// Dependencies are enabled via the `RUST_LOG` env flag.
|
||||
pub struct MetricsLayer;
|
||||
|
||||
impl<S: tracing_core::Subscriber> tracing_subscriber::layer::Layer<S> for MetricsLayer {
|
||||
fn on_event(
|
||||
&self,
|
||||
event: &tracing_core::Event<'_>,
|
||||
_ctx: tracing_subscriber::layer::Context<'_, S>,
|
||||
) {
|
||||
// get the event's normalized metadata
|
||||
// this is necessary to get the correct module path for libp2p events
|
||||
let normalized_meta = event.normalized_metadata();
|
||||
let meta = normalized_meta.as_ref().unwrap_or_else(|| event.metadata());
|
||||
|
||||
if !meta.is_event() {
|
||||
// ignore tracing span events
|
||||
return;
|
||||
}
|
||||
|
||||
let full_target = meta.module_path().unwrap_or_else(|| meta.target());
|
||||
let target = full_target
|
||||
.split_once("::")
|
||||
.map(|(name, _rest)| name)
|
||||
.unwrap_or(full_target);
|
||||
let target = &[target];
|
||||
match *meta.level() {
|
||||
tracing_core::Level::INFO => metrics::inc_counter_vec(&DEP_INFOS_TOTAL, target),
|
||||
tracing_core::Level::WARN => metrics::inc_counter_vec(&DEP_WARNS_TOTAL, target),
|
||||
tracing_core::Level::ERROR => metrics::inc_counter_vec(&DEP_ERRORS_TOTAL, target),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
//! Due to `jemalloc` requiring configuration at compile time or immediately upon runtime
|
||||
//! initialisation it is configured via a Cargo config file in `.cargo/config.toml`.
|
||||
//!
|
||||
//! The `jemalloc` tuning can be overriden by:
|
||||
//! The `jemalloc` tuning can be overridden by:
|
||||
//!
|
||||
//! A) `JEMALLOC_SYS_WITH_MALLOC_CONF` at compile-time.
|
||||
//! B) `_RJEM_MALLOC_CONF` at runtime.
|
||||
|
||||
Reference in New Issue
Block a user