Compare commits

...

8 Commits

Author SHA1 Message Date
Paul Hauner
9eb1945136 v1.2.2 (#2287)
## Issue Addressed

NA

## Proposed Changes

- Bump versions

## Additional Info

NA
2021-03-30 04:07:03 +00:00
Paul Hauner
3d239b85ac Allow for a clock disparity on the duties endpoints (#2283)
## Issue Addressed

Resolves #2280

## Proposed Changes

Allows for API consumers to call the proposer/attester duties endpoints [`MAXIMUM_GOSSIP_CLOCK_DISPARITY`](b34a79dc0b/beacon_node/beacon_chain/src/beacon_chain.rs (L99-L102)) earlier than the current epoch. For additional reasoning, see https://github.com/sigp/lighthouse/issues/2280#issuecomment-805358897.

## Additional Info

NA
2021-03-29 23:42:35 +00:00
Paul Hauner
03cefd0065 Expand observed attestations capacity (#2266)
## Issue Addressed

NA

## Proposed Changes

I noticed the following error on one of our nodes:

```
Mar 18 00:03:35 ip-xxxx lighthouse-bn[333503]: Mar 18 00:03:35.103 ERRO Unable to validate aggregate            error: ObservedAttestersError(EpochTooLow { epoch: Epoch(23961), lowest_permissible_epoch: Epoch(23962) }), peer_id: 16Uiu2HAm5GL5KzPLhvfg9MBBFSpBqTVGRFSiTg285oezzWcZzwEv
```

The slot during this log was 766,815 (the last slot of the epoch). I believe this is due to an off-by-one error in `observed_attesters` where we were failing to provide enough capacity to store observations from the previous, current and next epochs. See code comments for further reasoning.

Here's a link to the spec: https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/p2p-interface.md#beacon_aggregate_and_proof

## Additional Info

NA
2021-03-29 23:42:34 +00:00
stefa2k
39928d5c69 correcting name of flag (#2285)
## Issue Addressed

None, just a very small fix of documentation

## Proposed Changes

Fixing naming of paramter listed in documentation.

## Additional Info

No changes to code, just fixing documentation
2021-03-29 06:39:15 +00:00
Håvard Anda Estensen
d3d8c22edf Add to docs that macOS binaries are available (#2281)
## Proposed Changes

macOS binaries are available and should be listed in the Lighthouse Book
2021-03-26 04:53:58 +00:00
Michael Sproul
f9d60f5436 VC: accept unknown fields in chain spec (#2277)
## Issue Addressed

Closes #2274

## Proposed Changes

* Modify the `YamlConfig` to collect unknown fields into an `extra_fields` map, instead of failing hard.
* Log a debug message if there are extra fields returned to the VC from one of its BNs.

This restores Lighthouse's compatibility with Teku beacon nodes (and therefore Infura)
2021-03-26 04:53:57 +00:00
Paul Hauner
9a71a7e486 Fix default implementation on FixedVector (#2264)
## Issue Addressed

NA

## Proposed Changes

Whilst hacking on something I noticed that the default implementation of `FixedVector` can violate the length constraint!

E.g., `let v: FixedVector<u8; U4> = <_>::default()` would create a fixed vector with length 0, even though it promises to *always* have length 4! This causes SSZ deserialization to fail and probably other things too.

This isn't a security risk as it can't be triggered externally, however it's a foot gun for LH devs.

## Additional Info

NA
2021-03-22 00:54:09 +00:00
Paul Hauner
d18bba588b Update mailing list link (#2269)
## Issue Addressed

NA

## Proposed Changes

Updates the signup link to point to the new list.

## Additional Info

NA
2021-03-18 07:27:03 +00:00
35 changed files with 257 additions and 114 deletions

8
Cargo.lock generated
View File

@@ -628,7 +628,7 @@ dependencies = [
[[package]]
name = "beacon_node"
version = "1.2.1"
version = "1.2.2"
dependencies = [
"beacon_chain",
"clap",
@@ -841,7 +841,7 @@ dependencies = [
[[package]]
name = "boot_node"
version = "1.2.1"
version = "1.2.2"
dependencies = [
"beacon_node",
"clap",
@@ -3335,7 +3335,7 @@ dependencies = [
[[package]]
name = "lcli"
version = "1.2.1"
version = "1.2.2"
dependencies = [
"account_utils",
"bls",
@@ -3707,7 +3707,7 @@ dependencies = [
[[package]]
name = "lighthouse"
version = "1.2.1"
version = "1.2.2"
dependencies = [
"account_manager",
"account_utils",

View File

@@ -121,7 +121,11 @@ test-full: cargo-fmt test-release test-debug test-ef
# Lints the code for bad style and potentially unsafe arithmetic using Clippy.
# Clippy lints are opt-in per-crate for now. By default, everything is allowed except for performance and correctness lints.
lint:
cargo clippy --all --tests -- -D warnings
cargo clippy --all --tests -- \
-D warnings \
-A clippy::from-over-into \
-A clippy::upper-case-acronyms \
-A clippy::vec-init-then-push
# Runs the makefile in the `ef_tests` repo.
#

View File

@@ -69,8 +69,8 @@ The best place for discussion is the [Lighthouse Discord
server](https://discord.gg/cyAszAh). Alternatively, you may use the
[sigp/lighthouse gitter](https://gitter.im/sigp/lighthouse).
Sign up to the [Lighthouse Development Updates](https://mailchi.mp/3d9df0417779/lighthouse-dev-updates)
mailing list for email notifications about releases, network status and other important information.
Sign up to the [Lighthouse Development Updates](http://eepurl.com/dh9Lvb) mailing list for email
notifications about releases, network status and other important information.
Encrypt sensitive messages using our [PGP
key](https://keybase.io/sigp/pgp_keys.asc?fingerprint=15e66d941f697e28f49381f426416dc3f30674b0).

View File

@@ -10,7 +10,7 @@ use eth2_keystore::Keystore;
use eth2_network_config::Eth2NetworkConfig;
use safe_arith::SafeArith;
use slot_clock::{SlotClock, SystemTimeSlotClock};
use std::path::PathBuf;
use std::path::{Path, PathBuf};
use std::time::Duration;
use tokio::time::sleep;
use types::{ChainSpec, Epoch, EthSpec, Fork, VoluntaryExit};
@@ -91,7 +91,7 @@ pub fn cli_run<E: EthSpec>(matches: &ArgMatches, env: Environment<E>) -> Result<
/// Gets the keypair and validator_index for every validator and calls `publish_voluntary_exit` on it.
async fn publish_voluntary_exit<E: EthSpec>(
keystore_path: &PathBuf,
keystore_path: &Path,
password_file_path: Option<&PathBuf>,
client: &BeaconNodeHttpClient,
spec: &ChainSpec,
@@ -310,7 +310,7 @@ fn get_current_epoch<E: EthSpec>(genesis_time: u64, spec: &ChainSpec) -> Option<
/// If the `password_file_path` is Some, unlock keystore using password in given file
/// otherwise, prompts user for a password to unlock the keystore.
fn load_voting_keypair(
voting_keystore_path: &PathBuf,
voting_keystore_path: &Path,
password_file_path: Option<&PathBuf>,
stdin_inputs: bool,
) -> Result<Keypair, String> {

View File

@@ -1,6 +1,6 @@
[package]
name = "beacon_node"
version = "1.2.1"
version = "1.2.2"
authors = ["Paul Hauner <paul@paulhauner.com>", "Age Manning <Age@AgeManning.com"]
edition = "2018"

View File

@@ -252,11 +252,18 @@ impl<T: Item, E: EthSpec> AutoPruningContainer<T, E> {
/// The maximum number of epochs stored in `self`.
fn max_capacity(&self) -> u64 {
// The current epoch and the previous epoch. This is sufficient whilst
// GOSSIP_CLOCK_DISPARITY is 1/2 a slot or less:
// The next, current and previous epochs. We require the next epoch due to the
// `MAXIMUM_GOSSIP_CLOCK_DISPARITY`. We require the previous epoch since the
// specification delcares:
//
// https://github.com/ethereum/eth2.0-specs/pull/1706#issuecomment-610151808
2
// ```
// aggregate.data.slot + ATTESTATION_PROPAGATION_SLOT_RANGE
// >= current_slot >= aggregate.data.slot
// ```
//
// This means that during the current epoch we will always accept an attestation
// from at least one slot in the previous epoch.
3
}
/// Updates `self` with the current epoch, removing all attestations that become expired

View File

@@ -53,7 +53,7 @@ impl Inner {
pub fn from_bytes(bytes: &[u8], config: Config, spec: ChainSpec) -> Result<Self, String> {
let ssz_cache = SszEth1Cache::from_ssz_bytes(bytes)
.map_err(|e| format!("Ssz decoding error: {:?}", e))?;
Ok(ssz_cache.to_inner(config, spec)?)
ssz_cache.to_inner(config, spec)
}
/// Returns a reference to the specification.

View File

@@ -36,7 +36,7 @@ use ssz::Encode;
use std::collections::HashSet;
use std::fs::File;
use std::io::Write;
use std::path::PathBuf;
use std::path::{Path, PathBuf};
use std::{
collections::VecDeque,
marker::PhantomData,
@@ -1336,7 +1336,7 @@ impl<TSpec: EthSpec> std::convert::From<Response<TSpec>> for RPCCodedResponse<TS
}
/// Persist metadata to disk
pub fn save_metadata_to_disk<E: EthSpec>(dir: &PathBuf, metadata: MetaData<E>, log: &slog::Logger) {
pub fn save_metadata_to_disk<E: EthSpec>(dir: &Path, metadata: MetaData<E>, log: &slog::Logger) {
let _ = std::fs::create_dir_all(&dir);
match File::create(dir.join(METADATA_FILENAME))
.and_then(|mut f| f.write_all(&metadata.as_ssz_bytes()))

View File

@@ -474,7 +474,7 @@ fn strip_peer_id(addr: &mut Multiaddr) {
/// Load metadata from persisted file. Return default metadata if loading fails.
fn load_or_build_metadata<E: EthSpec>(
network_dir: &std::path::PathBuf,
network_dir: &std::path::Path,
log: &slog::Logger,
) -> MetaData<E> {
// Default metadata

View File

@@ -1,8 +1,11 @@
//! Contains the handler for the `GET validator/duties/attester/{epoch}` endpoint.
use crate::state_id::StateId;
use beacon_chain::{BeaconChain, BeaconChainError, BeaconChainTypes};
use beacon_chain::{
BeaconChain, BeaconChainError, BeaconChainTypes, MAXIMUM_GOSSIP_CLOCK_DISPARITY,
};
use eth2::types::{self as api_types};
use slot_clock::SlotClock;
use state_processing::state_advance::partial_state_advance;
use types::{
AttestationDuty, BeaconState, ChainSpec, CloneConfig, Epoch, EthSpec, Hash256, RelativeEpoch,
@@ -20,16 +23,32 @@ pub fn attester_duties<T: BeaconChainTypes>(
let current_epoch = chain
.epoch()
.map_err(warp_utils::reject::beacon_chain_error)?;
let next_epoch = current_epoch + 1;
if request_epoch > next_epoch {
// Determine what the current epoch would be if we fast-forward our system clock by
// `MAXIMUM_GOSSIP_CLOCK_DISPARITY`.
//
// Most of the time, `tolerant_current_epoch` will be equal to `current_epoch`. However, during
// the first `MAXIMUM_GOSSIP_CLOCK_DISPARITY` duration of the epoch `tolerant_current_epoch`
// will equal `current_epoch + 1`
let tolerant_current_epoch = chain
.slot_clock
.now_with_future_tolerance(MAXIMUM_GOSSIP_CLOCK_DISPARITY)
.ok_or_else(|| warp_utils::reject::custom_server_error("unable to read slot clock".into()))?
.epoch(T::EthSpec::slots_per_epoch());
if request_epoch == current_epoch
|| request_epoch == tolerant_current_epoch
|| request_epoch == current_epoch + 1
|| request_epoch == tolerant_current_epoch + 1
{
cached_attestation_duties(request_epoch, request_indices, chain)
} else if request_epoch > current_epoch + 1 {
Err(warp_utils::reject::custom_bad_request(format!(
"request epoch {} is more than one epoch past the current epoch {}",
request_epoch, current_epoch
)))
} else if request_epoch == current_epoch || request_epoch == next_epoch {
cached_attestation_duties(request_epoch, request_indices, chain)
} else {
// request_epoch < current_epoch
compute_historic_attester_duties(request_epoch, request_indices, chain)
}
}

View File

@@ -1,9 +1,12 @@
//! Contains the handler for the `GET validator/duties/proposer/{epoch}` endpoint.
use crate::state_id::StateId;
use beacon_chain::{BeaconChain, BeaconChainError, BeaconChainTypes};
use beacon_chain::{
BeaconChain, BeaconChainError, BeaconChainTypes, MAXIMUM_GOSSIP_CLOCK_DISPARITY,
};
use eth2::types::{self as api_types};
use slog::{debug, Logger};
use slot_clock::SlotClock;
use state_processing::state_advance::partial_state_advance;
use std::cmp::Ordering;
use types::{BeaconState, ChainSpec, CloneConfig, Epoch, EthSpec, Hash256, Slot};
@@ -21,35 +24,43 @@ pub fn proposer_duties<T: BeaconChainTypes>(
.epoch()
.map_err(warp_utils::reject::beacon_chain_error)?;
match request_epoch.cmp(&current_epoch) {
// request_epoch > current_epoch
//
// Determine what the current epoch would be if we fast-forward our system clock by
// `MAXIMUM_GOSSIP_CLOCK_DISPARITY`.
//
// Most of the time, `tolerant_current_epoch` will be equal to `current_epoch`. However, during
// the first `MAXIMUM_GOSSIP_CLOCK_DISPARITY` duration of the epoch `tolerant_current_epoch`
// will equal `current_epoch + 1`
let tolerant_current_epoch = chain
.slot_clock
.now_with_future_tolerance(MAXIMUM_GOSSIP_CLOCK_DISPARITY)
.ok_or_else(|| warp_utils::reject::custom_server_error("unable to read slot clock".into()))?
.epoch(T::EthSpec::slots_per_epoch());
if request_epoch == current_epoch || request_epoch == tolerant_current_epoch {
// If we could consider ourselves in the `request_epoch` when allowing for clock disparity
// tolerance then serve this request from the cache.
if let Some(duties) = try_proposer_duties_from_cache(request_epoch, chain)? {
Ok(duties)
} else {
debug!(
log,
"Proposer cache miss";
"request_epoch" => request_epoch,
);
compute_and_cache_proposer_duties(request_epoch, chain)
}
} else if request_epoch > current_epoch {
// Reject queries about the future as they're very expensive there's no look-ahead for
// proposer duties.
Ordering::Greater => Err(warp_utils::reject::custom_bad_request(format!(
Err(warp_utils::reject::custom_bad_request(format!(
"request epoch {} is ahead of the current epoch {}",
request_epoch, current_epoch
))),
// request_epoch == current_epoch
//
// Queries about the current epoch should attempt to find the value in the cache. If it
// can't be found, it should be computed and then stored in the cache for future gains.
Ordering::Equal => {
if let Some(duties) = try_proposer_duties_from_cache(request_epoch, chain)? {
Ok(duties)
} else {
debug!(
log,
"Proposer cache miss";
"request_epoch" => request_epoch,
);
compute_and_cache_proposer_duties(request_epoch, chain)
}
}
)))
} else {
// request_epoch < current_epoch
//
// Queries about the past are handled with a slow path.
Ordering::Less => compute_historic_proposer_duties(request_epoch, chain),
compute_historic_proposer_duties(request_epoch, chain)
}
}
@@ -58,10 +69,10 @@ pub fn proposer_duties<T: BeaconChainTypes>(
///
/// ## Notes
///
/// The `current_epoch` value should equal the current epoch on the slot clock, otherwise we risk
/// washing out the proposer cache at the expense of block processing.
/// The `current_epoch` value should equal the current epoch on the slot clock (with some
/// tolerance), otherwise we risk washing out the proposer cache at the expense of block processing.
fn try_proposer_duties_from_cache<T: BeaconChainTypes>(
current_epoch: Epoch,
request_epoch: Epoch,
chain: &BeaconChain<T>,
) -> Result<Option<ApiDuties>, warp::reject::Rejection> {
let head = chain
@@ -69,16 +80,16 @@ fn try_proposer_duties_from_cache<T: BeaconChainTypes>(
.map_err(warp_utils::reject::beacon_chain_error)?;
let head_epoch = head.slot.epoch(T::EthSpec::slots_per_epoch());
let dependent_root = match head_epoch.cmp(&current_epoch) {
// head_epoch == current_epoch
let dependent_root = match head_epoch.cmp(&request_epoch) {
// head_epoch == request_epoch
Ordering::Equal => head.proposer_shuffling_decision_root,
// head_epoch < current_epoch
// head_epoch < request_epoch
Ordering::Less => head.block_root,
// head_epoch > current_epoch
// head_epoch > request_epoch
Ordering::Greater => {
return Err(warp_utils::reject::custom_server_error(format!(
"head epoch {} is later than current epoch {}",
head_epoch, current_epoch
"head epoch {} is later than request epoch {}",
head_epoch, request_epoch
)))
}
};
@@ -86,10 +97,10 @@ fn try_proposer_duties_from_cache<T: BeaconChainTypes>(
chain
.beacon_proposer_cache
.lock()
.get_epoch::<T::EthSpec>(dependent_root, current_epoch)
.get_epoch::<T::EthSpec>(dependent_root, request_epoch)
.cloned()
.map(|indices| {
convert_to_api_response(chain, current_epoch, dependent_root, indices.to_vec())
convert_to_api_response(chain, request_epoch, dependent_root, indices.to_vec())
})
.transpose()
}

View File

@@ -2,7 +2,7 @@
use beacon_chain::{
test_utils::{AttestationStrategy, BeaconChainHarness, BlockStrategy, EphemeralHarnessType},
BeaconChain, StateSkipConfig,
BeaconChain, StateSkipConfig, MAXIMUM_GOSSIP_CLOCK_DISPARITY,
};
use discv5::enr::{CombinedKey, EnrBuilder};
use environment::null_logger;
@@ -18,6 +18,7 @@ use futures::stream::{Stream, StreamExt};
use futures::FutureExt;
use http_api::{Config, Context};
use network::NetworkMessage;
use slot_clock::SlotClock;
use state_processing::per_slot_processing;
use std::convert::TryInto;
use std::iter::Iterator;
@@ -1682,6 +1683,57 @@ impl ApiTester {
self
}
pub async fn test_get_validator_duties_early(self) -> Self {
let current_epoch = self.chain.epoch().unwrap();
let next_epoch = current_epoch + 1;
let current_epoch_start = self
.chain
.slot_clock
.start_of(current_epoch.start_slot(E::slots_per_epoch()))
.unwrap();
self.chain.slot_clock.set_current_time(
current_epoch_start - MAXIMUM_GOSSIP_CLOCK_DISPARITY - Duration::from_millis(1),
);
assert_eq!(
self.client
.get_validator_duties_proposer(current_epoch)
.await
.unwrap_err()
.status()
.map(Into::into),
Some(400),
"should not get proposer duties outside of tolerance"
);
assert_eq!(
self.client
.post_validator_duties_attester(next_epoch, &[0])
.await
.unwrap_err()
.status()
.map(Into::into),
Some(400),
"should not get attester duties outside of tolerance"
);
self.chain
.slot_clock
.set_current_time(current_epoch_start - MAXIMUM_GOSSIP_CLOCK_DISPARITY);
self.client
.get_validator_duties_proposer(current_epoch)
.await
.expect("should get proposer duties within tolerance");
self.client
.post_validator_duties_attester(next_epoch, &[0])
.await
.expect("should get attester duties within tolerance");
self
}
pub async fn test_block_production(self) -> Self {
let fork = self.chain.head_info().unwrap().fork;
let genesis_validators_root = self.chain.genesis_validators_root;
@@ -2356,6 +2408,11 @@ async fn node_get() {
.await;
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn get_validator_duties_early() {
ApiTester::new().test_get_validator_duties_early().await;
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn get_validator_duties_attester() {
ApiTester::new().test_get_validator_duties_attester().await;

View File

@@ -10,7 +10,7 @@ use std::cmp::max;
use std::fs;
use std::net::{IpAddr, Ipv4Addr, ToSocketAddrs};
use std::net::{TcpListener, UdpSocket};
use std::path::PathBuf;
use std::path::{Path, PathBuf};
use std::str::FromStr;
use types::{ChainSpec, Checkpoint, Epoch, EthSpec, Hash256, PublicKeyBytes, GRAFFITI_BYTES_LEN};
@@ -422,7 +422,7 @@ pub fn get_config<E: EthSpec>(
pub fn set_network_config(
config: &mut NetworkConfig,
cli_args: &ArgMatches,
data_dir: &PathBuf,
data_dir: &Path,
log: &Logger,
use_listening_port_as_enr_port_by_default: bool,
) -> Result<(), String> {

View File

@@ -660,7 +660,7 @@ impl<E: EthSpec, Hot: ItemStore<E>, Cold: ItemStore<E>> HotColdDB<E, Hot, Cold>
partial_state.load_historical_roots(&self.cold_db, &self.spec)?;
partial_state.load_randao_mixes(&self.cold_db, &self.spec)?;
Ok(partial_state.try_into()?)
partial_state.try_into()
}
/// Load a restore point state by its `restore_point_index`.

View File

@@ -4,14 +4,15 @@ Each Lighthouse release contains several downloadable binaries in the "Assets"
section of the release. You can find the [releases
on Github](https://github.com/sigp/lighthouse/releases).
> Note: binaries are not yet provided for MacOS or Windows native.
> Note: binaries are not yet provided for Windows native.
## Platforms
Binaries are supplied for two platforms:
Binaries are supplied for three platforms:
- `x86_64-unknown-linux-gnu`: AMD/Intel 64-bit processors (most desktops, laptops, servers)
- `aarch64-unknown-linux-gnu`: 64-bit ARM processors (Raspberry Pi 4)
- `x86_64-apple-darwin`: macOS with Intel chips
Additionally there is also a `-portable` suffix which indicates if the `portable` feature is used:

View File

@@ -25,7 +25,7 @@ In order to initiate an exit, users can use the `lighthouse account validator ex
- The `--keystore` flag is used to specify the path to the EIP-2335 voting keystore for the validator.
- The `--beacon-nodes` flag is used to specify a beacon chain HTTP endpoint that confirms to the [Eth2.0 Standard API](https://ethereum.github.io/eth2.0-APIs/) specifications. That beacon node will be used to validate and propagate the voluntary exit. The default value for this flag is `http://localhost:5052`.
- The `--beacon-node` flag is used to specify a beacon chain HTTP endpoint that confirms to the [Eth2.0 Standard API](https://ethereum.github.io/eth2.0-APIs/) specifications. That beacon node will be used to validate and propagate the voluntary exit. The default value for this flag is `http://localhost:5052`.
- The `--network` flag is used to specify a particular Eth2 network (default is `mainnet`).

View File

@@ -1,6 +1,6 @@
[package]
name = "boot_node"
version = "1.2.1"
version = "1.2.2"
authors = ["Sigma Prime <contact@sigmaprime.io>"]
edition = "2018"

View File

@@ -35,7 +35,7 @@ fn testnet_url() -> String {
fn main() {
match get_all_contracts() {
Ok(()) => (),
Err(e) => panic!(e),
Err(e) => panic!("{}", e),
}
}

View File

@@ -68,7 +68,7 @@ pub fn decode_eth1_tx_data(
)
.map_err(DecodeError::SszDecodeError)?
};
};
}
let root = decode_token!(Hash256, to_fixed_bytes);

View File

@@ -16,7 +16,7 @@ pub const VERSION: &str = git_version!(
// NOTE: using --match instead of --exclude for compatibility with old Git
"--match=thiswillnevermatchlol"
],
prefix = "Lighthouse/v1.2.1-",
prefix = "Lighthouse/v1.2.2-",
fallback = "unknown"
);
@@ -38,6 +38,10 @@ mod test {
fn version_formatting() {
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);
assert!(
re.is_match(VERSION),
"version doesn't match regex: {}",
VERSION
);
}
}

View File

@@ -149,7 +149,7 @@ mod post {
let r = run_testcase(u).unwrap_err();
for msg in msgs.iter() {
assert!(r.contains(msg), format!("{:?} should contain {:?}", r, msg));
assert!(r.contains(msg), "{:?} should contain {:?}", r, msg);
}
};

View File

@@ -89,7 +89,7 @@ impl ValidatorDir {
}
/// Returns the `dir` provided to `Self::open`.
pub fn dir(&self) -> &PathBuf {
pub fn dir(&self) -> &Path {
&self.dir
}
@@ -204,7 +204,7 @@ impl ValidatorDir {
/// Attempts to load and decrypt a Keypair given path to the keystore.
pub fn unlock_keypair<P: AsRef<Path>>(
keystore_path: &PathBuf,
keystore_path: &Path,
password_dir: P,
) -> Result<Keypair, Error> {
let keystore = Keystore::from_json_reader(
@@ -229,8 +229,8 @@ pub fn unlock_keypair<P: AsRef<Path>>(
/// Attempts to load and decrypt a Keypair given path to the keystore and the password file.
pub fn unlock_keypair_from_password_path(
keystore_path: &PathBuf,
password_path: &PathBuf,
keystore_path: &Path,
password_path: &Path,
) -> Result<Keypair, Error> {
let keystore = Keystore::from_json_reader(
&mut OpenOptions::new()
@@ -242,7 +242,7 @@ pub fn unlock_keypair_from_password_path(
.map_err(Error::UnableToReadKeystore)?;
let password: PlainText = read(password_path)
.map_err(|_| Error::UnableToReadPassword(password_path.clone()))?
.map_err(|_| Error::UnableToReadPassword(password_path.into()))?
.into();
keystore
.decrypt_keypair(password.as_bytes())

View File

@@ -182,7 +182,7 @@ fn concurrency() {
let harness = Harness::new();
let val_dir = harness.create_and_test(&BuildConfig::default());
let path = val_dir.dir().clone();
let path = val_dir.dir().to_owned();
// Should not re-open whilst opened after build.
ValidatorDir::open(&path).unwrap_err();

View File

@@ -55,8 +55,8 @@ impl<'de> Visitor<'de> for HexVisitor {
where
E: de::Error,
{
Ok(hex::decode(value.trim_start_matches("0x"))
.map_err(|e| de::Error::custom(format!("invalid hex ({:?})", e)))?)
hex::decode(value.trim_start_matches("0x"))
.map_err(|e| de::Error::custom(format!("invalid hex ({:?})", e)))
}
}

View File

@@ -353,7 +353,7 @@ macro_rules! impl_decodable_for_u8_array {
Err(DecodeError::InvalidByteLength { len, expected })
} else {
let mut array: [u8; $len] = [0; $len];
array.copy_from_slice(&bytes[..]);
array.copy_from_slice(bytes);
Ok(array)
}

View File

@@ -108,16 +108,16 @@ impl<T: Default, N: Unsigned> From<Vec<T>> for FixedVector<T, N> {
}
}
impl<T, N: Unsigned> Into<Vec<T>> for FixedVector<T, N> {
fn into(self) -> Vec<T> {
self.vec
impl<T, N: Unsigned> From<FixedVector<T, N>> for Vec<T> {
fn from(vector: FixedVector<T, N>) -> Vec<T> {
vector.vec
}
}
impl<T, N: Unsigned> Default for FixedVector<T, N> {
impl<T: Default, N: Unsigned> Default for FixedVector<T, N> {
fn default() -> Self {
Self {
vec: Vec::default(),
vec: (0..N::to_usize()).map(|_| T::default()).collect(),
_phantom: PhantomData,
}
}

View File

@@ -120,9 +120,9 @@ impl<T, N: Unsigned> From<Vec<T>> for VariableList<T, N> {
}
}
impl<T, N: Unsigned> Into<Vec<T>> for VariableList<T, N> {
fn into(self) -> Vec<T> {
self.vec
impl<T, N: Unsigned> From<VariableList<T, N>> for Vec<T> {
fn from(list: VariableList<T, N>) -> Vec<T> {
list.vec
}
}

View File

@@ -1,6 +1,7 @@
use crate::*;
use int_to_bytes::int_to_bytes4;
use serde_derive::{Deserialize, Serialize};
use std::collections::HashMap;
use std::fs::File;
use std::path::Path;
use tree_hash::TreeHash;
@@ -449,10 +450,8 @@ mod tests {
}
/// YAML config file as defined by the spec.
///
/// Spec v0.12.3
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
#[serde(rename_all = "UPPERCASE", deny_unknown_fields)]
#[serde(rename_all = "UPPERCASE")]
pub struct YamlConfig {
pub config_name: String,
// ChainSpec
@@ -576,6 +575,10 @@ pub struct YamlConfig {
#[serde(with = "serde_utils::quoted_u64")]
deposit_network_id: u64,
deposit_contract_address: Address,
// Extra fields (could be from a future hard-fork that we don't yet know).
#[serde(flatten)]
pub extra_fields: HashMap<String, String>,
}
impl Default for YamlConfig {
@@ -671,6 +674,8 @@ impl YamlConfig {
deposit_chain_id: spec.deposit_chain_id,
deposit_network_id: spec.deposit_network_id,
deposit_contract_address: spec.deposit_contract_address,
extra_fields: HashMap::new(),
}
}
@@ -849,6 +854,31 @@ mod yaml_tests {
assert_eq!(from, yamlconfig);
}
#[test]
fn extra_fields_round_trip() {
let tmp_file = NamedTempFile::new().expect("failed to create temp file");
let writer = OpenOptions::new()
.read(false)
.write(true)
.open(tmp_file.as_ref())
.expect("error opening file");
let mainnet_spec = ChainSpec::mainnet();
let mut yamlconfig = YamlConfig::from_spec::<MainnetEthSpec>(&mainnet_spec);
let (k1, v1) = ("SAMPLE_HARDFORK_KEY1", "123456789");
let (k2, v2) = ("SAMPLE_HARDFORK_KEY2", "987654321");
yamlconfig.extra_fields.insert(k1.into(), v1.into());
yamlconfig.extra_fields.insert(k2.into(), v2.into());
serde_yaml::to_writer(writer, &yamlconfig).expect("failed to write or serialize");
let reader = OpenOptions::new()
.read(true)
.write(false)
.open(tmp_file.as_ref())
.expect("error while opening the file");
let from: YamlConfig = serde_yaml::from_reader(reader).expect("error while deserializing");
assert_eq!(from, yamlconfig);
}
#[test]
fn apply_to_spec() {
let mut spec = ChainSpec::minimal();

View File

@@ -19,35 +19,35 @@ where
aggregate: Cow<'a, GenericAggregateSignature<Pub, AggPub, Sig, AggSig>>,
}
impl<'a, Pub, AggPub, Sig, AggSig> Into<WrappedSignature<'a, Pub, AggPub, Sig, AggSig>>
for &'a GenericSignature<Pub, Sig>
impl<'a, Pub, AggPub, Sig, AggSig> From<&'a GenericSignature<Pub, Sig>>
for WrappedSignature<'a, Pub, AggPub, Sig, AggSig>
where
Pub: TPublicKey + Clone,
AggPub: Clone,
Sig: TSignature<Pub> + Clone,
AggSig: TAggregateSignature<Pub, AggPub, Sig> + Clone,
{
fn into(self) -> WrappedSignature<'a, Pub, AggPub, Sig, AggSig> {
fn from(sig: &'a GenericSignature<Pub, Sig>) -> Self {
let mut aggregate: GenericAggregateSignature<Pub, AggPub, Sig, AggSig> =
GenericAggregateSignature::infinity();
aggregate.add_assign(self);
aggregate.add_assign(sig);
WrappedSignature {
aggregate: Cow::Owned(aggregate),
}
}
}
impl<'a, Pub, AggPub, Sig, AggSig> Into<WrappedSignature<'a, Pub, AggPub, Sig, AggSig>>
for &'a GenericAggregateSignature<Pub, AggPub, Sig, AggSig>
impl<'a, Pub, AggPub, Sig, AggSig> From<&'a GenericAggregateSignature<Pub, AggPub, Sig, AggSig>>
for WrappedSignature<'a, Pub, AggPub, Sig, AggSig>
where
Pub: TPublicKey + Clone,
AggPub: Clone,
Sig: Clone,
AggSig: Clone,
{
fn into(self) -> WrappedSignature<'a, Pub, AggPub, Sig, AggSig> {
fn from(aggregate: &'a GenericAggregateSignature<Pub, AggPub, Sig, AggSig>) -> Self {
WrappedSignature {
aggregate: Cow::Borrowed(self),
aggregate: Cow::Borrowed(aggregate),
}
}
}

View File

@@ -1,7 +1,7 @@
[package]
name = "lcli"
description = "Lighthouse CLI (modeled after zcli)"
version = "1.2.1"
version = "1.2.2"
authors = ["Paul Hauner <paul@paulhauner.com>"]
edition = "2018"

View File

@@ -1,6 +1,6 @@
[package]
name = "lighthouse"
version = "1.2.1"
version = "1.2.2"
authors = ["Sigma Prime <contact@sigmaprime.io>"]
edition = "2018"

View File

@@ -1,6 +1,7 @@
#![cfg(feature = "ef_tests")]
use ef_tests::*;
use std::collections::HashMap;
use std::path::PathBuf;
use types::*;
@@ -17,6 +18,11 @@ fn config_test<E: EthSpec + TypeName>() {
let yaml_from_spec = YamlConfig::from_spec::<E>(&spec);
assert_eq!(yaml_config.apply_to_chain_spec::<E>(&spec), Some(spec));
assert_eq!(yaml_from_spec, yaml_config);
assert_eq!(
yaml_config.extra_fields,
HashMap::new(),
"not all config fields read"
);
}
#[test]

View File

@@ -7,7 +7,7 @@ use state_processing::test_utils::BlockProcessingBuilder;
use std::env;
use std::fs::{self, File};
use std::io::Write;
use std::path::PathBuf;
use std::path::{Path, PathBuf};
use std::process::exit;
use types::MainnetEthSpec;
use types::{BeaconState, ChainSpec, EthSpec, SignedBeaconBlock};
@@ -91,12 +91,12 @@ fn write_vectors_to_file(title: &str, vectors: &[TestVector]) -> Result<(), Stri
}
/// Write some SSZ object to file.
fn write_to_ssz_file<T: Encode>(path: &PathBuf, item: &T) -> Result<(), String> {
fn write_to_ssz_file<T: Encode>(path: &Path, item: &T) -> Result<(), String> {
write_to_file(path, &item.as_ssz_bytes())
}
/// Write some bytes to file.
fn write_to_file(path: &PathBuf, item: &[u8]) -> Result<(), String> {
fn write_to_file(path: &Path, item: &[u8]) -> Result<(), String> {
File::create(path)
.map_err(|e| format!("Unable to create {:?}: {:?}", path, e))
.and_then(|mut file| {

View File

@@ -7,7 +7,7 @@ use crate::http_metrics::metrics::{inc_counter_vec, ENDPOINT_ERRORS, ENDPOINT_RE
use environment::RuntimeContext;
use eth2::BeaconNodeHttpClient;
use futures::future;
use slog::{error, info, warn, Logger};
use slog::{debug, error, info, warn, Logger};
use slot_clock::SlotClock;
use std::fmt;
use std::fmt::Debug;
@@ -236,6 +236,14 @@ impl<E: EthSpec> CandidateBeaconNode<E> {
CandidateError::Incompatible
})?;
if !yaml_config.extra_fields.is_empty() {
debug!(
log,
"Beacon spec includes unknown fields";
"fields" => ?yaml_config.extra_fields
);
}
if *spec == beacon_node_spec {
Ok(())
} else {

View File

@@ -19,7 +19,7 @@ use slog::{debug, error, info, warn, Logger};
use std::collections::{HashMap, HashSet};
use std::fs::File;
use std::io;
use std::path::PathBuf;
use std::path::{Path, PathBuf};
use types::{Graffiti, Keypair, PublicKey, PublicKeyBytes};
use crate::key_cache;
@@ -101,20 +101,16 @@ impl InitializedValidator {
}
}
fn open_keystore(path: &PathBuf) -> Result<Keystore, Error> {
fn open_keystore(path: &Path) -> Result<Keystore, Error> {
let keystore_file = File::open(path).map_err(Error::UnableToOpenVotingKeystore)?;
Keystore::from_json_reader(keystore_file).map_err(Error::UnableToParseVotingKeystore)
}
fn get_lockfile_path(file_path: &PathBuf) -> Option<PathBuf> {
fn get_lockfile_path(file_path: &Path) -> Option<PathBuf> {
file_path
.file_name()
.and_then(|os_str| os_str.to_str())
.map(|filename| {
file_path
.clone()
.with_file_name(format!("{}.lock", filename))
})
.map(|filename| file_path.with_file_name(format!("{}.lock", filename)))
}
impl InitializedValidator {
@@ -238,7 +234,7 @@ impl InitializedValidator {
/// Try to unlock `keystore` at `keystore_path` by prompting the user via `stdin`.
fn unlock_keystore_via_stdin_password(
keystore: &Keystore,
keystore_path: &PathBuf,
keystore_path: &Path,
) -> Result<(ZeroizeString, Keypair), Error> {
eprintln!();
eprintln!(