Serve Bellatrix preset in BN API (#3425)
## Issue Addressed Resolves #3388 Resolves #2638 ## Proposed Changes - Return the `BellatrixPreset` on `/eth/v1/config/spec` by default. - Allow users to opt out of this by providing `--http-spec-fork=altair` (unless there's a Bellatrix fork epoch set). - Add the Altair constants from #2638 and make serving the constants non-optional (the `http-disable-legacy-spec` flag is deprecated). - Modify the VC to only read the `Config` and not to log extra fields. This prevents it from having to muck around parsing the `ConfigAndPreset` fields it doesn't need. ## Additional Info This change is backwards-compatible for the VC and the BN, but is marked as a breaking change for the removal of `--http-disable-legacy-spec`. I tried making `Config` a `superstruct` too, but getting the automatic decoding to work was a huge pain and was going to require a lot of hacks, so I gave up in favour of keeping the default-based approach we have now.
This commit is contained in:
parent
c25934956b
commit
4e05f19fb5
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -7073,6 +7073,7 @@ dependencies = [
|
|||||||
"itertools",
|
"itertools",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"log",
|
"log",
|
||||||
|
"maplit",
|
||||||
"parking_lot 0.12.1",
|
"parking_lot 0.12.1",
|
||||||
"rand 0.8.5",
|
"rand 0.8.5",
|
||||||
"rand_xorshift",
|
"rand_xorshift",
|
||||||
|
@ -132,8 +132,7 @@ pub fn test_spec<E: EthSpec>() -> ChainSpec {
|
|||||||
FORK_NAME_ENV_VAR, e
|
FORK_NAME_ENV_VAR, e
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
let fork = ForkName::from_str(fork_name.as_str())
|
let fork = ForkName::from_str(fork_name.as_str()).unwrap();
|
||||||
.unwrap_or_else(|()| panic!("unknown FORK_NAME: {}", fork_name));
|
|
||||||
fork.make_genesis_spec(E::default_spec())
|
fork.make_genesis_spec(E::default_spec())
|
||||||
} else {
|
} else {
|
||||||
E::default_spec()
|
E::default_spec()
|
||||||
|
@ -104,9 +104,9 @@ pub struct Config {
|
|||||||
pub listen_addr: IpAddr,
|
pub listen_addr: IpAddr,
|
||||||
pub listen_port: u16,
|
pub listen_port: u16,
|
||||||
pub allow_origin: Option<String>,
|
pub allow_origin: Option<String>,
|
||||||
pub serve_legacy_spec: bool,
|
|
||||||
pub tls_config: Option<TlsConfig>,
|
pub tls_config: Option<TlsConfig>,
|
||||||
pub allow_sync_stalled: bool,
|
pub allow_sync_stalled: bool,
|
||||||
|
pub spec_fork_name: Option<ForkName>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Config {
|
impl Default for Config {
|
||||||
@ -116,9 +116,9 @@ impl Default for Config {
|
|||||||
listen_addr: IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)),
|
listen_addr: IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)),
|
||||||
listen_port: 5052,
|
listen_port: 5052,
|
||||||
allow_origin: None,
|
allow_origin: None,
|
||||||
serve_legacy_spec: true,
|
|
||||||
tls_config: None,
|
tls_config: None,
|
||||||
allow_sync_stalled: false,
|
allow_sync_stalled: false,
|
||||||
|
spec_fork_name: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1534,18 +1534,15 @@ pub fn serve<T: BeaconChainTypes>(
|
|||||||
});
|
});
|
||||||
|
|
||||||
// GET config/spec
|
// GET config/spec
|
||||||
let serve_legacy_spec = ctx.config.serve_legacy_spec;
|
let spec_fork_name = ctx.config.spec_fork_name;
|
||||||
let get_config_spec = config_path
|
let get_config_spec = config_path
|
||||||
.and(warp::path("spec"))
|
.and(warp::path("spec"))
|
||||||
.and(warp::path::end())
|
.and(warp::path::end())
|
||||||
.and(chain_filter.clone())
|
.and(chain_filter.clone())
|
||||||
.and_then(move |chain: Arc<BeaconChain<T>>| {
|
.and_then(move |chain: Arc<BeaconChain<T>>| {
|
||||||
blocking_json_task(move || {
|
blocking_json_task(move || {
|
||||||
let mut config_and_preset =
|
let config_and_preset =
|
||||||
ConfigAndPreset::from_chain_spec::<T::EthSpec>(&chain.spec);
|
ConfigAndPreset::from_chain_spec::<T::EthSpec>(&chain.spec, spec_fork_name);
|
||||||
if serve_legacy_spec {
|
|
||||||
config_and_preset.make_backwards_compat(&chain.spec);
|
|
||||||
}
|
|
||||||
Ok(api_types::GenericResponse::from(config_and_preset))
|
Ok(api_types::GenericResponse::from(config_and_preset))
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
@ -141,9 +141,9 @@ pub async fn create_api_server_on_port<T: BeaconChainTypes>(
|
|||||||
listen_addr: IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)),
|
listen_addr: IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)),
|
||||||
listen_port: port,
|
listen_port: port,
|
||||||
allow_origin: None,
|
allow_origin: None,
|
||||||
serve_legacy_spec: true,
|
|
||||||
tls_config: None,
|
tls_config: None,
|
||||||
allow_sync_stalled: false,
|
allow_sync_stalled: false,
|
||||||
|
spec_fork_name: None,
|
||||||
},
|
},
|
||||||
chain: Some(chain.clone()),
|
chain: Some(chain.clone()),
|
||||||
network_tx: Some(network_tx),
|
network_tx: Some(network_tx),
|
||||||
|
@ -1253,10 +1253,13 @@ impl ApiTester {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn test_get_config_spec(self) -> Self {
|
pub async fn test_get_config_spec(self) -> Self {
|
||||||
let result = self.client.get_config_spec().await.unwrap().data;
|
let result = self
|
||||||
|
.client
|
||||||
let mut expected = ConfigAndPreset::from_chain_spec::<E>(&self.chain.spec);
|
.get_config_spec::<ConfigAndPresetBellatrix>()
|
||||||
expected.make_backwards_compat(&self.chain.spec);
|
.await
|
||||||
|
.map(|res| ConfigAndPreset::Bellatrix(res.data))
|
||||||
|
.unwrap();
|
||||||
|
let expected = ConfigAndPreset::from_chain_spec::<E>(&self.chain.spec, None);
|
||||||
|
|
||||||
assert_eq!(result, expected);
|
assert_eq!(result, expected);
|
||||||
|
|
||||||
|
@ -229,8 +229,14 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> {
|
|||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("http-disable-legacy-spec")
|
Arg::with_name("http-disable-legacy-spec")
|
||||||
.long("http-disable-legacy-spec")
|
.long("http-disable-legacy-spec")
|
||||||
.help("Disable serving of legacy data on the /config/spec endpoint. May be \
|
.hidden(true)
|
||||||
disabled by default in a future release.")
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("http-spec-fork")
|
||||||
|
.long("http-spec-fork")
|
||||||
|
.help("Serve the spec for a specific hard fork on /eth/v1/config/spec. It should \
|
||||||
|
not be necessary to set this flag.")
|
||||||
|
.takes_value(true)
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("http-enable-tls")
|
Arg::with_name("http-enable-tls")
|
||||||
|
@ -116,7 +116,14 @@ pub fn get_config<E: EthSpec>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if cli_args.is_present("http-disable-legacy-spec") {
|
if cli_args.is_present("http-disable-legacy-spec") {
|
||||||
client_config.http_api.serve_legacy_spec = false;
|
warn!(
|
||||||
|
log,
|
||||||
|
"The flag --http-disable-legacy-spec is deprecated and will be removed"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(fork_name) = clap_utils::parse_optional(cli_args, "http-spec-fork")? {
|
||||||
|
client_config.http_api.spec_fork_name = Some(fork_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if cli_args.is_present("http-enable-tls") {
|
if cli_args.is_present("http-enable-tls") {
|
||||||
|
@ -977,7 +977,9 @@ impl BeaconNodeHttpClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// `GET config/spec`
|
/// `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)?;
|
let mut path = self.eth_path(V1)?;
|
||||||
|
|
||||||
path.path_segments_mut()
|
path.path_segments_mut()
|
||||||
|
@ -354,7 +354,9 @@ impl ValidatorClientHttpClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// `GET lighthouse/spec`
|
/// `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();
|
let mut path = self.server.full.clone();
|
||||||
|
|
||||||
path.path_segments_mut()
|
path.path_segments_mut()
|
||||||
|
@ -21,17 +21,17 @@ impl ResponseOptional for Result<Response, Error> {
|
|||||||
/// Trait for extracting the fork name from the headers of a response.
|
/// Trait for extracting the fork name from the headers of a response.
|
||||||
pub trait ResponseForkName {
|
pub trait ResponseForkName {
|
||||||
#[allow(clippy::result_unit_err)]
|
#[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 {
|
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()
|
self.headers()
|
||||||
.get(CONSENSUS_VERSION_HEADER)
|
.get(CONSENSUS_VERSION_HEADER)
|
||||||
.map(|fork_name| {
|
.map(|fork_name| {
|
||||||
fork_name
|
fork_name
|
||||||
.to_str()
|
.to_str()
|
||||||
.map_err(|_| ())
|
.map_err(|e| e.to_string())
|
||||||
.and_then(ForkName::from_str)
|
.and_then(ForkName::from_str)
|
||||||
})
|
})
|
||||||
.transpose()
|
.transpose()
|
||||||
|
@ -47,6 +47,7 @@ superstruct = "0.5.0"
|
|||||||
serde_json = "1.0.74"
|
serde_json = "1.0.74"
|
||||||
smallvec = "1.8.0"
|
smallvec = "1.8.0"
|
||||||
serde_with = "1.13.0"
|
serde_with = "1.13.0"
|
||||||
|
maplit = "1.0.2"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
criterion = "0.3.3"
|
criterion = "0.3.3"
|
||||||
|
@ -803,6 +803,10 @@ impl Default for ChainSpec {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Exact implementation of the *config* object from the Ethereum spec (YAML/JSON).
|
/// Exact implementation of the *config* object from the Ethereum spec (YAML/JSON).
|
||||||
|
///
|
||||||
|
/// Fields relevant to hard forks after Altair should be optional so that we can continue
|
||||||
|
/// to parse Altair configs. This default approach turns out to be much simpler than trying to
|
||||||
|
/// make `Config` a superstruct because of the hassle of deserializing an untagged enum.
|
||||||
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
|
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
|
||||||
#[serde(rename_all = "UPPERCASE")]
|
#[serde(rename_all = "UPPERCASE")]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
@ -813,17 +817,13 @@ pub struct Config {
|
|||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub preset_base: String,
|
pub preset_base: String,
|
||||||
|
|
||||||
// TODO(merge): remove this default
|
|
||||||
#[serde(default = "default_terminal_total_difficulty")]
|
#[serde(default = "default_terminal_total_difficulty")]
|
||||||
#[serde(with = "eth2_serde_utils::quoted_u256")]
|
#[serde(with = "eth2_serde_utils::quoted_u256")]
|
||||||
pub terminal_total_difficulty: Uint256,
|
pub terminal_total_difficulty: Uint256,
|
||||||
// TODO(merge): remove this default
|
|
||||||
#[serde(default = "default_terminal_block_hash")]
|
#[serde(default = "default_terminal_block_hash")]
|
||||||
pub terminal_block_hash: ExecutionBlockHash,
|
pub terminal_block_hash: ExecutionBlockHash,
|
||||||
// TODO(merge): remove this default
|
|
||||||
#[serde(default = "default_terminal_block_hash_activation_epoch")]
|
#[serde(default = "default_terminal_block_hash_activation_epoch")]
|
||||||
pub terminal_block_hash_activation_epoch: Epoch,
|
pub terminal_block_hash_activation_epoch: Epoch,
|
||||||
// TODO(merge): remove this default
|
|
||||||
#[serde(default = "default_safe_slots_to_import_optimistically")]
|
#[serde(default = "default_safe_slots_to_import_optimistically")]
|
||||||
#[serde(with = "eth2_serde_utils::quoted_u64")]
|
#[serde(with = "eth2_serde_utils::quoted_u64")]
|
||||||
pub safe_slots_to_import_optimistically: u64,
|
pub safe_slots_to_import_optimistically: u64,
|
||||||
@ -843,12 +843,10 @@ pub struct Config {
|
|||||||
#[serde(deserialize_with = "deserialize_fork_epoch")]
|
#[serde(deserialize_with = "deserialize_fork_epoch")]
|
||||||
pub altair_fork_epoch: Option<MaybeQuoted<Epoch>>,
|
pub altair_fork_epoch: Option<MaybeQuoted<Epoch>>,
|
||||||
|
|
||||||
// TODO(merge): remove this default
|
|
||||||
#[serde(default = "default_bellatrix_fork_version")]
|
#[serde(default = "default_bellatrix_fork_version")]
|
||||||
#[serde(with = "eth2_serde_utils::bytes_4_hex")]
|
#[serde(with = "eth2_serde_utils::bytes_4_hex")]
|
||||||
bellatrix_fork_version: [u8; 4],
|
bellatrix_fork_version: [u8; 4],
|
||||||
// TODO(merge): remove this default
|
#[serde(default)]
|
||||||
#[serde(default = "default_bellatrix_fork_epoch")]
|
|
||||||
#[serde(serialize_with = "serialize_fork_epoch")]
|
#[serde(serialize_with = "serialize_fork_epoch")]
|
||||||
#[serde(deserialize_with = "deserialize_fork_epoch")]
|
#[serde(deserialize_with = "deserialize_fork_epoch")]
|
||||||
pub bellatrix_fork_epoch: Option<MaybeQuoted<Epoch>>,
|
pub bellatrix_fork_epoch: Option<MaybeQuoted<Epoch>>,
|
||||||
@ -890,10 +888,6 @@ fn default_bellatrix_fork_version() -> [u8; 4] {
|
|||||||
[0xff, 0xff, 0xff, 0xff]
|
[0xff, 0xff, 0xff, 0xff]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn default_bellatrix_fork_epoch() -> Option<MaybeQuoted<Epoch>> {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Placeholder value: 2^256-2^10 (115792089237316195423570985008687907853269984665640564039457584007913129638912).
|
/// Placeholder value: 2^256-2^10 (115792089237316195423570985008687907853269984665640564039457584007913129638912).
|
||||||
///
|
///
|
||||||
/// Taken from https://github.com/ethereum/consensus-specs/blob/d5e4828aecafaf1c57ef67a5f23c4ae7b08c5137/configs/mainnet.yaml#L15-L16
|
/// Taken from https://github.com/ethereum/consensus-specs/blob/d5e4828aecafaf1c57ef67a5f23c4ae7b08c5137/configs/mainnet.yaml#L15-L16
|
||||||
@ -1335,10 +1329,7 @@ mod yaml_tests {
|
|||||||
default_safe_slots_to_import_optimistically()
|
default_safe_slots_to_import_optimistically()
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(chain_spec.bellatrix_fork_epoch, None);
|
||||||
chain_spec.bellatrix_fork_epoch,
|
|
||||||
default_bellatrix_fork_epoch()
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
chain_spec.bellatrix_fork_version,
|
chain_spec.bellatrix_fork_version,
|
||||||
|
@ -1,12 +1,21 @@
|
|||||||
use crate::{AltairPreset, BasePreset, BellatrixPreset, ChainSpec, Config, EthSpec};
|
use crate::{
|
||||||
|
consts::altair, AltairPreset, BasePreset, BellatrixPreset, ChainSpec, Config, EthSpec, ForkName,
|
||||||
|
};
|
||||||
|
use maplit::hashmap;
|
||||||
use serde_derive::{Deserialize, Serialize};
|
use serde_derive::{Deserialize, Serialize};
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use superstruct::superstruct;
|
||||||
|
|
||||||
/// Fusion of a runtime-config with the compile-time preset values.
|
/// Fusion of a runtime-config with the compile-time preset values.
|
||||||
///
|
///
|
||||||
/// Mostly useful for the API.
|
/// Mostly useful for the API.
|
||||||
|
#[superstruct(
|
||||||
|
variants(Altair, Bellatrix),
|
||||||
|
variant_attributes(derive(Serialize, Deserialize, Debug, PartialEq, Clone))
|
||||||
|
)]
|
||||||
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
|
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
|
||||||
|
#[serde(untagged)]
|
||||||
pub struct ConfigAndPreset {
|
pub struct ConfigAndPreset {
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
pub config: Config,
|
pub config: Config,
|
||||||
@ -15,80 +24,75 @@ pub struct ConfigAndPreset {
|
|||||||
pub base_preset: BasePreset,
|
pub base_preset: BasePreset,
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
pub altair_preset: AltairPreset,
|
pub altair_preset: AltairPreset,
|
||||||
// TODO(merge): re-enable
|
#[superstruct(only(Bellatrix))]
|
||||||
// #[serde(flatten)]
|
#[serde(flatten)]
|
||||||
// pub bellatrix_preset: BellatrixPreset,
|
pub bellatrix_preset: BellatrixPreset,
|
||||||
/// The `extra_fields` map allows us to gracefully decode fields intended for future hard forks.
|
/// The `extra_fields` map allows us to gracefully decode fields intended for future hard forks.
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
pub extra_fields: HashMap<String, Value>,
|
pub extra_fields: HashMap<String, Value>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ConfigAndPreset {
|
impl ConfigAndPreset {
|
||||||
pub fn from_chain_spec<T: EthSpec>(spec: &ChainSpec) -> Self {
|
pub fn from_chain_spec<T: EthSpec>(spec: &ChainSpec, fork_name: Option<ForkName>) -> Self {
|
||||||
let config = Config::from_chain_spec::<T>(spec);
|
let config = Config::from_chain_spec::<T>(spec);
|
||||||
let base_preset = BasePreset::from_chain_spec::<T>(spec);
|
let base_preset = BasePreset::from_chain_spec::<T>(spec);
|
||||||
let altair_preset = AltairPreset::from_chain_spec::<T>(spec);
|
let altair_preset = AltairPreset::from_chain_spec::<T>(spec);
|
||||||
// TODO(merge): re-enable
|
let extra_fields = get_extra_fields(spec);
|
||||||
let _bellatrix_preset = BellatrixPreset::from_chain_spec::<T>(spec);
|
|
||||||
let extra_fields = HashMap::new();
|
|
||||||
|
|
||||||
Self {
|
if spec.bellatrix_fork_epoch.is_some()
|
||||||
|
|| fork_name == None
|
||||||
|
|| fork_name == Some(ForkName::Merge)
|
||||||
|
{
|
||||||
|
let bellatrix_preset = BellatrixPreset::from_chain_spec::<T>(spec);
|
||||||
|
|
||||||
|
ConfigAndPreset::Bellatrix(ConfigAndPresetBellatrix {
|
||||||
|
config,
|
||||||
|
base_preset,
|
||||||
|
altair_preset,
|
||||||
|
bellatrix_preset,
|
||||||
|
extra_fields,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
ConfigAndPreset::Altair(ConfigAndPresetAltair {
|
||||||
config,
|
config,
|
||||||
base_preset,
|
base_preset,
|
||||||
altair_preset,
|
altair_preset,
|
||||||
extra_fields,
|
extra_fields,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Add fields that were previously part of the config but are now constants.
|
/// Get a hashmap of constants to add to the `PresetAndConfig`
|
||||||
pub fn make_backwards_compat(&mut self, spec: &ChainSpec) {
|
pub fn get_extra_fields(spec: &ChainSpec) -> HashMap<String, Value> {
|
||||||
let hex_string = |value: &[u8]| format!("0x{}", hex::encode(&value));
|
let hex_string = |value: &[u8]| format!("0x{}", hex::encode(&value)).into();
|
||||||
let u32_hex = |v: u32| hex_string(&v.to_le_bytes());
|
let u32_hex = |v: u32| hex_string(&v.to_le_bytes());
|
||||||
let u8_hex = |v: u8| hex_string(&v.to_le_bytes());
|
let u8_hex = |v: u8| hex_string(&v.to_le_bytes());
|
||||||
let fields = vec![
|
hashmap! {
|
||||||
(
|
"bls_withdrawal_prefix".to_uppercase() => u8_hex(spec.bls_withdrawal_prefix_byte),
|
||||||
"bls_withdrawal_prefix",
|
"domain_beacon_proposer".to_uppercase() => u32_hex(spec.domain_beacon_proposer),
|
||||||
u8_hex(spec.bls_withdrawal_prefix_byte),
|
"domain_beacon_attester".to_uppercase() => u32_hex(spec.domain_beacon_attester),
|
||||||
),
|
"domain_randao".to_uppercase()=> u32_hex(spec.domain_randao),
|
||||||
(
|
"domain_deposit".to_uppercase()=> u32_hex(spec.domain_deposit),
|
||||||
"domain_beacon_proposer",
|
"domain_voluntary_exit".to_uppercase() => u32_hex(spec.domain_voluntary_exit),
|
||||||
u32_hex(spec.domain_beacon_proposer),
|
"domain_selection_proof".to_uppercase() => u32_hex(spec.domain_selection_proof),
|
||||||
),
|
"domain_aggregate_and_proof".to_uppercase() => u32_hex(spec.domain_aggregate_and_proof),
|
||||||
(
|
"domain_application_mask".to_uppercase()=> u32_hex(spec.domain_application_mask),
|
||||||
"domain_beacon_attester",
|
"target_aggregators_per_committee".to_uppercase() =>
|
||||||
u32_hex(spec.domain_beacon_attester),
|
spec.target_aggregators_per_committee.to_string().into(),
|
||||||
),
|
"random_subnets_per_validator".to_uppercase() =>
|
||||||
("domain_randao", u32_hex(spec.domain_randao)),
|
spec.random_subnets_per_validator.to_string().into(),
|
||||||
("domain_deposit", u32_hex(spec.domain_deposit)),
|
"epochs_per_random_subnet_subscription".to_uppercase() =>
|
||||||
("domain_voluntary_exit", u32_hex(spec.domain_voluntary_exit)),
|
spec.epochs_per_random_subnet_subscription.to_string().into(),
|
||||||
(
|
"domain_contribution_and_proof".to_uppercase() =>
|
||||||
"domain_selection_proof",
|
u32_hex(spec.domain_contribution_and_proof),
|
||||||
u32_hex(spec.domain_selection_proof),
|
"domain_sync_committee".to_uppercase() => u32_hex(spec.domain_sync_committee),
|
||||||
),
|
"domain_sync_committee_selection_proof".to_uppercase() =>
|
||||||
(
|
u32_hex(spec.domain_sync_committee_selection_proof),
|
||||||
"domain_aggregate_and_proof",
|
"sync_committee_subnet_count".to_uppercase() =>
|
||||||
u32_hex(spec.domain_aggregate_and_proof),
|
altair::SYNC_COMMITTEE_SUBNET_COUNT.to_string().into(),
|
||||||
),
|
"target_aggregators_per_sync_subcommittee".to_uppercase() =>
|
||||||
(
|
altair::TARGET_AGGREGATORS_PER_SYNC_SUBCOMMITTEE.to_string().into(),
|
||||||
"domain_application_mask",
|
|
||||||
u32_hex(spec.domain_application_mask),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"target_aggregators_per_committee",
|
|
||||||
spec.target_aggregators_per_committee.to_string(),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"random_subnets_per_validator",
|
|
||||||
spec.random_subnets_per_validator.to_string(),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"epochs_per_random_subnet_subscription",
|
|
||||||
spec.epochs_per_random_subnet_subscription.to_string(),
|
|
||||||
),
|
|
||||||
];
|
|
||||||
for (key, value) in fields {
|
|
||||||
self.extra_fields.insert(key.to_uppercase(), value.into());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,15 +112,16 @@ mod test {
|
|||||||
.open(tmp_file.as_ref())
|
.open(tmp_file.as_ref())
|
||||||
.expect("error opening file");
|
.expect("error opening file");
|
||||||
let mainnet_spec = ChainSpec::mainnet();
|
let mainnet_spec = ChainSpec::mainnet();
|
||||||
let mut yamlconfig = ConfigAndPreset::from_chain_spec::<MainnetEthSpec>(&mainnet_spec);
|
let mut yamlconfig =
|
||||||
|
ConfigAndPreset::from_chain_spec::<MainnetEthSpec>(&mainnet_spec, None);
|
||||||
let (k1, v1) = ("SAMPLE_HARDFORK_KEY1", "123456789");
|
let (k1, v1) = ("SAMPLE_HARDFORK_KEY1", "123456789");
|
||||||
let (k2, v2) = ("SAMPLE_HARDFORK_KEY2", "987654321");
|
let (k2, v2) = ("SAMPLE_HARDFORK_KEY2", "987654321");
|
||||||
let (k3, v3) = ("SAMPLE_HARDFORK_KEY3", 32);
|
let (k3, v3) = ("SAMPLE_HARDFORK_KEY3", 32);
|
||||||
let (k4, v4) = ("SAMPLE_HARDFORK_KEY4", Value::Null);
|
let (k4, v4) = ("SAMPLE_HARDFORK_KEY4", Value::Null);
|
||||||
yamlconfig.extra_fields.insert(k1.into(), v1.into());
|
yamlconfig.extra_fields_mut().insert(k1.into(), v1.into());
|
||||||
yamlconfig.extra_fields.insert(k2.into(), v2.into());
|
yamlconfig.extra_fields_mut().insert(k2.into(), v2.into());
|
||||||
yamlconfig.extra_fields.insert(k3.into(), v3.into());
|
yamlconfig.extra_fields_mut().insert(k3.into(), v3.into());
|
||||||
yamlconfig.extra_fields.insert(k4.into(), v4);
|
yamlconfig.extra_fields_mut().insert(k4.into(), v4);
|
||||||
|
|
||||||
serde_yaml::to_writer(writer, &yamlconfig).expect("failed to write or serialize");
|
serde_yaml::to_writer(writer, &yamlconfig).expect("failed to write or serialize");
|
||||||
|
|
||||||
@ -125,8 +130,8 @@ mod test {
|
|||||||
.write(false)
|
.write(false)
|
||||||
.open(tmp_file.as_ref())
|
.open(tmp_file.as_ref())
|
||||||
.expect("error while opening the file");
|
.expect("error while opening the file");
|
||||||
let from: ConfigAndPreset =
|
let from: ConfigAndPresetBellatrix =
|
||||||
serde_yaml::from_reader(reader).expect("error while deserializing");
|
serde_yaml::from_reader(reader).expect("error while deserializing");
|
||||||
assert_eq!(from, yamlconfig);
|
assert_eq!(ConfigAndPreset::Bellatrix(from), yamlconfig);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -106,14 +106,14 @@ macro_rules! map_fork_name_with {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl FromStr for ForkName {
|
impl FromStr for ForkName {
|
||||||
type Err = ();
|
type Err = String;
|
||||||
|
|
||||||
fn from_str(fork_name: &str) -> Result<Self, ()> {
|
fn from_str(fork_name: &str) -> Result<Self, String> {
|
||||||
Ok(match fork_name.to_lowercase().as_ref() {
|
Ok(match fork_name.to_lowercase().as_ref() {
|
||||||
"phase0" | "base" => ForkName::Base,
|
"phase0" | "base" => ForkName::Base,
|
||||||
"altair" => ForkName::Altair,
|
"altair" => ForkName::Altair,
|
||||||
"bellatrix" | "merge" => ForkName::Merge,
|
"bellatrix" | "merge" => ForkName::Merge,
|
||||||
_ => return Err(()),
|
_ => return Err(format!("unknown fork name: {}", fork_name)),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -138,7 +138,7 @@ impl TryFrom<String> for ForkName {
|
|||||||
type Error = String;
|
type Error = String;
|
||||||
|
|
||||||
fn try_from(s: String) -> Result<Self, Self::Error> {
|
fn try_from(s: String) -> Result<Self, Self::Error> {
|
||||||
Self::from_str(&s).map_err(|()| format!("Invalid fork name: {}", s))
|
Self::from_str(&s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -178,8 +178,8 @@ mod test {
|
|||||||
assert_eq!(ForkName::from_str("AlTaIr"), Ok(ForkName::Altair));
|
assert_eq!(ForkName::from_str("AlTaIr"), Ok(ForkName::Altair));
|
||||||
assert_eq!(ForkName::from_str("altair"), Ok(ForkName::Altair));
|
assert_eq!(ForkName::from_str("altair"), Ok(ForkName::Altair));
|
||||||
|
|
||||||
assert_eq!(ForkName::from_str("NO_NAME"), Err(()));
|
assert!(ForkName::from_str("NO_NAME").is_err());
|
||||||
assert_eq!(ForkName::from_str("no_name"), Err(()));
|
assert!(ForkName::from_str("no_name").is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -110,7 +110,9 @@ pub use crate::beacon_committee::{BeaconCommittee, OwnedBeaconCommittee};
|
|||||||
pub use crate::beacon_state::{BeaconTreeHashCache, Error as BeaconStateError, *};
|
pub use crate::beacon_state::{BeaconTreeHashCache, Error as BeaconStateError, *};
|
||||||
pub use crate::chain_spec::{ChainSpec, Config, Domain};
|
pub use crate::chain_spec::{ChainSpec, Config, Domain};
|
||||||
pub use crate::checkpoint::Checkpoint;
|
pub use crate::checkpoint::Checkpoint;
|
||||||
pub use crate::config_and_preset::ConfigAndPreset;
|
pub use crate::config_and_preset::{
|
||||||
|
ConfigAndPreset, ConfigAndPresetAltair, ConfigAndPresetBellatrix,
|
||||||
|
};
|
||||||
pub use crate::contribution_and_proof::ContributionAndProof;
|
pub use crate::contribution_and_proof::ContributionAndProof;
|
||||||
pub use crate::deposit::{Deposit, DEPOSIT_TREE_DEPTH};
|
pub use crate::deposit::{Deposit, DEPOSIT_TREE_DEPTH};
|
||||||
pub use crate::deposit_data::DepositData;
|
pub use crate::deposit_data::DepositData;
|
||||||
|
@ -11,7 +11,7 @@ use std::process::Command;
|
|||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::string::ToString;
|
use std::string::ToString;
|
||||||
use tempfile::TempDir;
|
use tempfile::TempDir;
|
||||||
use types::{Address, Checkpoint, Epoch, ExecutionBlockHash, Hash256, MainnetEthSpec};
|
use types::{Address, Checkpoint, Epoch, ExecutionBlockHash, ForkName, Hash256, MainnetEthSpec};
|
||||||
use unused_port::{unused_tcp_port, unused_udp_port};
|
use unused_port::{unused_tcp_port, unused_udp_port};
|
||||||
|
|
||||||
const DEFAULT_ETH1_ENDPOINT: &str = "http://localhost:8545/";
|
const DEFAULT_ETH1_ENDPOINT: &str = "http://localhost:8545/";
|
||||||
@ -949,6 +949,21 @@ fn http_tls_flags() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn http_spec_fork_default() {
|
||||||
|
CommandLineTest::new()
|
||||||
|
.run_with_zero_port()
|
||||||
|
.with_config(|config| assert_eq!(config.http_api.spec_fork_name, None));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn http_spec_fork_override() {
|
||||||
|
CommandLineTest::new()
|
||||||
|
.flag("http-spec-fork", Some("altair"))
|
||||||
|
.run_with_zero_port()
|
||||||
|
.with_config(|config| assert_eq!(config.http_api.spec_fork_name, Some(ForkName::Altair)));
|
||||||
|
}
|
||||||
|
|
||||||
// Tests for Metrics flags.
|
// Tests for Metrics flags.
|
||||||
#[test]
|
#[test]
|
||||||
fn metrics_flag() {
|
fn metrics_flag() {
|
||||||
|
@ -7,7 +7,7 @@ use crate::http_metrics::metrics::{inc_counter_vec, ENDPOINT_ERRORS, ENDPOINT_RE
|
|||||||
use environment::RuntimeContext;
|
use environment::RuntimeContext;
|
||||||
use eth2::BeaconNodeHttpClient;
|
use eth2::BeaconNodeHttpClient;
|
||||||
use futures::future;
|
use futures::future;
|
||||||
use slog::{debug, error, info, warn, Logger};
|
use slog::{error, info, warn, Logger};
|
||||||
use slot_clock::SlotClock;
|
use slot_clock::SlotClock;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
@ -16,7 +16,7 @@ use std::marker::PhantomData;
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use tokio::{sync::RwLock, time::sleep};
|
use tokio::{sync::RwLock, time::sleep};
|
||||||
use types::{ChainSpec, EthSpec};
|
use types::{ChainSpec, Config, EthSpec};
|
||||||
|
|
||||||
/// The number of seconds *prior* to slot start that we will try and update the state of fallback
|
/// The number of seconds *prior* to slot start that we will try and update the state of fallback
|
||||||
/// nodes.
|
/// nodes.
|
||||||
@ -213,9 +213,9 @@ impl<E: EthSpec> CandidateBeaconNode<E> {
|
|||||||
|
|
||||||
/// Checks if the node has the correct specification.
|
/// Checks if the node has the correct specification.
|
||||||
async fn is_compatible(&self, spec: &ChainSpec, log: &Logger) -> Result<(), CandidateError> {
|
async fn is_compatible(&self, spec: &ChainSpec, log: &Logger) -> Result<(), CandidateError> {
|
||||||
let config_and_preset = self
|
let config = self
|
||||||
.beacon_node
|
.beacon_node
|
||||||
.get_config_spec()
|
.get_config_spec::<Config>()
|
||||||
.await
|
.await
|
||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
error!(
|
error!(
|
||||||
@ -228,8 +228,7 @@ impl<E: EthSpec> CandidateBeaconNode<E> {
|
|||||||
})?
|
})?
|
||||||
.data;
|
.data;
|
||||||
|
|
||||||
let beacon_node_spec =
|
let beacon_node_spec = ChainSpec::from_config::<E>(&config).ok_or_else(|| {
|
||||||
ChainSpec::from_config::<E>(&config_and_preset.config).ok_or_else(|| {
|
|
||||||
error!(
|
error!(
|
||||||
log,
|
log,
|
||||||
"The minimal/mainnet spec type of the beacon node does not match the validator \
|
"The minimal/mainnet spec type of the beacon node does not match the validator \
|
||||||
@ -239,15 +238,6 @@ impl<E: EthSpec> CandidateBeaconNode<E> {
|
|||||||
CandidateError::Incompatible
|
CandidateError::Incompatible
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
if !config_and_preset.extra_fields.is_empty() {
|
|
||||||
debug!(
|
|
||||||
log,
|
|
||||||
"Beacon spec includes unknown fields";
|
|
||||||
"endpoint" => %self.beacon_node,
|
|
||||||
"fields" => ?config_and_preset.extra_fields,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if beacon_node_spec.genesis_fork_version != spec.genesis_fork_version {
|
if beacon_node_spec.genesis_fork_version != spec.genesis_fork_version {
|
||||||
error!(
|
error!(
|
||||||
log,
|
log,
|
||||||
|
@ -217,8 +217,7 @@ pub fn serve<T: 'static + SlotClock + Clone, E: EthSpec>(
|
|||||||
.and(signer.clone())
|
.and(signer.clone())
|
||||||
.and_then(|spec: Arc<_>, signer| {
|
.and_then(|spec: Arc<_>, signer| {
|
||||||
blocking_signed_json_task(signer, move || {
|
blocking_signed_json_task(signer, move || {
|
||||||
let mut config = ConfigAndPreset::from_chain_spec::<E>(&spec);
|
let config = ConfigAndPreset::from_chain_spec::<E>(&spec, None);
|
||||||
config.make_backwards_compat(&spec);
|
|
||||||
Ok(api_types::GenericResponse::from(config))
|
Ok(api_types::GenericResponse::from(config))
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
@ -208,10 +208,13 @@ impl ApiTester {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn test_get_lighthouse_spec(self) -> Self {
|
pub async fn test_get_lighthouse_spec(self) -> Self {
|
||||||
let result = self.client.get_lighthouse_spec().await.unwrap().data;
|
let result = self
|
||||||
|
.client
|
||||||
let mut expected = ConfigAndPreset::from_chain_spec::<E>(&E::default_spec());
|
.get_lighthouse_spec::<ConfigAndPresetBellatrix>()
|
||||||
expected.make_backwards_compat(&E::default_spec());
|
.await
|
||||||
|
.map(|res| ConfigAndPreset::Bellatrix(res.data))
|
||||||
|
.unwrap();
|
||||||
|
let expected = ConfigAndPreset::from_chain_spec::<E>(&E::default_spec(), None);
|
||||||
|
|
||||||
assert_eq!(result, expected);
|
assert_eq!(result, expected);
|
||||||
|
|
||||||
@ -623,7 +626,9 @@ fn routes_with_invalid_auth() {
|
|||||||
.await
|
.await
|
||||||
.test_with_invalid_auth(|client| async move { client.get_lighthouse_health().await })
|
.test_with_invalid_auth(|client| async move { client.get_lighthouse_health().await })
|
||||||
.await
|
.await
|
||||||
.test_with_invalid_auth(|client| async move { client.get_lighthouse_spec().await })
|
.test_with_invalid_auth(|client| async move {
|
||||||
|
client.get_lighthouse_spec::<types::Config>().await
|
||||||
|
})
|
||||||
.await
|
.await
|
||||||
.test_with_invalid_auth(
|
.test_with_invalid_auth(
|
||||||
|client| async move { client.get_lighthouse_validators().await },
|
|client| async move { client.get_lighthouse_validators().await },
|
||||||
|
Loading…
Reference in New Issue
Block a user