Merge remote-tracking branch 'origin/unstable' into tree-states

This commit is contained in:
Michael Sproul
2022-09-14 13:51:23 +10:00
404 changed files with 28947 additions and 12000 deletions

View File

@@ -45,6 +45,29 @@ pub enum Error {
UnableToCreateValidatorDir(PathBuf),
}
#[derive(Clone, PartialEq, Serialize, Deserialize, Hash, Eq)]
pub struct Web3SignerDefinition {
pub url: String,
/// Path to a .pem file.
#[serde(skip_serializing_if = "Option::is_none")]
pub root_certificate_path: Option<PathBuf>,
/// Specifies a request timeout.
///
/// The timeout is applied from when the request starts connecting until the response body has finished.
#[serde(skip_serializing_if = "Option::is_none")]
pub request_timeout_ms: Option<u64>,
/// Path to a PKCS12 file.
#[serde(skip_serializing_if = "Option::is_none")]
pub client_identity_path: Option<PathBuf>,
/// Password for the PKCS12 file.
///
/// An empty password will be used if this is omitted.
#[serde(skip_serializing_if = "Option::is_none")]
pub client_identity_password: Option<String>,
}
/// Defines how the validator client should attempt to sign messages for this validator.
#[derive(Clone, PartialEq, Serialize, Deserialize)]
#[serde(tag = "type")]
@@ -62,27 +85,7 @@ pub enum SigningDefinition {
///
/// https://github.com/ConsenSys/web3signer
#[serde(rename = "web3signer")]
Web3Signer {
url: String,
/// Path to a .pem file.
#[serde(skip_serializing_if = "Option::is_none")]
root_certificate_path: Option<PathBuf>,
/// Specifies a request timeout.
///
/// The timeout is applied from when the request starts connecting until the response body has finished.
#[serde(skip_serializing_if = "Option::is_none")]
request_timeout_ms: Option<u64>,
/// Path to a PKCS12 file.
#[serde(skip_serializing_if = "Option::is_none")]
client_identity_path: Option<PathBuf>,
/// Password for the PKCS12 file.
///
/// An empty password will be used if this is omitted.
#[serde(skip_serializing_if = "Option::is_none")]
client_identity_password: Option<String>,
},
Web3Signer(Web3SignerDefinition),
}
impl SigningDefinition {
@@ -106,6 +109,12 @@ pub struct ValidatorDefinition {
#[serde(skip_serializing_if = "Option::is_none")]
pub suggested_fee_recipient: Option<Address>,
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub gas_limit: Option<u64>,
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub builder_proposals: Option<bool>,
#[serde(default)]
pub description: String,
#[serde(flatten)]
pub signing_definition: SigningDefinition,
@@ -123,6 +132,8 @@ impl ValidatorDefinition {
voting_keystore_password: Option<ZeroizeString>,
graffiti: Option<GraffitiString>,
suggested_fee_recipient: Option<Address>,
gas_limit: Option<u64>,
builder_proposals: Option<bool>,
) -> Result<Self, Error> {
let voting_keystore_path = voting_keystore_path.as_ref().into();
let keystore =
@@ -135,6 +146,8 @@ impl ValidatorDefinition {
description: keystore.description().unwrap_or("").to_string(),
graffiti,
suggested_fee_recipient,
gas_limit,
builder_proposals,
signing_definition: SigningDefinition::LocalKeystore {
voting_keystore_path,
voting_keystore_password_path: None,
@@ -281,6 +294,8 @@ impl ValidatorDefinitions {
description: keystore.description().unwrap_or("").to_string(),
graffiti: None,
suggested_fee_recipient: None,
gas_limit: None,
builder_proposals: None,
signing_definition: SigningDefinition::LocalKeystore {
voting_keystore_path,
voting_keystore_password_path,
@@ -523,4 +538,84 @@ mod tests {
Some(Address::from_str("0xa2e334e71511686bcfe38bb3ee1ad8f6babcc03d").unwrap())
);
}
#[test]
fn gas_limit_checks() {
let no_gas_limit = r#"---
description: ""
enabled: true
type: local_keystore
suggested_fee_recipient: "0xa2e334e71511686bcfe38bb3ee1ad8f6babcc03d"
voting_keystore_path: ""
voting_public_key: "0xaf3c7ddab7e293834710fca2d39d068f884455ede270e0d0293dc818e4f2f0f975355067e8437955cb29aec674e5c9e7"
"#;
let def: ValidatorDefinition = serde_yaml::from_str(no_gas_limit).unwrap();
assert!(def.gas_limit.is_none());
let invalid_gas_limit = r#"---
description: ""
enabled: true
type: local_keystore
suggested_fee_recipient: "0xa2e334e71511686bcfe38bb3ee1ad8f6babcc03d"
gas_limit: "banana"
voting_keystore_path: ""
voting_public_key: "0xaf3c7ddab7e293834710fca2d39d068f884455ede270e0d0293dc818e4f2f0f975355067e8437955cb29aec674e5c9e7"
"#;
let def: Result<ValidatorDefinition, _> = serde_yaml::from_str(invalid_gas_limit);
assert!(def.is_err());
let valid_gas_limit = r#"---
description: ""
enabled: true
type: local_keystore
suggested_fee_recipient: "0xa2e334e71511686bcfe38bb3ee1ad8f6babcc03d"
gas_limit: 35000000
voting_keystore_path: ""
voting_public_key: "0xaf3c7ddab7e293834710fca2d39d068f884455ede270e0d0293dc818e4f2f0f975355067e8437955cb29aec674e5c9e7"
"#;
let def: ValidatorDefinition = serde_yaml::from_str(valid_gas_limit).unwrap();
assert_eq!(def.gas_limit, Some(35000000));
}
#[test]
fn builder_proposals_checks() {
let no_builder_proposals = r#"---
description: ""
enabled: true
type: local_keystore
suggested_fee_recipient: "0xa2e334e71511686bcfe38bb3ee1ad8f6babcc03d"
voting_keystore_path: ""
voting_public_key: "0xaf3c7ddab7e293834710fca2d39d068f884455ede270e0d0293dc818e4f2f0f975355067e8437955cb29aec674e5c9e7"
"#;
let def: ValidatorDefinition = serde_yaml::from_str(no_builder_proposals).unwrap();
assert!(def.builder_proposals.is_none());
let invalid_builder_proposals = r#"---
description: ""
enabled: true
type: local_keystore
suggested_fee_recipient: "0xa2e334e71511686bcfe38bb3ee1ad8f6babcc03d"
builder_proposals: "banana"
voting_keystore_path: ""
voting_public_key: "0xaf3c7ddab7e293834710fca2d39d068f884455ede270e0d0293dc818e4f2f0f975355067e8437955cb29aec674e5c9e7"
"#;
let def: Result<ValidatorDefinition, _> = serde_yaml::from_str(invalid_builder_proposals);
assert!(def.is_err());
let valid_builder_proposals = r#"---
description: ""
enabled: true
type: local_keystore
suggested_fee_recipient: "0xa2e334e71511686bcfe38bb3ee1ad8f6babcc03d"
builder_proposals: true
voting_keystore_path: ""
voting_public_key: "0xaf3c7ddab7e293834710fca2d39d068f884455ede270e0d0293dc818e4f2f0f975355067e8437955cb29aec674e5c9e7"
"#;
let def: ValidatorDefinition = serde_yaml::from_str(valid_builder_proposals).unwrap();
assert_eq!(def.builder_proposals, Some(true));
}
}

View File

@@ -54,12 +54,10 @@ fn read_contract_file_from_url(url: Url) -> Result<Value, String> {
.map_err(|e| format!("Respsonse is not a valid json {:?}", e))?;
Ok(contract)
}
Err(e) => {
return Err(format!(
"No abi file found. Failed to download from github: {:?}",
e
))
}
Err(e) => Err(format!(
"No abi file found. Failed to download from github: {:?}",
e
)),
}
}
}

View File

@@ -23,7 +23,7 @@ use lighthouse_network::PeerId;
pub use reqwest;
use reqwest::{IntoUrl, RequestBuilder, Response};
pub use reqwest::{StatusCode, Url};
use sensitive_url::SensitiveUrl;
pub use sensitive_url::SensitiveUrl;
use serde::{de::DeserializeOwned, Serialize};
use std::convert::TryFrom;
use std::fmt;
@@ -110,7 +110,10 @@ pub struct Timeouts {
pub liveness: Duration,
pub proposal: Duration,
pub proposer_duties: Duration,
pub sync_committee_contribution: Duration,
pub sync_duties: Duration,
pub get_beacon_blocks_ssz: Duration,
pub get_debug_beacon_states: Duration,
}
impl Timeouts {
@@ -121,7 +124,10 @@ impl Timeouts {
liveness: timeout,
proposal: timeout,
proposer_duties: timeout,
sync_committee_contribution: timeout,
sync_duties: timeout,
get_beacon_blocks_ssz: timeout,
get_debug_beacon_states: timeout,
}
}
}
@@ -237,9 +243,10 @@ impl BeaconNodeHttpClient {
&self,
url: U,
accept_header: Accept,
timeout: Duration,
) -> Result<Option<Vec<u8>>, Error> {
let opt_response = self
.get_response(url, |b| b.accept(accept_header))
.get_response(url, |b| b.accept(accept_header).timeout(timeout))
.await
.optional()?;
match opt_response {
@@ -330,7 +337,7 @@ impl BeaconNodeHttpClient {
pub async fn get_beacon_states_root(
&self,
state_id: StateId,
) -> Result<Option<GenericResponse<RootData>>, Error> {
) -> Result<Option<ExecutionOptimisticResponse<RootData>>, Error> {
let mut path = self.eth_path(V1)?;
path.path_segments_mut()
@@ -349,7 +356,7 @@ impl BeaconNodeHttpClient {
pub async fn get_beacon_states_fork(
&self,
state_id: StateId,
) -> Result<Option<GenericResponse<Fork>>, Error> {
) -> Result<Option<ExecutionOptimisticResponse<Fork>>, Error> {
let mut path = self.eth_path(V1)?;
path.path_segments_mut()
@@ -368,7 +375,7 @@ impl BeaconNodeHttpClient {
pub async fn get_beacon_states_finality_checkpoints(
&self,
state_id: StateId,
) -> Result<Option<GenericResponse<FinalityCheckpointsData>>, Error> {
) -> Result<Option<ExecutionOptimisticResponse<FinalityCheckpointsData>>, Error> {
let mut path = self.eth_path(V1)?;
path.path_segments_mut()
@@ -388,7 +395,7 @@ impl BeaconNodeHttpClient {
&self,
state_id: StateId,
ids: Option<&[ValidatorId]>,
) -> Result<Option<GenericResponse<Vec<ValidatorBalanceData>>>, Error> {
) -> Result<Option<ExecutionOptimisticResponse<Vec<ValidatorBalanceData>>>, Error> {
let mut path = self.eth_path(V1)?;
path.path_segments_mut()
@@ -418,7 +425,7 @@ impl BeaconNodeHttpClient {
state_id: StateId,
ids: Option<&[ValidatorId]>,
statuses: Option<&[ValidatorStatus]>,
) -> Result<Option<GenericResponse<Vec<ValidatorData>>>, Error> {
) -> Result<Option<ExecutionOptimisticResponse<Vec<ValidatorData>>>, Error> {
let mut path = self.eth_path(V1)?;
path.path_segments_mut()
@@ -458,7 +465,7 @@ impl BeaconNodeHttpClient {
slot: Option<Slot>,
index: Option<u64>,
epoch: Option<Epoch>,
) -> Result<Option<GenericResponse<Vec<CommitteeData>>>, Error> {
) -> Result<Option<ExecutionOptimisticResponse<Vec<CommitteeData>>>, Error> {
let mut path = self.eth_path(V1)?;
path.path_segments_mut()
@@ -491,7 +498,7 @@ impl BeaconNodeHttpClient {
&self,
state_id: StateId,
epoch: Option<Epoch>,
) -> Result<GenericResponse<SyncCommitteeByValidatorIndices>, Error> {
) -> Result<ExecutionOptimisticResponse<SyncCommitteeByValidatorIndices>, Error> {
let mut path = self.eth_path(V1)?;
path.path_segments_mut()
@@ -516,7 +523,7 @@ impl BeaconNodeHttpClient {
&self,
state_id: StateId,
validator_id: &ValidatorId,
) -> Result<Option<GenericResponse<ValidatorData>>, Error> {
) -> Result<Option<ExecutionOptimisticResponse<ValidatorData>>, Error> {
let mut path = self.eth_path(V1)?;
path.path_segments_mut()
@@ -537,7 +544,7 @@ impl BeaconNodeHttpClient {
&self,
slot: Option<Slot>,
parent_root: Option<Hash256>,
) -> Result<Option<GenericResponse<Vec<BlockHeaderData>>>, Error> {
) -> Result<Option<ExecutionOptimisticResponse<Vec<BlockHeaderData>>>, Error> {
let mut path = self.eth_path(V1)?;
path.path_segments_mut()
@@ -564,7 +571,7 @@ impl BeaconNodeHttpClient {
pub async fn get_beacon_headers_block_id(
&self,
block_id: BlockId,
) -> Result<Option<GenericResponse<BlockHeaderData>>, Error> {
) -> Result<Option<ExecutionOptimisticResponse<BlockHeaderData>>, Error> {
let mut path = self.eth_path(V1)?;
path.path_segments_mut()
@@ -633,7 +640,7 @@ impl BeaconNodeHttpClient {
pub async fn get_beacon_blocks<T: EthSpec>(
&self,
block_id: BlockId,
) -> Result<Option<ForkVersionedResponse<SignedBeaconBlock<T>>>, Error> {
) -> Result<Option<ExecutionOptimisticForkVersionedResponse<SignedBeaconBlock<T>>>, Error> {
let path = self.get_beacon_blocks_path(block_id)?;
let response = match self.get_response(path, |b| b).await.optional()? {
Some(res) => res,
@@ -642,20 +649,31 @@ impl BeaconNodeHttpClient {
// If present, use the fork provided in the headers to decode the block. Gracefully handle
// missing and malformed fork names by falling back to regular deserialisation.
let (block, version) = match response.fork_name_from_header() {
let (block, version, execution_optimistic) = match response.fork_name_from_header() {
Ok(Some(fork_name)) => {
map_fork_name_with!(fork_name, SignedBeaconBlock, {
let ForkVersionedResponse { version, data } = response.json().await?;
(data, version)
})
let (data, (version, execution_optimistic)) =
map_fork_name_with!(fork_name, SignedBeaconBlock, {
let ExecutionOptimisticForkVersionedResponse {
version,
execution_optimistic,
data,
} = response.json().await?;
(data, (version, execution_optimistic))
});
(data, version, execution_optimistic)
}
Ok(None) | Err(_) => {
let ForkVersionedResponse { version, data } = response.json().await?;
(data, version)
let ExecutionOptimisticForkVersionedResponse {
version,
execution_optimistic,
data,
} = response.json().await?;
(data, version, execution_optimistic)
}
};
Ok(Some(ForkVersionedResponse {
Ok(Some(ExecutionOptimisticForkVersionedResponse {
version,
execution_optimistic,
data: block,
}))
}
@@ -688,7 +706,7 @@ impl BeaconNodeHttpClient {
) -> Result<Option<SignedBeaconBlock<T>>, Error> {
let path = self.get_beacon_blocks_path(block_id)?;
self.get_bytes_opt_accept_header(path, Accept::Ssz)
self.get_bytes_opt_accept_header(path, Accept::Ssz, self.timeouts.get_beacon_blocks_ssz)
.await?
.map(|bytes| SignedBeaconBlock::from_ssz_bytes(&bytes, spec).map_err(Error::InvalidSsz))
.transpose()
@@ -700,7 +718,7 @@ impl BeaconNodeHttpClient {
pub async fn get_beacon_blocks_root(
&self,
block_id: BlockId,
) -> Result<Option<GenericResponse<RootData>>, Error> {
) -> Result<Option<ExecutionOptimisticResponse<RootData>>, Error> {
let mut path = self.eth_path(V1)?;
path.path_segments_mut()
@@ -719,7 +737,7 @@ impl BeaconNodeHttpClient {
pub async fn get_beacon_blocks_attestations<T: EthSpec>(
&self,
block_id: BlockId,
) -> Result<Option<GenericResponse<Vec<Attestation<T>>>>, Error> {
) -> Result<Option<ExecutionOptimisticResponse<Vec<Attestation<T>>>>, Error> {
let mut path = self.eth_path(V1)?;
path.path_segments_mut()
@@ -907,7 +925,12 @@ impl BeaconNodeHttpClient {
.push("validator")
.push("contribution_and_proofs");
self.post(path, &signed_contributions).await?;
self.post_with_timeout(
path,
&signed_contributions,
self.timeouts.sync_committee_contribution,
)
.await?;
Ok(())
}
@@ -929,6 +952,23 @@ impl BeaconNodeHttpClient {
Ok(())
}
/// `POST validator/register_validator`
pub async fn post_validator_register_validator(
&self,
registration_data: &[SignedValidatorRegistrationData],
) -> Result<(), Error> {
let mut path = self.eth_path(V1)?;
path.path_segments_mut()
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
.push("validator")
.push("register_validator");
self.post(path, &registration_data).await?;
Ok(())
}
/// `GET config/fork_schedule`
pub async fn get_config_fork_schedule(&self) -> Result<GenericResponse<Vec<Fork>>, Error> {
let mut path = self.eth_path(V1)?;
@@ -942,7 +982,9 @@ impl BeaconNodeHttpClient {
}
/// `GET config/spec`
pub async fn get_config_spec(&self) -> Result<GenericResponse<ConfigAndPreset>, Error> {
pub async fn get_config_spec<T: Serialize + DeserializeOwned>(
&self,
) -> Result<GenericResponse<T>, Error> {
let mut path = self.eth_path(V1)?;
path.path_segments_mut()
@@ -1099,7 +1141,7 @@ impl BeaconNodeHttpClient {
pub async fn get_debug_beacon_states<T: EthSpec>(
&self,
state_id: StateId,
) -> Result<Option<ForkVersionedResponse<BeaconState<T>>>, Error> {
) -> Result<Option<ExecutionOptimisticForkVersionedResponse<BeaconState<T>>>, Error> {
let path = self.get_debug_beacon_states_path(state_id)?;
self.get_opt(path).await
}
@@ -1108,7 +1150,7 @@ impl BeaconNodeHttpClient {
pub async fn get_debug_beacon_states_v1<T: EthSpec>(
&self,
state_id: StateId,
) -> Result<Option<ForkVersionedResponse<BeaconState<T>>>, Error> {
) -> Result<Option<ExecutionOptimisticForkVersionedResponse<BeaconState<T>>>, Error> {
let mut path = self.eth_path(V1)?;
path.path_segments_mut()
@@ -1130,15 +1172,30 @@ impl BeaconNodeHttpClient {
) -> Result<Option<BeaconState<T>>, Error> {
let path = self.get_debug_beacon_states_path(state_id)?;
self.get_bytes_opt_accept_header(path, Accept::Ssz)
self.get_bytes_opt_accept_header(path, Accept::Ssz, self.timeouts.get_debug_beacon_states)
.await?
.map(|bytes| BeaconState::from_ssz_bytes(&bytes, spec).map_err(Error::InvalidSsz))
.transpose()
}
/// `GET debug/beacon/heads`
/// `GET v2/debug/beacon/heads`
pub async fn get_debug_beacon_heads(
&self,
) -> Result<GenericResponse<Vec<ChainHeadData>>, Error> {
let mut path = self.eth_path(V2)?;
path.path_segments_mut()
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
.push("debug")
.push("beacon")
.push("heads");
self.get(path).await
}
/// `GET v1/debug/beacon/heads` (LEGACY)
pub async fn get_debug_beacon_heads_v1(
&self,
) -> Result<GenericResponse<Vec<ChainHeadData>>, Error> {
let mut path = self.eth_path(V1)?;
@@ -1230,7 +1287,7 @@ impl BeaconNodeHttpClient {
.await
}
/// `GET v2/validator/blocks/{slot}`
/// `GET v1/validator/blinded_blocks/{slot}`
pub async fn get_validator_blinded_blocks_with_verify_randao<
T: EthSpec,
Payload: ExecPayload<T>,
@@ -1241,7 +1298,7 @@ impl BeaconNodeHttpClient {
graffiti: Option<&Graffiti>,
verify_randao: Option<bool>,
) -> Result<ForkVersionedResponse<BeaconBlock<T, Payload>>, Error> {
let mut path = self.eth_path(V2)?;
let mut path = self.eth_path(V1)?;
path.path_segments_mut()
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
@@ -1470,7 +1527,7 @@ impl BeaconNodeHttpClient {
&self,
epoch: Epoch,
indices: &[u64],
) -> Result<GenericResponse<Vec<SyncDuty>>, Error> {
) -> Result<ExecutionOptimisticResponse<Vec<SyncDuty>>, Error> {
let mut path = self.eth_path(V1)?;
path.path_segments_mut()
@@ -1491,7 +1548,7 @@ impl BeaconNodeHttpClient {
/// Returns `Ok(response)` if the response is a `200 OK` response. Otherwise, creates an
/// appropriate error message.
async fn ok_or_error(response: Response) -> Result<Response, Error> {
pub async fn ok_or_error(response: Response) -> Result<Response, Error> {
let status = response.status();
if status == StatusCode::OK {

View File

@@ -1,6 +1,6 @@
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use types::{Hash256, Slot};
use types::{AttestationData, Hash256, Slot};
/// Details about the rewards paid to a block proposer for proposing a block.
///
@@ -42,6 +42,9 @@ pub struct AttestationRewards {
///
/// Each element of the vec is a map from validator index to reward.
pub per_attestation_rewards: Vec<HashMap<u64, u64>>,
/// The attestations themselves (optional).
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub attestations: Vec<AttestationData>,
}
/// Query parameters for the `/lighthouse/block_rewards` endpoint.
@@ -51,4 +54,7 @@ pub struct BlockRewardsQuery {
pub start_slot: Slot,
/// Upper slot limit for block rewards returned (inclusive).
pub end_slot: Slot,
/// Include the full attestations themselves?
#[serde(default)]
pub include_attestations: bool,
}

View File

@@ -303,11 +303,11 @@ impl ValidatorClientHttpClient {
}
/// Perform a HTTP DELETE request.
async fn delete_with_unsigned_response<T: Serialize, U: IntoUrl, V: DeserializeOwned>(
async fn delete_with_raw_response<T: Serialize, U: IntoUrl>(
&self,
url: U,
body: &T,
) -> Result<V, Error> {
) -> Result<Response, Error> {
let response = self
.client
.delete(url)
@@ -316,7 +316,16 @@ impl ValidatorClientHttpClient {
.send()
.await
.map_err(Error::Reqwest)?;
let response = ok_or_error(response).await?;
ok_or_error(response).await
}
/// Perform a HTTP DELETE request.
async fn delete_with_unsigned_response<T: Serialize, U: IntoUrl, V: DeserializeOwned>(
&self,
url: U,
body: &T,
) -> Result<V, Error> {
let response = self.delete_with_raw_response(url, body).await?;
Ok(response.json().await?)
}
@@ -345,7 +354,9 @@ impl ValidatorClientHttpClient {
}
/// `GET lighthouse/spec`
pub async fn get_lighthouse_spec(&self) -> Result<GenericResponse<ConfigAndPreset>, Error> {
pub async fn get_lighthouse_spec<T: Serialize + DeserializeOwned>(
&self,
) -> Result<GenericResponse<T>, Error> {
let mut path = self.server.full.clone();
path.path_segments_mut()
@@ -453,7 +464,9 @@ impl ValidatorClientHttpClient {
pub async fn patch_lighthouse_validators(
&self,
voting_pubkey: &PublicKeyBytes,
enabled: bool,
enabled: Option<bool>,
gas_limit: Option<u64>,
builder_proposals: Option<bool>,
) -> Result<(), Error> {
let mut path = self.server.full.clone();
@@ -463,7 +476,15 @@ impl ValidatorClientHttpClient {
.push("validators")
.push(&voting_pubkey.to_string());
self.patch(path, &ValidatorPatchRequest { enabled }).await
self.patch(
path,
&ValidatorPatchRequest {
enabled,
gas_limit,
builder_proposals,
},
)
.await
}
fn make_keystores_url(&self) -> Result<Url, Error> {
@@ -486,6 +507,30 @@ impl ValidatorClientHttpClient {
Ok(url)
}
fn make_fee_recipient_url(&self, pubkey: &PublicKeyBytes) -> Result<Url, Error> {
let mut url = self.server.full.clone();
url.path_segments_mut()
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
.push("eth")
.push("v1")
.push("validator")
.push(&pubkey.to_string())
.push("feerecipient");
Ok(url)
}
fn make_gas_limit_url(&self, pubkey: &PublicKeyBytes) -> Result<Url, Error> {
let mut url = self.server.full.clone();
url.path_segments_mut()
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
.push("eth")
.push("v1")
.push("validator")
.push(&pubkey.to_string())
.push("gas_limit");
Ok(url)
}
/// `GET lighthouse/auth`
pub async fn get_auth(&self) -> Result<AuthResponse, Error> {
let mut url = self.server.full.clone();
@@ -543,14 +588,71 @@ impl ValidatorClientHttpClient {
let url = self.make_remotekeys_url()?;
self.delete_with_unsigned_response(url, req).await
}
/// `GET /eth/v1/validator/{pubkey}/feerecipient`
pub async fn get_fee_recipient(
&self,
pubkey: &PublicKeyBytes,
) -> Result<GetFeeRecipientResponse, Error> {
let url = self.make_fee_recipient_url(pubkey)?;
self.get(url)
.await
.map(|generic: GenericResponse<GetFeeRecipientResponse>| generic.data)
}
/// `POST /eth/v1/validator/{pubkey}/feerecipient`
pub async fn post_fee_recipient(
&self,
pubkey: &PublicKeyBytes,
req: &UpdateFeeRecipientRequest,
) -> Result<Response, Error> {
let url = self.make_fee_recipient_url(pubkey)?;
self.post_with_raw_response(url, req).await
}
/// `DELETE /eth/v1/validator/{pubkey}/feerecipient`
pub async fn delete_fee_recipient(&self, pubkey: &PublicKeyBytes) -> Result<Response, Error> {
let url = self.make_fee_recipient_url(pubkey)?;
self.delete_with_raw_response(url, &()).await
}
/// `GET /eth/v1/validator/{pubkey}/gas_limit`
pub async fn get_gas_limit(
&self,
pubkey: &PublicKeyBytes,
) -> Result<GetGasLimitResponse, Error> {
let url = self.make_gas_limit_url(pubkey)?;
self.get(url)
.await
.map(|generic: GenericResponse<GetGasLimitResponse>| generic.data)
}
/// `POST /eth/v1/validator/{pubkey}/gas_limit`
pub async fn post_gas_limit(
&self,
pubkey: &PublicKeyBytes,
req: &UpdateGasLimitRequest,
) -> Result<Response, Error> {
let url = self.make_gas_limit_url(pubkey)?;
self.post_with_raw_response(url, req).await
}
/// `DELETE /eth/v1/validator/{pubkey}/gas_limit`
pub async fn delete_gas_limit(&self, pubkey: &PublicKeyBytes) -> Result<Response, Error> {
let url = self.make_gas_limit_url(pubkey)?;
self.delete_with_raw_response(url, &()).await
}
}
/// Returns `Ok(response)` if the response is a `200 OK` response. Otherwise, creates an
/// appropriate error message.
/// Returns `Ok(response)` if the response is a `200 OK` response or a
/// `202 Accepted` response. Otherwise, creates an appropriate error message.
async fn ok_or_error(response: Response) -> Result<Response, Error> {
let status = response.status();
if status == StatusCode::OK {
if status == StatusCode::OK
|| status == StatusCode::ACCEPTED
|| status == StatusCode::NO_CONTENT
{
Ok(response)
} else if let Ok(message) = response.json().await {
Err(Error::ServerMessage(message))

View File

@@ -2,7 +2,20 @@ use account_utils::ZeroizeString;
use eth2_keystore::Keystore;
use serde::{Deserialize, Serialize};
use slashing_protection::interchange::Interchange;
use types::PublicKeyBytes;
use types::{Address, PublicKeyBytes};
#[derive(Debug, Deserialize, Serialize, PartialEq)]
pub struct GetFeeRecipientResponse {
pub pubkey: PublicKeyBytes,
pub ethaddress: Address,
}
#[derive(Debug, Deserialize, Serialize, PartialEq)]
pub struct GetGasLimitResponse {
pub pubkey: PublicKeyBytes,
#[serde(with = "eth2_serde_utils::quoted_u64")]
pub gas_limit: u64,
}
#[derive(Debug, Deserialize, Serialize, PartialEq)]
pub struct AuthResponse {

View File

@@ -26,6 +26,12 @@ pub struct ValidatorRequest {
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub suggested_fee_recipient: Option<Address>,
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub gas_limit: Option<u64>,
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub builder_proposals: Option<bool>,
#[serde(with = "eth2_serde_utils::quoted_u64")]
pub deposit_gwei: u64,
}
@@ -49,6 +55,12 @@ pub struct CreatedValidator {
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub suggested_fee_recipient: Option<Address>,
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub gas_limit: Option<u64>,
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub builder_proposals: Option<bool>,
pub eth1_deposit_tx_data: String,
#[serde(with = "eth2_serde_utils::quoted_u64")]
pub deposit_gwei: u64,
@@ -62,7 +74,15 @@ pub struct PostValidatorsResponseData {
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ValidatorPatchRequest {
pub enabled: bool,
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub enabled: Option<bool>,
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub gas_limit: Option<u64>,
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub builder_proposals: Option<bool>,
}
#[derive(Clone, PartialEq, Serialize, Deserialize)]
@@ -70,8 +90,18 @@ pub struct KeystoreValidatorsPostRequest {
pub password: ZeroizeString,
pub enable: bool,
pub keystore: Keystore,
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub graffiti: Option<GraffitiString>,
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub suggested_fee_recipient: Option<Address>,
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub gas_limit: Option<u64>,
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub builder_proposals: Option<bool>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
@@ -84,6 +114,12 @@ pub struct Web3SignerValidatorRequest {
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub suggested_fee_recipient: Option<Address>,
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub gas_limit: Option<u64>,
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub builder_proposals: Option<bool>,
pub voting_public_key: PublicKey,
pub url: String,
#[serde(default)]
@@ -97,3 +133,14 @@ pub struct Web3SignerValidatorRequest {
#[serde(skip_serializing_if = "Option::is_none")]
pub client_identity_password: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct UpdateFeeRecipientRequest {
pub ethaddress: Address,
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct UpdateGasLimitRequest {
#[serde(with = "eth2_serde_utils::quoted_u64")]
pub gas_limit: u64,
}

View File

@@ -21,17 +21,17 @@ impl ResponseOptional for Result<Response, Error> {
/// Trait for extracting the fork name from the headers of a response.
pub trait ResponseForkName {
#[allow(clippy::result_unit_err)]
fn fork_name_from_header(&self) -> Result<Option<ForkName>, ()>;
fn fork_name_from_header(&self) -> Result<Option<ForkName>, String>;
}
impl ResponseForkName for Response {
fn fork_name_from_header(&self) -> Result<Option<ForkName>, ()> {
fn fork_name_from_header(&self) -> Result<Option<ForkName>, String> {
self.headers()
.get(CONSENSUS_VERSION_HEADER)
.map(|fork_name| {
fork_name
.to_str()
.map_err(|_| ())
.map_err(|e| e.to_string())
.and_then(ForkName::from_str)
})
.transpose()

View File

@@ -189,6 +189,14 @@ impl fmt::Display for StateId {
#[serde(bound = "T: Serialize + serde::de::DeserializeOwned")]
pub struct DutiesResponse<T: Serialize + serde::de::DeserializeOwned> {
pub dependent_root: Hash256,
pub execution_optimistic: Option<bool>,
pub data: T,
}
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
#[serde(bound = "T: Serialize + serde::de::DeserializeOwned")]
pub struct ExecutionOptimisticResponse<T: Serialize + serde::de::DeserializeOwned> {
pub execution_optimistic: Option<bool>,
pub data: T,
}
@@ -204,6 +212,18 @@ impl<T: Serialize + serde::de::DeserializeOwned> From<T> for GenericResponse<T>
}
}
impl<T: Serialize + serde::de::DeserializeOwned> GenericResponse<T> {
pub fn add_execution_optimistic(
self,
execution_optimistic: bool,
) -> ExecutionOptimisticResponse<T> {
ExecutionOptimisticResponse {
execution_optimistic: Some(execution_optimistic),
data: self.data,
}
}
}
#[derive(Debug, PartialEq, Clone, Serialize)]
#[serde(bound = "T: Serialize")]
pub struct GenericResponseRef<'a, T: Serialize> {
@@ -216,6 +236,14 @@ impl<'a, T: Serialize> From<&'a T> for GenericResponseRef<'a, T> {
}
}
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
pub struct ExecutionOptimisticForkVersionedResponse<T> {
#[serde(skip_serializing_if = "Option::is_none")]
pub version: Option<ForkName>,
pub execution_optimistic: Option<bool>,
pub data: T,
}
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
pub struct ForkVersionedResponse<T> {
#[serde(skip_serializing_if = "Option::is_none")]
@@ -495,6 +523,8 @@ pub struct DepositContractData {
pub struct ChainHeadData {
pub slot: Slot,
pub root: Hash256,
#[serde(skip_serializing_if = "Option::is_none")]
pub execution_optimistic: Option<bool>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
@@ -522,6 +552,7 @@ pub struct VersionData {
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct SyncingData {
pub is_syncing: bool,
pub is_optimistic: Option<bool>,
pub head_slot: Slot,
pub sync_distance: Slot,
}
@@ -651,7 +682,7 @@ pub struct ValidatorAggregateAttestationQuery {
pub slot: Slot,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)]
pub struct BeaconCommitteeSubscription {
#[serde(with = "eth2_serde_utils::quoted_u64")]
pub validator_index: u64,
@@ -794,6 +825,7 @@ pub struct PeerCount {
pub struct SseBlock {
pub slot: Slot,
pub block: Hash256,
pub execution_optimistic: bool,
}
#[derive(PartialEq, Debug, Serialize, Deserialize, Clone)]
@@ -801,6 +833,7 @@ pub struct SseFinalizedCheckpoint {
pub block: Hash256,
pub state: Hash256,
pub epoch: Epoch,
pub execution_optimistic: bool,
}
#[derive(PartialEq, Debug, Serialize, Deserialize, Clone)]
@@ -811,6 +844,7 @@ pub struct SseHead {
pub current_duty_dependent_root: Hash256,
pub previous_duty_dependent_root: Hash256,
pub epoch_transition: bool,
pub execution_optimistic: bool,
}
#[derive(PartialEq, Debug, Serialize, Deserialize, Clone)]
@@ -823,6 +857,7 @@ pub struct SseChainReorg {
pub new_head_block: Hash256,
pub new_head_state: Hash256,
pub epoch: Epoch,
pub execution_optimistic: bool,
}
#[derive(PartialEq, Debug, Serialize, Deserialize, Clone)]
@@ -838,6 +873,7 @@ pub struct SseLateHead {
pub attestable_delay: Option<Duration>,
pub imported_delay: Option<Duration>,
pub set_as_head_delay: Option<Duration>,
pub execution_optimistic: bool,
}
#[derive(PartialEq, Debug, Serialize, Clone)]

View File

@@ -69,7 +69,7 @@ impl Eth2Config {
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Eth2NetArchiveAndDirectory<'a> {
pub name: &'a str,
pub unique_id: &'a str,
pub config_dir: &'a str,
pub genesis_is_known: bool,
}
@@ -81,7 +81,7 @@ impl<'a> Eth2NetArchiveAndDirectory<'a> {
.parse::<PathBuf>()
.expect("should parse manifest dir as path")
.join(PREDEFINED_NETWORKS_DIR)
.join(self.unique_id)
.join(self.config_dir)
}
pub fn genesis_state_archive(&self) -> PathBuf {
@@ -96,6 +96,7 @@ const GENESIS_STATE_IS_KNOWN: bool = true;
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct HardcodedNet {
pub name: &'static str,
pub config_dir: &'static str,
pub genesis_is_known: bool,
pub config: &'static [u8],
pub deploy_block: &'static [u8],
@@ -108,15 +109,15 @@ pub struct HardcodedNet {
/// It also defines a `include_<title>_file!` macro which provides a wrapper around
/// `std::include_bytes`, allowing the inclusion of bytes from the specific testnet directory.
macro_rules! define_archive {
($name_ident: ident, $name_str: tt, $genesis_is_known: ident) => {
($name_ident: ident, $config_dir: tt, $genesis_is_known: ident) => {
paste! {
#[macro_use]
pub mod $name_ident {
use super::*;
pub const ETH2_NET_DIR: Eth2NetArchiveAndDirectory = Eth2NetArchiveAndDirectory {
name: $name_str,
unique_id: $name_str,
name: stringify!($name_ident),
config_dir: $config_dir,
genesis_is_known: $genesis_is_known,
};
@@ -130,7 +131,7 @@ macro_rules! define_archive {
"/",
$this_crate::predefined_networks_dir!(),
"/",
$name_str,
$config_dir,
"/",
$filename
))
@@ -149,6 +150,7 @@ macro_rules! define_net {
$this_crate::HardcodedNet {
name: ETH2_NET_DIR.name,
config_dir: ETH2_NET_DIR.config_dir,
genesis_is_known: ETH2_NET_DIR.genesis_is_known,
config: $this_crate::$include_file!($this_crate, "../", "config.yaml"),
deploy_block: $this_crate::$include_file!($this_crate, "../", "deploy_block.txt"),
@@ -164,13 +166,13 @@ macro_rules! define_net {
/// - `HARDCODED_NET_NAMES`: a list of the *names* of the networks defined by this macro.
#[macro_export]
macro_rules! define_nets {
($this_crate: ident, $($name_ident: ident, $name_str: tt,)+) => {
($this_crate: ident, $($name_ident: ident,)+) => {
$this_crate::paste! {
$(
const [<$name_ident:upper>]: $this_crate::HardcodedNet = $this_crate::define_net!($this_crate, $name_ident, [<include_ $name_ident _file>]);
)+
const HARDCODED_NETS: &[$this_crate::HardcodedNet] = &[$([<$name_ident:upper>],)+];
pub const HARDCODED_NET_NAMES: &[&'static str] = &[$($name_str,)+];
pub const HARDCODED_NET_NAMES: &[&'static str] = &[$(stringify!($name_ident),)+];
}
};
}
@@ -197,9 +199,9 @@ macro_rules! define_nets {
/// `build.rs` which will unzip the genesis states. Then, that `eth2_network_configs` crate can
/// perform the final step of using `std::include_bytes` to bake the files (bytes) into the binary.
macro_rules! define_hardcoded_nets {
($(($name_ident: ident, $name_str: tt, $genesis_is_known: ident)),+) => {
($(($name_ident: ident, $config_dir: tt, $genesis_is_known: ident)),+) => {
$(
define_archive!($name_ident, $name_str, $genesis_is_known);
define_archive!($name_ident, $config_dir, $genesis_is_known);
)+
pub const ETH2_NET_DIRS: &[Eth2NetArchiveAndDirectory<'static>] = &[$($name_ident::ETH2_NET_DIR,)+];
@@ -213,7 +215,7 @@ macro_rules! define_hardcoded_nets {
#[macro_export]
macro_rules! instantiate_hardcoded_nets {
($this_crate: ident) => {
$this_crate::define_nets!($this_crate, $($name_ident, $name_str,)+);
$this_crate::define_nets!($this_crate, $($name_ident,)+);
}
}
};
@@ -234,9 +236,76 @@ macro_rules! define_hardcoded_nets {
//
// The directory containing the testnet files should match the human-friendly name (element 1).
define_hardcoded_nets!(
(mainnet, "mainnet", GENESIS_STATE_IS_KNOWN),
(prater, "prater", GENESIS_STATE_IS_KNOWN),
(gnosis, "gnosis", GENESIS_STATE_IS_KNOWN),
(kiln, "kiln", GENESIS_STATE_IS_KNOWN),
(ropsten, "ropsten", GENESIS_STATE_IS_KNOWN)
(
// Network name (must be unique among all networks).
mainnet,
// The name of the directory in the `eth2_network_config/built_in_network_configs`
// directory where the configuration files are located for this network.
"mainnet",
// Set to `true` if the genesis state can be found in the `built_in_network_configs`
// directory.
GENESIS_STATE_IS_KNOWN
),
(
// Network name (must be unique among all networks).
prater,
// The name of the directory in the `eth2_network_config/built_in_network_configs`
// directory where the configuration files are located for this network.
"prater",
// Set to `true` if the genesis state can be found in the `built_in_network_configs`
// directory.
GENESIS_STATE_IS_KNOWN
),
(
// Network name (must be unique among all networks).
goerli,
// The name of the directory in the `eth2_network_config/built_in_network_configs`
// directory where the configuration files are located for this network.
//
// The Goerli network is effectively an alias to Prater.
"prater",
// Set to `true` if the genesis state can be found in the `built_in_network_configs`
// directory.
GENESIS_STATE_IS_KNOWN
),
(
// Network name (must be unique among all networks).
gnosis,
// The name of the directory in the `eth2_network_config/built_in_network_configs`
// directory where the configuration files are located for this network.
"gnosis",
// Set to `true` if the genesis state can be found in the `built_in_network_configs`
// directory.
GENESIS_STATE_IS_KNOWN
),
(
// Network name (must be unique among all networks).
kiln,
// The name of the directory in the `eth2_network_config/built_in_network_configs`
// directory where the configuration files are located for this network.
"kiln",
// Set to `true` if the genesis state can be found in the `built_in_network_configs`
// directory.
GENESIS_STATE_IS_KNOWN
),
(
// Network name (must be unique among all networks).
ropsten,
// The name of the directory in the `eth2_network_config/built_in_network_configs`
// directory where the configuration files are located for this network.
"ropsten",
// Set to `true` if the genesis state can be found in the `built_in_network_configs`
// directory.
GENESIS_STATE_IS_KNOWN
),
(
// Network name (must be unique among all networks).
sepolia,
// The name of the directory in the `eth2_network_config/built_in_network_configs`
// directory where the configuration files are located for this network.
"sepolia",
// Set to `true` if the genesis state can be found in the `built_in_network_configs`
// directory.
GENESIS_STATE_IS_KNOWN
)
);

View File

@@ -6,7 +6,7 @@ PRESET_BASE: 'mainnet'
MIN_GENESIS_ACTIVE_VALIDATOR_COUNT: 95000
# Mar 11th, 2022, 14:00 UTC
MIN_GENESIS_TIME: 1647007200
# Gensis fork
# Genesis fork
GENESIS_FORK_VERSION: 0x70000069
# 300 seconds (5 min)
GENESIS_DELAY: 300

View File

@@ -6,8 +6,8 @@ PRESET_BASE: 'mainnet'
# Transition
# ---------------------------------------------------------------
# TBD, 2**256-2**10 is a placeholder
TERMINAL_TOTAL_DIFFICULTY: 115792089237316195423570985008687907853269984665640564039457584007913129638912
# Estimated on Sept 15, 2022
TERMINAL_TOTAL_DIFFICULTY: 58750000000000000000000
# By default, don't use these params
TERMINAL_BLOCK_HASH: 0x0000000000000000000000000000000000000000000000000000000000000000
TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH: 18446744073709551615
@@ -35,7 +35,7 @@ ALTAIR_FORK_VERSION: 0x01000000
ALTAIR_FORK_EPOCH: 74240
# Merge
BELLATRIX_FORK_VERSION: 0x02000000
BELLATRIX_FORK_EPOCH: 18446744073709551615
BELLATRIX_FORK_EPOCH: 144896 # Sept 6, 2022, 11:34:47am UTC
# Sharding
SHARDING_FORK_VERSION: 0x03000000
SHARDING_FORK_EPOCH: 18446744073709551615

View File

@@ -7,4 +7,11 @@
# Prysm bootnode #1
- enr:-Ku4QFmUkNp0g9bsLX2PfVeIyT-9WO-PZlrqZBNtEyofOOfLMScDjaTzGxIb1Ns9Wo5Pm_8nlq-SZwcQfTH2cgO-s88Bh2F0dG5ldHOIAAAAAAAAAACEZXRoMpDkvpOTAAAQIP__________gmlkgnY0gmlwhBLf22SJc2VjcDI1NmsxoQLV_jMOIxKbjHFKgrkFvwDvpexo6Nd58TK5k7ss4Vt0IoN1ZHCCG1g
# Lighthouse bootnode #1
- enr:-LK4QLINdtobGquK7jukLDAKmsrH2ZuHM4k0TklY5jDTD4ZgfxR9weZmo5Jwu81hlKu3qPAvk24xHGBDjYs4o8f1gZ0Bh2F0dG5ldHOIAAAAAAAAAACEZXRoMpB53wQoAAAQIP__________gmlkgnY0gmlwhDRN_P6Jc2VjcDI1NmsxoQJuNujTgsJUHUgVZML3pzrtgNtYg7rQ4K1tkWERgl0DdoN0Y3CCIyiDdWRwgiMo
- enr:-Ly4QFPk-cTMxZ3jWTafiNblEZkQIXGF2aVzCIGW0uHp6KaEAvBMoctE8S7YU0qZtuS7By0AA4YMfKoN9ls_GJRccVpFh2F0dG5ldHOI__________-EZXRoMpCC9KcrAgAQIIS2AQAAAAAAgmlkgnY0gmlwhKh3joWJc2VjcDI1NmsxoQKrxz8M1IHwJqRIpDqdVW_U1PeixMW5SfnBD-8idYIQrIhzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA
# Lighthouse bootnode #2
- enr:-L64QJmwSDtaHVgGiqIxJWUtxWg6uLCipsms6j-8BdsOJfTWAs7CLF9HJnVqFE728O-JYUDCxzKvRdeMqBSauHVCMdaCAVWHYXR0bmV0c4j__________4RldGgykIL0pysCABAghLYBAAAAAACCaWSCdjSCaXCEQWxOdolzZWNwMjU2azGhA7Qmod9fK86WidPOzLsn5_8QyzL7ZcJ1Reca7RnD54vuiHN5bmNuZXRzD4N0Y3CCIyiDdWRwgiMo
# Nimbus bootstrap nodes
- enr:-LK4QMzPq4Q7w5R-rnGQDcI8BYky6oPVBGQTbS1JJLVtNi_8PzBLV7Bdzsoame9nJK5bcJYpGHn4SkaDN2CM6tR5G_4Bh2F0dG5ldHOIAAAAAAAAAACEZXRoMpB53wQoAAAQIP__________gmlkgnY0gmlwhAN4yvyJc2VjcDI1NmsxoQKa8Qnp_P2clLIP6VqLKOp_INvEjLszalEnW0LoBZo4YYN0Y3CCI4yDdWRwgiOM
- enr:-LK4QLM_pPHa78R8xlcU_s40Y3XhFjlb3kPddW9lRlY67N5qeFE2Wo7RgzDgRs2KLCXODnacVHMFw1SfpsW3R474RZEBh2F0dG5ldHOIAAAAAAAAAACEZXRoMpB53wQoAAAQIP__________gmlkgnY0gmlwhANBY-yJc2VjcDI1NmsxoQNsZkFXgKbTzuxF7uwxlGauTGJelE6HD269CcFlZ_R7A4N0Y3CCI4yDdWRwgiOM
# Teku bootnode
- enr:-KK4QH0RsNJmIG0EX9LSnVxMvg-CAOr3ZFF92hunU63uE7wcYBjG1cFbUTvEa5G_4nDJkRhUq9q2ck9xY-VX1RtBsruBtIRldGgykIL0pysBABAg__________-CaWSCdjSCaXCEEnXQ0YlzZWNwMjU2azGhA1grTzOdMgBvjNrk-vqWtTZsYQIi0QawrhoZrsn5Hd56g3RjcIIjKIN1ZHCCIyg

View File

@@ -6,8 +6,7 @@ PRESET_BASE: 'mainnet'
# Transition
# ---------------------------------------------------------------
# TBD, 2**256-2**10 is a placeholder
TERMINAL_TOTAL_DIFFICULTY: 115792089237316195423570985008687907853269984665640564039457584007913129638912
TERMINAL_TOTAL_DIFFICULTY: 10790000
# By default, don't use these params
TERMINAL_BLOCK_HASH: 0x0000000000000000000000000000000000000000000000000000000000000000
TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH: 18446744073709551615
@@ -35,7 +34,7 @@ ALTAIR_FORK_VERSION: 0x01001020
ALTAIR_FORK_EPOCH: 36660
# Merge
BELLATRIX_FORK_VERSION: 0x02001020
BELLATRIX_FORK_EPOCH: 18446744073709551615
BELLATRIX_FORK_EPOCH: 112260
# Sharding
SHARDING_FORK_VERSION: 0x03001020
SHARDING_FORK_EPOCH: 18446744073709551615

View File

@@ -23,7 +23,7 @@ ALTAIR_FORK_EPOCH: 500
# Merge
BELLATRIX_FORK_VERSION: 0x80000071
BELLATRIX_FORK_EPOCH: 750
TERMINAL_TOTAL_DIFFICULTY: 43531756765713534
TERMINAL_TOTAL_DIFFICULTY: 50000000000000000
TERMINAL_BLOCK_HASH: 0x0000000000000000000000000000000000000000000000000000000000000000
TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH: 18446744073709551615

View File

@@ -0,0 +1 @@
- enr:-Iq4QMCTfIMXnow27baRUb35Q8iiFHSIDBJh6hQM5Axohhf4b6Kr_cOCu0htQ5WvVqKvFgY28893DHAg8gnBAXsAVqmGAX53x8JggmlkgnY0gmlwhLKAlv6Jc2VjcDI1NmsxoQK6S-Cii_KmfFdUJL2TANL3ksaKUnNXvTCv1tLwXs0QgIN1ZHCCIyk

View File

@@ -0,0 +1,76 @@
# Extends the mainnet preset
PRESET_BASE: 'mainnet'
CONFIG_NAME: 'sepolia'
# Genesis
# ---------------------------------------------------------------
MIN_GENESIS_ACTIVE_VALIDATOR_COUNT: 1300
# Sunday, June 19, 2022 2:00:00 PM +UTC
MIN_GENESIS_TIME: 1655647200
GENESIS_FORK_VERSION: 0x90000069
GENESIS_DELAY: 86400
# Forking
# ---------------------------------------------------------------
# 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: 0x90000070
ALTAIR_FORK_EPOCH: 50
# Merge
BELLATRIX_FORK_VERSION: 0x90000071
BELLATRIX_FORK_EPOCH: 100
TERMINAL_TOTAL_DIFFICULTY: 17000000000000000
TERMINAL_BLOCK_HASH: 0x0000000000000000000000000000000000000000000000000000000000000000
TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH: 18446744073709551615
# Capella
CAPELLA_FORK_VERSION: 0x03001020
CAPELLA_FORK_EPOCH: 18446744073709551615
# Sharding
SHARDING_FORK_VERSION: 0x04001020
SHARDING_FORK_EPOCH: 18446744073709551615
# Time parameters
# ---------------------------------------------------------------
# 12 seconds
SECONDS_PER_SLOT: 12
# 14 (estimate from Eth1 mainnet)
SECONDS_PER_ETH1_BLOCK: 14
# 2**8 (= 256) epochs ~27 hours
MIN_VALIDATOR_WITHDRAWABILITY_DELAY: 256
# 2**8 (= 256) epochs ~27 hours
SHARD_COMMITTEE_PERIOD: 256
# 2**11 (= 2,048) Eth1 blocks ~8 hours
ETH1_FOLLOW_DISTANCE: 2048
# 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**16 (= 65,536)
CHURN_LIMIT_QUOTIENT: 65536
# Fork choice
# ---------------------------------------------------------------
# 40%
PROPOSER_SCORE_BOOST: 40
# Deposit contract
# ---------------------------------------------------------------
DEPOSIT_CHAIN_ID: 11155111
DEPOSIT_NETWORK_ID: 11155111
DEPOSIT_CONTRACT_ADDRESS: 0x7f02C3E3c98b133055B8B348B2Ac625669Ed295D

View File

@@ -256,6 +256,13 @@ mod tests {
config.beacon_state::<E>().expect("beacon state can decode");
}
#[test]
fn prater_and_goerli_are_equal() {
let goerli = Eth2NetworkConfig::from_hardcoded_net(&GOERLI).unwrap();
let prater = Eth2NetworkConfig::from_hardcoded_net(&PRATER).unwrap();
assert_eq!(goerli, prater);
}
#[test]
fn hard_coded_nets_work() {
for net in HARDCODED_NETS {
@@ -275,7 +282,7 @@ mod tests {
"{:?}",
net.name
);
assert_eq!(config.config.config_name, Some(net.name.to_string()));
assert_eq!(config.config.config_name, Some(net.config_dir.to_string()));
}
}

View File

@@ -45,7 +45,7 @@ impl<T> Fallback<T> {
{
match error {
FallbackError::AllErrored(v) => format!(
"All fallback errored: {}",
"All fallbacks errored: {}",
join(
zip(self.servers.iter().map(f), v.iter())
.map(|(server, error)| format!("{} => {:?}", server, error)),

View File

@@ -1,12 +0,0 @@
[package]
name = "hashset_delay"
version = "0.2.0"
authors = ["Sigma Prime <contact@sigmaprime.io>"]
edition = "2021"
[dependencies]
futures = "0.3.7"
tokio-util = { version = "0.6.2", features = ["time"] }
[dev-dependencies]
tokio = { version = "1.14.0", features = ["time", "rt-multi-thread", "macros"] }

View File

@@ -1,197 +0,0 @@
//NOTE: This is just a specific case of a HashMapDelay.
// The code has been copied to make unique `insert` and `insert_at` functions.
/// The default delay for entries, in seconds. This is only used when `insert()` is used to add
/// entries.
const DEFAULT_DELAY: u64 = 30;
use futures::prelude::*;
use std::{
collections::HashMap,
pin::Pin,
task::{Context, Poll},
time::{Duration, Instant},
};
use tokio_util::time::delay_queue::{self, DelayQueue};
pub struct HashSetDelay<K>
where
K: std::cmp::Eq + std::hash::Hash + std::clone::Clone + Unpin,
{
/// The given entries.
entries: HashMap<K, MapEntry>,
/// A queue holding the timeouts of each entry.
expirations: DelayQueue<K>,
/// The default expiration timeout of an entry.
default_entry_timeout: Duration,
}
/// A wrapping around entries that adds the link to the entry's expiration, via a `delay_queue` key.
struct MapEntry {
/// The expiration key for the entry.
key: delay_queue::Key,
/// The actual entry.
value: Instant,
}
impl<K> Default for HashSetDelay<K>
where
K: std::cmp::Eq + std::hash::Hash + std::clone::Clone + Unpin,
{
fn default() -> Self {
HashSetDelay::new(Duration::from_secs(DEFAULT_DELAY))
}
}
impl<K> HashSetDelay<K>
where
K: std::cmp::Eq + std::hash::Hash + std::clone::Clone + Unpin,
{
/// Creates a new instance of `HashSetDelay`.
pub fn new(default_entry_timeout: Duration) -> Self {
HashSetDelay {
entries: HashMap::new(),
expirations: DelayQueue::new(),
default_entry_timeout,
}
}
/// Insert an entry into the mapping. Entries will expire after the `default_entry_timeout`.
pub fn insert(&mut self, key: K) {
self.insert_at(key, self.default_entry_timeout);
}
/// Inserts an entry that will expire at a given instant. If the entry already exists, the
/// timeout is updated.
pub fn insert_at(&mut self, key: K, entry_duration: Duration) {
if self.contains(&key) {
// update the timeout
self.update_timeout(&key, entry_duration);
} else {
let delay_key = self.expirations.insert(key.clone(), entry_duration);
let entry = MapEntry {
key: delay_key,
value: Instant::now() + entry_duration,
};
self.entries.insert(key, entry);
}
}
/// Gets a reference to an entry if it exists.
///
/// Returns None if the entry does not exist.
pub fn get(&self, key: &K) -> Option<&Instant> {
self.entries.get(key).map(|entry| &entry.value)
}
/// Returns true if the key exists, false otherwise.
pub fn contains(&self, key: &K) -> bool {
self.entries.contains_key(key)
}
/// Returns the length of the mapping.
pub fn len(&self) -> usize {
self.entries.len()
}
/// Checks if the mapping is empty.
pub fn is_empty(&self) -> bool {
self.entries.is_empty()
}
/// Updates the timeout for a given key. Returns true if the key existed, false otherwise.
///
/// Panics if the duration is too far in the future.
pub fn update_timeout(&mut self, key: &K, timeout: Duration) -> bool {
if let Some(entry) = self.entries.get(key) {
self.expirations.reset(&entry.key, timeout);
true
} else {
false
}
}
/// Removes a key from the map returning the value associated with the key that was in the map.
///
/// Return false if the key was not in the map.
pub fn remove(&mut self, key: &K) -> bool {
if let Some(entry) = self.entries.remove(key) {
self.expirations.remove(&entry.key);
return true;
}
false
}
/// Retains only the elements specified by the predicate.
///
/// In other words, remove all pairs `(k, v)` such that `f(&k,&mut v)` returns false.
pub fn retain<F: FnMut(&K) -> bool>(&mut self, mut f: F) {
let expiration = &mut self.expirations;
self.entries.retain(|key, entry| {
let result = f(key);
if !result {
expiration.remove(&entry.key);
}
result
})
}
/// Removes all entries from the map.
pub fn clear(&mut self) {
self.entries.clear();
self.expirations.clear();
}
/// Returns a vector of referencing all keys in the map.
pub fn keys(&self) -> impl Iterator<Item = &K> {
self.entries.keys()
}
}
impl<K> Stream for HashSetDelay<K>
where
K: std::cmp::Eq + std::hash::Hash + std::clone::Clone + Unpin,
{
type Item = Result<K, String>;
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Option<Self::Item>> {
match self.expirations.poll_expired(cx) {
Poll::Ready(Some(Ok(key))) => match self.entries.remove(key.get_ref()) {
Some(_) => Poll::Ready(Some(Ok(key.into_inner()))),
None => Poll::Ready(Some(Err("Value no longer exists in expirations".into()))),
},
Poll::Ready(Some(Err(e))) => {
Poll::Ready(Some(Err(format!("delay queue error: {:?}", e))))
}
Poll::Ready(None) => Poll::Ready(None),
Poll::Pending => Poll::Pending,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn should_not_panic() {
let key = 2u8;
let mut map = HashSetDelay::default();
map.insert(key);
map.update_timeout(&key, Duration::from_secs(100));
let fut = |cx: &mut Context| {
let _ = map.poll_next_unpin(cx);
let _ = map.poll_next_unpin(cx);
Poll::Ready(())
};
future::poll_fn(fut).await;
map.insert(key);
map.update_timeout(&key, Duration::from_secs(100));
}
}

View File

@@ -1,12 +0,0 @@
//! This crate provides a single type (its counter-part HashMapDelay has been removed as it
//! currently is not in use in lighthouse):
//! - `HashSetDelay`
//!
//! # HashSetDelay
//!
//! This is similar to a `HashMapDelay` except the mapping maps to the expiry time. This
//! allows users to add objects and check their expiry deadlines before the `Stream`
//! consumes them.
mod hashset_delay;
pub use crate::hashset_delay::HashSetDelay;

View File

@@ -54,14 +54,15 @@
//! }
//! ```
use prometheus::{HistogramOpts, Opts};
use prometheus::{Error, HistogramOpts, Opts};
use std::time::Duration;
use prometheus::core::{Atomic, GenericGauge, GenericGaugeVec};
pub use prometheus::{
exponential_buckets, linear_buckets,
proto::{Metric, MetricFamily, MetricType},
Encoder, Gauge, GaugeVec, Histogram, HistogramTimer, HistogramVec, IntCounter, IntCounterVec,
IntGauge, IntGaugeVec, Result, TextEncoder,
IntGauge, IntGaugeVec, Result, TextEncoder, DEFAULT_BUCKETS,
};
/// Collect all the metrics for reporting.
@@ -99,7 +100,17 @@ pub fn try_create_float_gauge(name: &str, help: &str) -> Result<Gauge> {
/// Attempts to create a `Histogram`, returning `Err` if the registry does not accept the counter
/// (potentially due to naming conflict).
pub fn try_create_histogram(name: &str, help: &str) -> Result<Histogram> {
let opts = HistogramOpts::new(name, help);
try_create_histogram_with_buckets(name, help, Ok(DEFAULT_BUCKETS.to_vec()))
}
/// Attempts to create a `Histogram` with specified buckets, returning `Err` if the registry does not accept the counter
/// (potentially due to naming conflict) or no valid buckets are provided.
pub fn try_create_histogram_with_buckets(
name: &str,
help: &str,
buckets: Result<Vec<f64>>,
) -> Result<Histogram> {
let opts = HistogramOpts::new(name, help).buckets(buckets?);
let histogram = Histogram::with_opts(opts)?;
prometheus::register(Box::new(histogram.clone()))?;
Ok(histogram)
@@ -112,7 +123,18 @@ pub fn try_create_histogram_vec(
help: &str,
label_names: &[&str],
) -> Result<HistogramVec> {
let opts = HistogramOpts::new(name, help);
try_create_histogram_vec_with_buckets(name, help, Ok(DEFAULT_BUCKETS.to_vec()), label_names)
}
/// Attempts to create a `HistogramVec` with specified buckets, returning `Err` if the registry does not accept the counter
/// (potentially due to naming conflict) or no valid buckets are provided.
pub fn try_create_histogram_vec_with_buckets(
name: &str,
help: &str,
buckets: Result<Vec<f64>>,
label_names: &[&str],
) -> Result<HistogramVec> {
let opts = HistogramOpts::new(name, help).buckets(buckets?);
let histogram_vec = HistogramVec::new(opts, label_names)?;
prometheus::register(Box::new(histogram_vec.clone()))?;
Ok(histogram_vec)
@@ -357,3 +379,28 @@ fn duration_to_f64(duration: Duration) -> f64 {
let nanos = f64::from(duration.subsec_nanos()) / 1e9;
duration.as_secs() as f64 + nanos
}
/// Create buckets using divisors of 10 multiplied by powers of 10, e.g.,
/// […, 0.1, 0.2, 0.5, 1, 2, 5, 10, 20, 50, …]
///
/// The buckets go from `10^min_power` to `5 × 10^max_power`, inclusively.
/// The total number of buckets is `3 * (max_power - min_power + 1)`.
///
/// assert_eq!(vec![0.1, 0.2, 0.5, 1.0, 2.0, 5.0, 10.0, 20.0, 50.0], decimal_buckets(-1, 1));
/// assert_eq!(vec![1.0, 2.0, 5.0, 10.0, 20.0, 50.0, 100.0, 200.0, 500.0], decimal_buckets(0, 2));
pub fn decimal_buckets(min_power: i32, max_power: i32) -> Result<Vec<f64>> {
if max_power < min_power {
return Err(Error::Msg(format!(
"decimal_buckets min_power needs to be <= max_power, given {} and {}",
min_power, max_power
)));
}
let mut buckets = Vec::with_capacity(3 * (max_power - min_power + 1) as usize);
for n in min_power..=max_power {
for m in &[1f64, 2f64, 5f64] {
buckets.push(m * 10f64.powi(n))
}
}
Ok(buckets)
}

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/v2.2.1-",
fallback = "Lighthouse/v2.2.1"
prefix = "Lighthouse/v3.1.0-",
fallback = "Lighthouse/v3.1.0"
);
/// Returns `VERSION`, but with platform information appended to the end.
@@ -37,8 +37,9 @@ mod test {
#[test]
fn version_formatting() {
let re = Regex::new(r"^Lighthouse/v[0-9]+\.[0-9]+\.[0-9]+(-rc.[0-9])?-[[:xdigit:]]{7}\+?$")
.unwrap();
let re =
Regex::new(r"^Lighthouse/v[0-9]+\.[0-9]+\.[0-9]+(-rc.[0-9])?(-[[:xdigit:]]{7})?\+?$")
.unwrap();
assert!(
re.is_match(VERSION),
"version doesn't match regex: {}",

View File

@@ -16,7 +16,7 @@ use types::*;
pub use types::ProcessType;
/// Duration after which we collect and send metrics to remote endpoint.
pub const UPDATE_DURATION: u64 = 60;
pub const DEFAULT_UPDATE_DURATION: u64 = 60;
/// Timeout for HTTP requests.
pub const TIMEOUT_DURATION: u64 = 5;
@@ -55,6 +55,8 @@ pub struct Config {
/// Path for the cold database required for fetching beacon db size metrics.
/// Note: not relevant for validator and system metrics.
pub freezer_db_path: Option<PathBuf>,
/// User-defined update period in seconds.
pub update_period_secs: Option<u64>,
}
#[derive(Clone)]
@@ -64,6 +66,7 @@ pub struct MonitoringHttpClient {
db_path: Option<PathBuf>,
/// Path to the freezer database.
freezer_db_path: Option<PathBuf>,
update_period: Duration,
monitoring_endpoint: SensitiveUrl,
log: slog::Logger,
}
@@ -74,6 +77,9 @@ impl MonitoringHttpClient {
client: reqwest::Client::new(),
db_path: config.db_path.clone(),
freezer_db_path: config.freezer_db_path.clone(),
update_period: Duration::from_secs(
config.update_period_secs.unwrap_or(DEFAULT_UPDATE_DURATION),
),
monitoring_endpoint: SensitiveUrl::parse(&config.monitoring_endpoint)
.map_err(|e| format!("Invalid monitoring endpoint: {:?}", e))?,
log,
@@ -100,10 +106,15 @@ impl MonitoringHttpClient {
let mut interval = interval_at(
// Have some initial delay for the metrics to get initialized
Instant::now() + Duration::from_secs(25),
Duration::from_secs(UPDATE_DURATION),
self.update_period,
);
info!(self.log, "Starting monitoring api"; "endpoint" => %self.monitoring_endpoint);
info!(
self.log,
"Starting monitoring API";
"endpoint" => %self.monitoring_endpoint,
"update_period" => format!("{}s", self.update_period.as_secs()),
);
let update_future = async move {
loop {

View File

@@ -1,5 +1,6 @@
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
use std::fmt;
use std::str::FromStr;
use url::Url;
#[derive(Debug)]
@@ -9,6 +10,12 @@ pub enum SensitiveError {
RedactError(String),
}
impl fmt::Display for SensitiveError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", self)
}
}
// Wrapper around Url which provides a custom `Display` implementation to protect user secrets.
#[derive(Clone, PartialEq)]
pub struct SensitiveUrl {
@@ -39,7 +46,7 @@ impl Serialize for SensitiveUrl {
where
S: Serializer,
{
serializer.serialize_str(&self.full.to_string())
serializer.serialize_str(self.full.as_ref())
}
}
@@ -54,6 +61,14 @@ impl<'de> Deserialize<'de> for SensitiveUrl {
}
}
impl FromStr for SensitiveUrl {
type Err = SensitiveError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Self::parse(s)
}
}
impl SensitiveUrl {
pub fn parse(url: &str) -> Result<Self, SensitiveError> {
let surl = Url::parse(url).map_err(SensitiveError::ParseError)?;

View File

@@ -5,7 +5,7 @@ authors = ["Sigma Prime <contact@sigmaprime.io>"]
edition = "2021"
[dependencies]
tokio = { version = "1.14.0", features = ["rt-multi-thread"] }
tokio = { version = "1.14.0", features = ["rt-multi-thread", "macros"] }
slog = "2.5.2"
futures = "0.3.7"
exit-future = "0.2.0"

View File

@@ -7,6 +7,8 @@ use slog::{crit, debug, o, trace};
use std::sync::Weak;
use tokio::runtime::{Handle, Runtime};
pub use tokio::task::JoinHandle;
/// Provides a reason when Lighthouse is shut down.
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum ShutdownReason {
@@ -312,6 +314,61 @@ impl TaskExecutor {
Some(future)
}
/// Block the current (non-async) thread on the completion of some future.
///
/// ## Warning
///
/// This method is "dangerous" since calling it from an async thread will result in a panic! Any
/// use of this outside of testing should be very deeply considered as Lighthouse has been
/// burned by this function in the past.
///
/// Determining what is an "async thread" is rather challenging; just because a function isn't
/// marked as `async` doesn't mean it's not being called from an `async` function or there isn't
/// a `tokio` context present in the thread-local storage due to some `rayon` funkiness. Talk to
/// @paulhauner if you plan to use this function in production. He has put metrics in here to
/// track any use of it, so don't think you can pull a sneaky one on him.
pub fn block_on_dangerous<F: Future>(
&self,
future: F,
name: &'static str,
) -> Option<F::Output> {
let timer = metrics::start_timer_vec(&metrics::BLOCK_ON_TASKS_HISTOGRAM, &[name]);
metrics::inc_gauge_vec(&metrics::BLOCK_ON_TASKS_COUNT, &[name]);
let log = self.log.clone();
let handle = self.handle()?;
let exit = self.exit.clone();
debug!(
log,
"Starting block_on task";
"name" => name
);
handle.block_on(async {
let output = tokio::select! {
output = future => {
debug!(
log,
"Completed block_on task";
"name" => name
);
Some(output)
},
_ = exit => {
debug!(
log,
"Cancelled block_on task";
"name" => name,
);
None
}
};
metrics::dec_gauge_vec(&metrics::BLOCK_ON_TASKS_COUNT, &[name]);
drop(timer);
output
})
}
/// Returns a `Handle` to the current runtime.
pub fn handle(&self) -> Option<Handle> {
self.handle_provider.handle()

View File

@@ -18,6 +18,16 @@ lazy_static! {
"Time taken by blocking tasks",
&["blocking_task_hist"]
);
pub static ref BLOCK_ON_TASKS_COUNT: Result<IntGaugeVec> = try_create_int_gauge_vec(
"block_on_tasks_count",
"Total number of block_on_dangerous tasks spawned",
&["name"]
);
pub static ref BLOCK_ON_TASKS_HISTOGRAM: Result<HistogramVec> = try_create_histogram_vec(
"block_on_tasks_histogram",
"Time taken by block_on_dangerous tasks",
&["name"]
);
pub static ref TASKS_HISTOGRAM: Result<HistogramVec> = try_create_histogram_vec(
"async_tasks_time_histogram",
"Time taken by async tasks",

View File

@@ -205,8 +205,13 @@ pub async fn handle_rejection(err: warp::Rejection) -> Result<impl warp::Reply,
code = StatusCode::FORBIDDEN;
message = format!("FORBIDDEN: Invalid auth token: {}", e.0);
} else if let Some(e) = err.find::<warp::reject::MissingHeader>() {
code = StatusCode::BAD_REQUEST;
message = format!("BAD_REQUEST: missing {} header", e.name());
if e.name().eq("Authorization") {
code = StatusCode::UNAUTHORIZED;
message = "UNAUTHORIZED: missing Authorization header".to_string();
} else {
code = StatusCode::BAD_REQUEST;
message = format!("BAD_REQUEST: missing {} header", e.name());
}
} else if let Some(e) = err.find::<warp::reject::InvalidHeader>() {
code = StatusCode::BAD_REQUEST;
message = format!("BAD_REQUEST: invalid {} header", e.name());